Merge branch 'net-sched-action-bind'
Pedro Tammela says: ==================== net/sched: fix action bind logic Some actions are not handling the case where an action can be created and bound to a filter independently. These actions are checking for parameters only passed in the netlink message for create/change/replace, which then errors out for valid uses like: tc filter ... action pedit index 1 In the iproute2 side, we saw a couple of actions with their parsers broken when passing "index 1" as the only action argument, while the kernel side accepted it correctly. We fixed those as well. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
3fa1056336
@ -190,40 +190,67 @@ static int tcf_mpls_init(struct net *net, struct nlattr *nla,
|
||||
parm = nla_data(tb[TCA_MPLS_PARMS]);
|
||||
index = parm->index;
|
||||
|
||||
err = tcf_idr_check_alloc(tn, &index, a, bind);
|
||||
if (err < 0)
|
||||
return err;
|
||||
exists = err;
|
||||
if (exists && bind)
|
||||
return 0;
|
||||
|
||||
if (!exists) {
|
||||
ret = tcf_idr_create(tn, index, est, a, &act_mpls_ops, bind,
|
||||
true, flags);
|
||||
if (ret) {
|
||||
tcf_idr_cleanup(tn, index);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ACT_P_CREATED;
|
||||
} else if (!(flags & TCA_ACT_FLAGS_REPLACE)) {
|
||||
tcf_idr_release(*a, bind);
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
/* Verify parameters against action type. */
|
||||
switch (parm->m_action) {
|
||||
case TCA_MPLS_ACT_POP:
|
||||
if (!tb[TCA_MPLS_PROTO]) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Protocol must be set for MPLS pop");
|
||||
return -EINVAL;
|
||||
err = -EINVAL;
|
||||
goto release_idr;
|
||||
}
|
||||
if (!eth_proto_is_802_3(nla_get_be16(tb[TCA_MPLS_PROTO]))) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Invalid protocol type for MPLS pop");
|
||||
return -EINVAL;
|
||||
err = -EINVAL;
|
||||
goto release_idr;
|
||||
}
|
||||
if (tb[TCA_MPLS_LABEL] || tb[TCA_MPLS_TTL] || tb[TCA_MPLS_TC] ||
|
||||
tb[TCA_MPLS_BOS]) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Label, TTL, TC or BOS cannot be used with MPLS pop");
|
||||
return -EINVAL;
|
||||
err = -EINVAL;
|
||||
goto release_idr;
|
||||
}
|
||||
break;
|
||||
case TCA_MPLS_ACT_DEC_TTL:
|
||||
if (tb[TCA_MPLS_PROTO] || tb[TCA_MPLS_LABEL] ||
|
||||
tb[TCA_MPLS_TTL] || tb[TCA_MPLS_TC] || tb[TCA_MPLS_BOS]) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Label, TTL, TC, BOS or protocol cannot be used with MPLS dec_ttl");
|
||||
return -EINVAL;
|
||||
err = -EINVAL;
|
||||
goto release_idr;
|
||||
}
|
||||
break;
|
||||
case TCA_MPLS_ACT_PUSH:
|
||||
case TCA_MPLS_ACT_MAC_PUSH:
|
||||
if (!tb[TCA_MPLS_LABEL]) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Label is required for MPLS push");
|
||||
return -EINVAL;
|
||||
err = -EINVAL;
|
||||
goto release_idr;
|
||||
}
|
||||
if (tb[TCA_MPLS_PROTO] &&
|
||||
!eth_p_mpls(nla_get_be16(tb[TCA_MPLS_PROTO]))) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Protocol must be an MPLS type for MPLS push");
|
||||
return -EPROTONOSUPPORT;
|
||||
err = -EPROTONOSUPPORT;
|
||||
goto release_idr;
|
||||
}
|
||||
/* Push needs a TTL - if not specified, set a default value. */
|
||||
if (!tb[TCA_MPLS_TTL]) {
|
||||
@ -238,33 +265,14 @@ static int tcf_mpls_init(struct net *net, struct nlattr *nla,
|
||||
case TCA_MPLS_ACT_MODIFY:
|
||||
if (tb[TCA_MPLS_PROTO]) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Protocol cannot be used with MPLS modify");
|
||||
return -EINVAL;
|
||||
err = -EINVAL;
|
||||
goto release_idr;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
NL_SET_ERR_MSG_MOD(extack, "Unknown MPLS action");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = tcf_idr_check_alloc(tn, &index, a, bind);
|
||||
if (err < 0)
|
||||
return err;
|
||||
exists = err;
|
||||
if (exists && bind)
|
||||
return 0;
|
||||
|
||||
if (!exists) {
|
||||
ret = tcf_idr_create(tn, index, est, a,
|
||||
&act_mpls_ops, bind, true, flags);
|
||||
if (ret) {
|
||||
tcf_idr_cleanup(tn, index);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ACT_P_CREATED;
|
||||
} else if (!(flags & TCA_ACT_FLAGS_REPLACE)) {
|
||||
tcf_idr_release(*a, bind);
|
||||
return -EEXIST;
|
||||
err = -EINVAL;
|
||||
goto release_idr;
|
||||
}
|
||||
|
||||
err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack);
|
||||
|
@ -181,26 +181,6 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
|
||||
}
|
||||
|
||||
parm = nla_data(pattr);
|
||||
if (!parm->nkeys) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Pedit requires keys to be passed");
|
||||
return -EINVAL;
|
||||
}
|
||||
ksize = parm->nkeys * sizeof(struct tc_pedit_key);
|
||||
if (nla_len(pattr) < sizeof(*parm) + ksize) {
|
||||
NL_SET_ERR_MSG_ATTR(extack, pattr, "Length of TCA_PEDIT_PARMS or TCA_PEDIT_PARMS_EX pedit attribute is invalid");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
nparms = kzalloc(sizeof(*nparms), GFP_KERNEL);
|
||||
if (!nparms)
|
||||
return -ENOMEM;
|
||||
|
||||
nparms->tcfp_keys_ex =
|
||||
tcf_pedit_keys_ex_parse(tb[TCA_PEDIT_KEYS_EX], parm->nkeys);
|
||||
if (IS_ERR(nparms->tcfp_keys_ex)) {
|
||||
ret = PTR_ERR(nparms->tcfp_keys_ex);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
index = parm->index;
|
||||
err = tcf_idr_check_alloc(tn, &index, a, bind);
|
||||
@ -209,25 +189,49 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
|
||||
&act_pedit_ops, bind, flags);
|
||||
if (ret) {
|
||||
tcf_idr_cleanup(tn, index);
|
||||
goto out_free_ex;
|
||||
return ret;
|
||||
}
|
||||
ret = ACT_P_CREATED;
|
||||
} else if (err > 0) {
|
||||
if (bind)
|
||||
goto out_free;
|
||||
return 0;
|
||||
if (!(flags & TCA_ACT_FLAGS_REPLACE)) {
|
||||
ret = -EEXIST;
|
||||
goto out_release;
|
||||
}
|
||||
} else {
|
||||
ret = err;
|
||||
goto out_free_ex;
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!parm->nkeys) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Pedit requires keys to be passed");
|
||||
ret = -EINVAL;
|
||||
goto out_release;
|
||||
}
|
||||
ksize = parm->nkeys * sizeof(struct tc_pedit_key);
|
||||
if (nla_len(pattr) < sizeof(*parm) + ksize) {
|
||||
NL_SET_ERR_MSG_ATTR(extack, pattr, "Length of TCA_PEDIT_PARMS or TCA_PEDIT_PARMS_EX pedit attribute is invalid");
|
||||
ret = -EINVAL;
|
||||
goto out_release;
|
||||
}
|
||||
|
||||
nparms = kzalloc(sizeof(*nparms), GFP_KERNEL);
|
||||
if (!nparms) {
|
||||
ret = -ENOMEM;
|
||||
goto out_release;
|
||||
}
|
||||
|
||||
nparms->tcfp_keys_ex =
|
||||
tcf_pedit_keys_ex_parse(tb[TCA_PEDIT_KEYS_EX], parm->nkeys);
|
||||
if (IS_ERR(nparms->tcfp_keys_ex)) {
|
||||
ret = PTR_ERR(nparms->tcfp_keys_ex);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack);
|
||||
if (err < 0) {
|
||||
ret = err;
|
||||
goto out_release;
|
||||
goto out_free_ex;
|
||||
}
|
||||
|
||||
nparms->tcfp_off_max_hint = 0;
|
||||
@ -278,12 +282,12 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
|
||||
put_chain:
|
||||
if (goto_ch)
|
||||
tcf_chain_put_by_act(goto_ch);
|
||||
out_release:
|
||||
tcf_idr_release(*a, bind);
|
||||
out_free_ex:
|
||||
kfree(nparms->tcfp_keys_ex);
|
||||
out_free:
|
||||
kfree(nparms);
|
||||
out_release:
|
||||
tcf_idr_release(*a, bind);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -55,8 +55,8 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla,
|
||||
sample_policy, NULL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (!tb[TCA_SAMPLE_PARMS] || !tb[TCA_SAMPLE_RATE] ||
|
||||
!tb[TCA_SAMPLE_PSAMPLE_GROUP])
|
||||
|
||||
if (!tb[TCA_SAMPLE_PARMS])
|
||||
return -EINVAL;
|
||||
|
||||
parm = nla_data(tb[TCA_SAMPLE_PARMS]);
|
||||
@ -80,6 +80,13 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla,
|
||||
tcf_idr_release(*a, bind);
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
if (!tb[TCA_SAMPLE_RATE] || !tb[TCA_SAMPLE_PSAMPLE_GROUP]) {
|
||||
NL_SET_ERR_MSG(extack, "sample rate and group are required");
|
||||
err = -EINVAL;
|
||||
goto release_idr;
|
||||
}
|
||||
|
||||
err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack);
|
||||
if (err < 0)
|
||||
goto release_idr;
|
||||
|
Loading…
x
Reference in New Issue
Block a user