diff mbox series

[1/3] net/sched: netem: use extack

Message ID 20240201034653.450138-2-stephen@networkplumber.org (mailing list archive)
State Changes Requested
Delegated to: Netdev Maintainers
Headers show
Series net/sched: netem cleanups | expand

Checks

Context Check Description
netdev/series_format warning Target tree name not specified in the subject
netdev/tree_selection success Guessed tree name to be net-next
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 1048 this patch: 1048
netdev/build_tools success No tools touched, skip
netdev/cc_maintainers success CCed 0 of 0 maintainers
netdev/build_clang success Errors and warnings before: 1065 this patch: 1065
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 1065 this patch: 1065
netdev/checkpatch warning WARNING: line length of 82 exceeds 80 columns WARNING: line length of 84 exceeds 80 columns WARNING: line length of 86 exceeds 80 columns WARNING: line length of 90 exceeds 80 columns
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0
netdev/contest success net-next-2024-02-01--15-00 (tests: 713)

Commit Message

Stephen Hemminger Feb. 1, 2024, 3:45 a.m. UTC
The error handling in netem predates introduction of extack,
and was mostly using pr_info(). Use extack to put errors in
result rather than console log.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 net/sched/sch_netem.c | 39 +++++++++++++++++++++------------------
 1 file changed, 21 insertions(+), 18 deletions(-)

Comments

Jiri Pirko Feb. 1, 2024, 9:30 a.m. UTC | #1
Thu, Feb 01, 2024 at 04:45:58AM CET, stephen@networkplumber.org wrote:
>The error handling in netem predates introduction of extack,
>and was mostly using pr_info(). Use extack to put errors in
>result rather than console log.
>

[...]

