Skip to content

Commit 81e57ad

Browse files
committed
net-shapers: implement cap validation in the core
JIRA: https://issues.redhat.com/browse/RHEL-89973 commit ecd82cf Author: Paolo Abeni <pabeni@redhat.com> Date: Wed Oct 9 10:09:56 2024 +0200 net-shapers: implement cap validation in the core Use the device capabilities to reject invalid attribute values before pushing them to the H/W. Note that validating the metric explicitly avoids NL_SET_BAD_ATTR() usage, to provide unambiguous error messages to the user. Validating the nesting requires the knowledge of the new parent for the given shaper; as such is a chicken-egg problem: to validate the leaf nesting we need to know the node scope, to validate the node nesting we need to know the leafs parent scope. To break the circular dependency, place the leafs nesting validation after the parsing. Suggested-by: Jakub Kicinski <kuba@kernel.org> Reviewed-by: Jakub Kicinski <kuba@kernel.org> Reviewed-by: Jiri Pirko <jiri@nvidia.com> Signed-off-by: Paolo Abeni <pabeni@redhat.com> Link: https://patch.msgid.link/54667601813e4c0348f39bf8ad2446ffc9fcd383.1728460186.git.pabeni@redhat.com Signed-off-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: Jose Ignacio Tornos Martinez <jtornosm@redhat.com>
1 parent dbf3656 commit 81e57ad

File tree

1 file changed

+101
-0
lines changed

1 file changed

+101
-0
lines changed

net/shaper/shaper.c

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,74 @@ static int net_shaper_parse_handle(const struct nlattr *attr,
439439
return 0;
440440
}
441441

442+
static int net_shaper_validate_caps(struct net_shaper_binding *binding,
443+
struct nlattr **tb,
444+
const struct genl_info *info,
445+
struct net_shaper *shaper)
446+
{
447+
const struct net_shaper_ops *ops = net_shaper_ops(binding);
448+
struct nlattr *bad = NULL;
449+
unsigned long caps = 0;
450+
451+
ops->capabilities(binding, shaper->handle.scope, &caps);
452+
453+
if (tb[NET_SHAPER_A_PRIORITY] &&
454+
!(caps & BIT(NET_SHAPER_A_CAPS_SUPPORT_PRIORITY)))
455+
bad = tb[NET_SHAPER_A_PRIORITY];
456+
if (tb[NET_SHAPER_A_WEIGHT] &&
457+
!(caps & BIT(NET_SHAPER_A_CAPS_SUPPORT_WEIGHT)))
458+
bad = tb[NET_SHAPER_A_WEIGHT];
459+
if (tb[NET_SHAPER_A_BW_MIN] &&
460+
!(caps & BIT(NET_SHAPER_A_CAPS_SUPPORT_BW_MIN)))
461+
bad = tb[NET_SHAPER_A_BW_MIN];
462+
if (tb[NET_SHAPER_A_BW_MAX] &&
463+
!(caps & BIT(NET_SHAPER_A_CAPS_SUPPORT_BW_MAX)))
464+
bad = tb[NET_SHAPER_A_BW_MAX];
465+
if (tb[NET_SHAPER_A_BURST] &&
466+
!(caps & BIT(NET_SHAPER_A_CAPS_SUPPORT_BURST)))
467+
bad = tb[NET_SHAPER_A_BURST];
468+
469+
if (!caps)
470+
bad = tb[NET_SHAPER_A_HANDLE];
471+
472+
if (bad) {
473+
NL_SET_BAD_ATTR(info->extack, bad);
474+
return -EOPNOTSUPP;
475+
}
476+
477+
if (shaper->handle.scope == NET_SHAPER_SCOPE_QUEUE &&
478+
binding->type == NET_SHAPER_BINDING_TYPE_NETDEV &&
479+
shaper->handle.id >= binding->netdev->real_num_tx_queues) {
480+
NL_SET_ERR_MSG_FMT(info->extack,
481+
"Not existing queue id %d max %d",
482+
shaper->handle.id,
483+
binding->netdev->real_num_tx_queues);
484+
return -ENOENT;
485+
}
486+
487+
/* The metric is really used only if there is *any* rate-related
488+
* setting, either in current attributes set or in pre-existing
489+
* values.
490+
*/
491+
if (shaper->burst || shaper->bw_min || shaper->bw_max) {
492+
u32 metric_cap = NET_SHAPER_A_CAPS_SUPPORT_METRIC_BPS +
493+
shaper->metric;
494+
495+
/* The metric test can fail even when the user did not
496+
* specify the METRIC attribute. Pointing to rate related
497+
* attribute will be confusing, as the attribute itself
498+
* could be indeed supported, with a different metric.
499+
* Be more specific.
500+
*/
501+
if (!(caps & BIT(metric_cap))) {
502+
NL_SET_ERR_MSG_FMT(info->extack, "Bad metric %d",
503+
shaper->metric);
504+
return -EOPNOTSUPP;
505+
}
506+
}
507+
return 0;
508+
}
509+
442510
static int net_shaper_parse_info(struct net_shaper_binding *binding,
443511
struct nlattr **tb,
444512
const struct genl_info *info,
@@ -487,6 +555,28 @@ static int net_shaper_parse_info(struct net_shaper_binding *binding,
487555

488556
if (tb[NET_SHAPER_A_WEIGHT])
489557
shaper->weight = nla_get_u32(tb[NET_SHAPER_A_WEIGHT]);
558+
559+
ret = net_shaper_validate_caps(binding, tb, info, shaper);
560+
if (ret < 0)
561+
return ret;
562+
563+
return 0;
564+
}
565+
566+
static int net_shaper_validate_nesting(struct net_shaper_binding *binding,
567+
const struct net_shaper *shaper,
568+
struct netlink_ext_ack *extack)
569+
{
570+
const struct net_shaper_ops *ops = net_shaper_ops(binding);
571+
unsigned long caps = 0;
572+
573+
ops->capabilities(binding, shaper->handle.scope, &caps);
574+
if (!(caps & BIT(NET_SHAPER_A_CAPS_SUPPORT_NESTING))) {
575+
NL_SET_ERR_MSG_FMT(extack,
576+
"Nesting not supported for scope %d",
577+
shaper->handle.scope);
578+
return -EOPNOTSUPP;
579+
}
490580
return 0;
491581
}
492582

@@ -517,6 +607,13 @@ static int net_shaper_parse_leaf(struct net_shaper_binding *binding,
517607
return -EINVAL;
518608
}
519609

610+
if (node->handle.scope == NET_SHAPER_SCOPE_NODE) {
611+
ret = net_shaper_validate_nesting(binding, shaper,
612+
info->extack);
613+
if (ret < 0)
614+
return ret;
615+
}
616+
520617
if (!exists)
521618
net_shaper_default_parent(&shaper->handle, &shaper->parent);
522619
return 0;
@@ -858,6 +955,10 @@ static int __net_shaper_group(struct net_shaper_binding *binding,
858955
node->parent.scope, node->parent.id);
859956
return -ENOENT;
860957
}
958+
959+
ret = net_shaper_validate_nesting(binding, node, extack);
960+
if (ret < 0)
961+
return ret;
861962
}
862963

863964
if (update_node) {

0 commit comments

Comments
 (0)