>@@ -1068,18 +1073,16 @@ static int netem_init(struct Qdisc *sch, struct nlattr *opt,
> 		      struct netlink_ext_ack *extack)
> {
> 	struct netem_sched_data *q = qdisc_priv(sch);
>-	int ret;
> 
> 	qdisc_watchdog_init(&q->watchdog, sch);
> 
>-	if (!opt)
>+	if (!opt) {
>+		NL_SET_ERR_MSG_MOD(extack, "Netem missing required parameters");

Drop "Netem " here.

Otherwise, this looks fine.

> 		return -EINVAL;
>+	}
> 
> 	q->loss_model = CLG_RANDOM;
>-	ret = netem_change(sch, opt, extack);
>-	if (ret)
>-		pr_info("netem: change failed\n");
>-	return ret;
>+	return netem_change(sch, opt, extack);
> }
> 
> static void netem_destroy(struct Qdisc *sch)
>-- 
>2.43.0
>
>
Jakub Kicinski Feb. 1, 2024, 5 p.m. UTC | #2
On Thu, 1 Feb 2024 10:30:27 +0100 Jiri Pirko wrote:
> Thu, Feb 01, 2024 at 04:45:58AM CET, stephen@networkplumber.org wrote:
> >-	if (!opt)
> >+	if (!opt) {
> >+		NL_SET_ERR_MSG_MOD(extack, "Netem missing required parameters");  
> 
> Drop "Netem " here.
> 
> Otherwise, this looks fine.

Looks like most sch's require opt. Would it be a bad idea to pull 
the check out to the caller? Minor simplification, plus the caller
has the outer message so they can use NL_SET_ERR_ATTR_MISS() and
friends.


$ git grep -A1 'if (!opt)' -- net/sched/
net/sched/cls_fw.c:     if (!opt)
net/sched/cls_fw.c-             return handle ? -EINVAL : 0; /* Succeed if it is old method. */
--
net/sched/cls_u32.c:    if (!opt) {
net/sched/cls_u32.c-            if (handle) {
--
net/sched/sch_cbs.c:    if (!opt) {
net/sched/sch_cbs.c-            NL_SET_ERR_MSG(extack, "Missing CBS qdisc options  which are mandatory");
--
net/sched/sch_drr.c:    if (!opt) {
net/sched/sch_drr.c-            NL_SET_ERR_MSG(extack, "DRR options are required for this operation");
--
net/sched/sch_etf.c:    if (!opt) {
net/sched/sch_etf.c-            NL_SET_ERR_MSG(extack,
--
net/sched/sch_ets.c:    if (!opt) {
net/sched/sch_ets.c-            NL_SET_ERR_MSG(extack, "ETS options are required for this operation");
--
net/sched/sch_ets.c:    if (!opt)
net/sched/sch_ets.c-            return -EINVAL;
--
net/sched/sch_gred.c:   if (!opt)
net/sched/sch_gred.c-           return -EINVAL;
--
net/sched/sch_htb.c:    if (!opt)
net/sched/sch_htb.c-            return -EINVAL;
--
net/sched/sch_htb.c:    if (!opt)
net/sched/sch_htb.c-            goto failure;
--
net/sched/sch_multiq.c: if (!opt)
net/sched/sch_multiq.c-         return -EINVAL;
--
net/sched/sch_netem.c:  if (!opt)
net/sched/sch_netem.c-          return -EINVAL;
--
net/sched/sch_prio.c:   if (!opt)
net/sched/sch_prio.c-           return -EINVAL;
--
net/sched/sch_red.c:    if (!opt)
net/sched/sch_red.c-            return -EINVAL;
--
net/sched/sch_skbprio.c:        if (!opt)
net/sched/sch_skbprio.c-                return 0;
--
net/sched/sch_taprio.c: if (!opt)
net/sched/sch_taprio.c-         return -EINVAL;
--
net/sched/sch_tbf.c:    if (!opt)
net/sched/sch_tbf.c-            return -EINVAL;
Donald Hunter Feb. 2, 2024, 11:53 a.m. UTC | #3
Jakub Kicinski <kuba@kernel.org> writes:

> On Thu, 1 Feb 2024 10:30:27 +0100 Jiri Pirko wrote:
>> Thu, Feb 01, 2024 at 04:45:58AM CET, stephen@networkplumber.org wrote:
>> >-	if (!opt)
>> >+	if (!opt) {
>> >+		NL_SET_ERR_MSG_MOD(extack, "Netem missing required parameters");  
>> 
>> Drop "Netem " here.
>> 
>> Otherwise, this looks fine.
>
> Looks like most sch's require opt. Would it be a bad idea to pull 
> the check out to the caller? Minor simplification, plus the caller
> has the outer message so they can use NL_SET_ERR_ATTR_MISS() and
> friends.

There's also these which maybe complicates things:

$ git grep -A1 'if (opt == NULL)' -- net/sched/
net/sched/cls_flow.c:   if (opt == NULL)
net/sched/cls_flow.c-           return -EINVAL;
--
net/sched/sch_choke.c:  if (opt == NULL)
net/sched/sch_choke.c-          return -EINVAL;
--
net/sched/sch_fifo.c:   if (opt == NULL) {
net/sched/sch_fifo.c-           u32 limit = qdisc_dev(sch)->tx_queue_len;
--
net/sched/sch_hfsc.c:   if (opt == NULL)
net/sched/sch_hfsc.c-           return -EINVAL;
--
net/sched/sch_plug.c:   if (opt == NULL) {
net/sched/sch_plug.c-           q->limit = qdisc_dev(sch)->tx_queue_len

I'm in favour of qdisc specific extack messages.

> $ git grep -A1 'if (!opt)' -- net/sched/
> net/sched/cls_fw.c:     if (!opt)
> net/sched/cls_fw.c-             return handle ? -EINVAL : 0; /* Succeed if it is old method. */
> --
> net/sched/cls_u32.c:    if (!opt) {
> net/sched/cls_u32.c-            if (handle) {
> --
> net/sched/sch_cbs.c:    if (!opt) {
> net/sched/sch_cbs.c-            NL_SET_ERR_MSG(extack, "Missing CBS qdisc options  which are mandatory");
> --
> net/sched/sch_drr.c:    if (!opt) {
> net/sched/sch_drr.c-            NL_SET_ERR_MSG(extack, "DRR options are required for this operation");
> --
> net/sched/sch_etf.c:    if (!opt) {
> net/sched/sch_etf.c-            NL_SET_ERR_MSG(extack,
> --
> net/sched/sch_ets.c:    if (!opt) {
> net/sched/sch_ets.c-            NL_SET_ERR_MSG(extack, "ETS options are required for this operation");
> --
> net/sched/sch_ets.c:    if (!opt)
> net/sched/sch_ets.c-            return -EINVAL;
> --
> net/sched/sch_gred.c:   if (!opt)
> net/sched/sch_gred.c-           return -EINVAL;
> --
> net/sched/sch_htb.c:    if (!opt)
> net/sched/sch_htb.c-            return -EINVAL;
> --
> net/sched/sch_htb.c:    if (!opt)
> net/sched/sch_htb.c-            goto failure;
> --
> net/sched/sch_multiq.c: if (!opt)
> net/sched/sch_multiq.c-         return -EINVAL;
> --
> net/sched/sch_netem.c:  if (!opt)
> net/sched/sch_netem.c-          return -EINVAL;
> --
> net/sched/sch_prio.c:   if (!opt)
> net/sched/sch_prio.c-           return -EINVAL;
> --
> net/sched/sch_red.c:    if (!opt)
> net/sched/sch_red.c-            return -EINVAL;
> --
> net/sched/sch_skbprio.c:        if (!opt)
> net/sched/sch_skbprio.c-                return 0;
> --
> net/sched/sch_taprio.c: if (!opt)
> net/sched/sch_taprio.c-         return -EINVAL;
> --
> net/sched/sch_tbf.c:    if (!opt)
> net/sched/sch_tbf.c-            return -EINVAL;
Jakub Kicinski Feb. 2, 2024, 4:23 p.m. UTC | #4
On Fri, 02 Feb 2024 11:53:04 +0000 Donald Hunter wrote:
> > Looks like most sch's require opt. Would it be a bad idea to pull 
> > the check out to the caller? Minor simplification, plus the caller
> > has the outer message so they can use NL_SET_ERR_ATTR_MISS() and
> > friends.  
> 
> There's also these which maybe complicates things:
> 
> $ git grep -A1 'if (opt == NULL)' -- net/sched/
> net/sched/cls_flow.c:   if (opt == NULL)
> net/sched/cls_flow.c-           return -EINVAL;
> --
> net/sched/sch_choke.c:  if (opt == NULL)
> net/sched/sch_choke.c-          return -EINVAL;
> --
> net/sched/sch_fifo.c:   if (opt == NULL) {
> net/sched/sch_fifo.c-           u32 limit = qdisc_dev(sch)->tx_queue_len;
> --
> net/sched/sch_hfsc.c:   if (opt == NULL)
> net/sched/sch_hfsc.c-           return -EINVAL;
> --
> net/sched/sch_plug.c:   if (opt == NULL) {
> net/sched/sch_plug.c-           q->limit = qdisc_dev(sch)->tx_queue_len

That's fine, I was thinking opt-in. Add a bit to ops that says
"init_requires_opts" or whatnot. 

> I'm in favour of qdisc specific extack messages.

Most of them just say "$name requires options" in a more or less concise
and more or less well spelled form :( Even if we don't want to depend
purely on ATTR_MISS - extack messages support printf now, and we have
the qdisc name in the ops (ops->id), so we can printf the same string 
in the core.

Just an idea, if you all prefer to keep things as they are, that's fine.
But we've been sprinkling the damn string messages throughout TC for
years now, and still they keep coming and still if you step one foot
away from the most actively developed actions and classifiers, you're
back in the 90s :(
Donald Hunter Feb. 2, 2024, 5:03 p.m. UTC | #5
On Fri, 2 Feb 2024 at 16:24, Jakub Kicinski <kuba@kernel.org> wrote:
>
> That's fine, I was thinking opt-in. Add a bit to ops that says
> "init_requires_opts" or whatnot.
>
> > I'm in favour of qdisc specific extack messages.
>
> Most of them just say "$name requires options" in a more or less concise
> and more or less well spelled form :( Even if we don't want to depend
> purely on ATTR_MISS - extack messages support printf now, and we have
> the qdisc name in the ops (ops->id), so we can printf the same string
> in the core.

Fair point, it's not easy to steer people to the right options attrs.

> Just an idea, if you all prefer to keep things as they are, that's fine.
> But we've been sprinkling the damn string messages throughout TC for
> years now, and still they keep coming and still if you step one foot
> away from the most actively developed actions and classifiers, you're
> back in the 90s :(

So true. FWIW I was thinking of putting some effort into smoothing off
some of the sharp edges in all of the qdiscs, along the lines of this:

diff --git a/net/sched/sch_choke.c b/net/sched/sch_choke.c
index ae1da08e268f..8c16fcbaad71 100644
--- a/net/sched/sch_choke.c
+++ b/net/sched/sch_choke.c
@@ -352,19 +352,28 @@ static int choke_change(struct Qdisc *sch,
struct nlattr *opt,
        if (err < 0)
                return err;

-       if (tb[TCA_CHOKE_PARMS] == NULL ||
-           tb[TCA_CHOKE_STAB] == NULL)
+       if (tb[TCA_CHOKE_PARMS] == NULL) {
+               NL_SET_ERR_MSG(extack,
+                              "Missing TCA_CHOKE_PARMS of type
'struct tc_red_qopt'");
                return -EINVAL;
+       }
+       if (tb[TCA_CHOKE_STAB] == NULL) {
+               NL_SET_ERR_MSG(extack, "Missing TCA_CHOKE_STAB");
+               return -EINVAL;
+       }

        max_P = tb[TCA_CHOKE_MAX_P] ? nla_get_u32(tb[TCA_CHOKE_MAX_P]) : 0;

        ctl = nla_data(tb[TCA_CHOKE_PARMS]);
        stab = nla_data(tb[TCA_CHOKE_STAB]);
-       if (!red_check_params(ctl->qth_min, ctl->qth_max, ctl->Wlog,
ctl->Scell_log, stab))
+       if (!red_check_params(ctl->qth_min, ctl->qth_max, ctl->Wlog,
ctl->Scell_log, stab)) {
+               NL_SET_ERR_MSG(extack, "TCA_CHOKE_PARMS has invalid
red parameters");
                return -EINVAL;
-
-       if (ctl->limit > CHOKE_MAX_QUEUE)
+       }
+       if (ctl->limit > CHOKE_MAX_QUEUE) {
+               NL_SET_ERR_MSG(extack, "TCA_CHOKE_PARMS.limit exceeds
CHOKE_MAX_QUEUE");
                return -EINVAL;
+       }

        mask = roundup_pow_of_two(ctl->limit + 1) - 1;
        if (mask != q->tab_mask) {
diff mbox series

Patch

diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index fa678eb88528..7c37a69aba0e 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -782,15 +782,18 @@  static void dist_free(struct disttable *d)
  * signed 16 bit values.
  */
 
-static int get_dist_table(struct disttable **tbl, const struct nlattr *attr)
+static int get_dist_table(struct disttable **tbl, const struct nlattr *attr,
+			  struct netlink_ext_ack *extack)
 {
 	size_t n = nla_len(attr)/sizeof(__s16);
 	const __s16 *data = nla_data(attr);
 	struct disttable *d;
 	int i;
 
-	if (!n || n > NETEM_DIST_MAX)
+	if (!n || n > NETEM_DIST_MAX) {
+		NL_SET_ERR_MSG_FMT_MOD(extack, "invalid distribution table size: %zu", n);
 		return -EINVAL;
+	}
 
 	d = kvmalloc(struct_size(d, table, n), GFP_KERNEL);
 	if (!d)
@@ -865,7 +868,8 @@  static void get_rate(struct netem_sched_data *q, const struct nlattr *attr)
 		q->cell_size_reciprocal = (struct reciprocal_value) { 0 };
 }
 
-static int get_loss_clg(struct netem_sched_data *q, const struct nlattr *attr)
+static int get_loss_clg(struct netem_sched_data *q, const struct nlattr *attr,
+			struct netlink_ext_ack *extack)
 {
 	const struct nlattr *la;
 	int rem;
@@ -878,7 +882,7 @@  static int get_loss_clg(struct netem_sched_data *q, const struct nlattr *attr)
 			const struct tc_netem_gimodel *gi = nla_data(la);
 
 			if (nla_len(la) < sizeof(struct tc_netem_gimodel)) {
-				pr_info("netem: incorrect gi model size\n");
+				NL_SET_ERR_MSG_MOD(extack, "incorrect GI model size");
 				return -EINVAL;
 			}
 
@@ -897,7 +901,7 @@  static int get_loss_clg(struct netem_sched_data *q, const struct nlattr *attr)
 			const struct tc_netem_gemodel *ge = nla_data(la);
 
 			if (nla_len(la) < sizeof(struct tc_netem_gemodel)) {
-				pr_info("netem: incorrect ge model size\n");
+				NL_SET_ERR_MSG_MOD(extack, "incorrect GE model size");
 				return -EINVAL;
 			}
 
@@ -911,7 +915,7 @@  static int get_loss_clg(struct netem_sched_data *q, const struct nlattr *attr)
 		}
 
 		default:
-			pr_info("netem: unknown loss type %u\n", type);
+			NL_SET_ERR_MSG_FMT_MOD(extack, "unknown loss type: %u", type);
 			return -EINVAL;
 		}
 	}
@@ -934,12 +938,13 @@  static const struct nla_policy netem_policy[TCA_NETEM_MAX + 1] = {
 };
 
 static int parse_attr(struct nlattr *tb[], int maxtype, struct nlattr *nla,
-		      const struct nla_policy *policy, int len)
+		      const struct nla_policy *policy, int len,
+		      struct netlink_ext_ack *extack)
 {
 	int nested_len = nla_len(nla) - NLA_ALIGN(len);
 
 	if (nested_len < 0) {
-		pr_info("netem: invalid attributes len %d\n", nested_len);
+		NL_SET_ERR_MSG_MOD(extack, "invalid nested attribute length");
 		return -EINVAL;
 	}
 
@@ -966,18 +971,18 @@  static int netem_change(struct Qdisc *sch, struct nlattr *opt,
 	int ret;
 
 	qopt = nla_data(opt);
-	ret = parse_attr(tb, TCA_NETEM_MAX, opt, netem_policy, sizeof(*qopt));
+	ret = parse_attr(tb, TCA_NETEM_MAX, opt, netem_policy, sizeof(*qopt), extack);
 	if (ret < 0)
 		return ret;
 
 	if (tb[TCA_NETEM_DELAY_DIST]) {
-		ret = get_dist_table(&delay_dist, tb[TCA_NETEM_DELAY_DIST]);
+		ret = get_dist_table(&delay_dist, tb[TCA_NETEM_DELAY_DIST], extack);
 		if (ret)
 			goto table_free;
 	}
 
 	if (tb[TCA_NETEM_SLOT_DIST]) {
-		ret = get_dist_table(&slot_dist, tb[TCA_NETEM_SLOT_DIST]);
+		ret = get_dist_table(&slot_dist, tb[TCA_NETEM_SLOT_DIST], extack);
 		if (ret)
 			goto table_free;
 	}
@@ -988,7 +993,7 @@  static int netem_change(struct Qdisc *sch, struct nlattr *opt,
 	old_loss_model = q->loss_model;
 
 	if (tb[TCA_NETEM_LOSS]) {
-		ret = get_loss_clg(q, tb[TCA_NETEM_LOSS]);
+		ret = get_loss_clg(q, tb[TCA_NETEM_LOSS], extack);
 		if (ret) {
 			q->loss_model = old_loss_model;
 			q->clg = old_clg;
@@ -1068,18 +1073,16 @@  static int netem_init(struct Qdisc *sch, struct nlattr *opt,
 		      struct netlink_ext_ack *extack)
 {
 	struct netem_sched_data *q = qdisc_priv(sch);
-	int ret;
 
 	qdisc_watchdog_init(&q->watchdog, sch);
 
-	if (!opt)
+	if (!opt) {
+		NL_SET_ERR_MSG_MOD(extack, "Netem missing required parameters");
 		return -EINVAL;
+	}
 
 	q->loss_model = CLG_RANDOM;
-	ret = netem_change(sch, opt, extack);
-	if (ret)
-		pr_info("netem: change failed\n");
-	return ret;
+	return netem_change(sch, opt, extack);
 }
 
 static void netem_destroy(struct Qdisc *sch)