Commit 3fa10563 authored by David S. Miller's avatar David S. Miller

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: default avatarDavid S. Miller <davem@davemloft.net>
parents aaa3c08e 4a20056a
...@@ -190,40 +190,67 @@ static int tcf_mpls_init(struct net *net, struct nlattr *nla, ...@@ -190,40 +190,67 @@ static int tcf_mpls_init(struct net *net, struct nlattr *nla,
parm = nla_data(tb[TCA_MPLS_PARMS]); parm = nla_data(tb[TCA_MPLS_PARMS]);
index = parm->index; 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. */ /* Verify parameters against action type. */
switch (parm->m_action) { switch (parm->m_action) {
case TCA_MPLS_ACT_POP: case TCA_MPLS_ACT_POP:
if (!tb[TCA_MPLS_PROTO]) { if (!tb[TCA_MPLS_PROTO]) {
NL_SET_ERR_MSG_MOD(extack, "Protocol must be set for MPLS pop"); 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]))) { 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"); 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] || if (tb[TCA_MPLS_LABEL] || tb[TCA_MPLS_TTL] || tb[TCA_MPLS_TC] ||
tb[TCA_MPLS_BOS]) { tb[TCA_MPLS_BOS]) {
NL_SET_ERR_MSG_MOD(extack, "Label, TTL, TC or BOS cannot be used with MPLS pop"); 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; break;
case TCA_MPLS_ACT_DEC_TTL: case TCA_MPLS_ACT_DEC_TTL:
if (tb[TCA_MPLS_PROTO] || tb[TCA_MPLS_LABEL] || if (tb[TCA_MPLS_PROTO] || tb[TCA_MPLS_LABEL] ||
tb[TCA_MPLS_TTL] || tb[TCA_MPLS_TC] || tb[TCA_MPLS_BOS]) { 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"); 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; break;
case TCA_MPLS_ACT_PUSH: case TCA_MPLS_ACT_PUSH:
case TCA_MPLS_ACT_MAC_PUSH: case TCA_MPLS_ACT_MAC_PUSH:
if (!tb[TCA_MPLS_LABEL]) { if (!tb[TCA_MPLS_LABEL]) {
NL_SET_ERR_MSG_MOD(extack, "Label is required for MPLS push"); NL_SET_ERR_MSG_MOD(extack, "Label is required for MPLS push");
return -EINVAL; err = -EINVAL;
goto release_idr;
} }
if (tb[TCA_MPLS_PROTO] && if (tb[TCA_MPLS_PROTO] &&
!eth_p_mpls(nla_get_be16(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"); 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. */ /* Push needs a TTL - if not specified, set a default value. */
if (!tb[TCA_MPLS_TTL]) { if (!tb[TCA_MPLS_TTL]) {
...@@ -238,33 +265,14 @@ static int tcf_mpls_init(struct net *net, struct nlattr *nla, ...@@ -238,33 +265,14 @@ static int tcf_mpls_init(struct net *net, struct nlattr *nla,
case TCA_MPLS_ACT_MODIFY: case TCA_MPLS_ACT_MODIFY:
if (tb[TCA_MPLS_PROTO]) { if (tb[TCA_MPLS_PROTO]) {
NL_SET_ERR_MSG_MOD(extack, "Protocol cannot be used with MPLS modify"); NL_SET_ERR_MSG_MOD(extack, "Protocol cannot be used with MPLS modify");
return -EINVAL; err = -EINVAL;
goto release_idr;
} }
break; break;
default: default:
NL_SET_ERR_MSG_MOD(extack, "Unknown MPLS action"); NL_SET_ERR_MSG_MOD(extack, "Unknown MPLS action");
return -EINVAL; err = -EINVAL;
} goto release_idr;
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 = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack); 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, ...@@ -181,26 +181,6 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
} }
parm = nla_data(pattr); 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; index = parm->index;
err = tcf_idr_check_alloc(tn, &index, a, bind); err = tcf_idr_check_alloc(tn, &index, a, bind);
...@@ -209,25 +189,49 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, ...@@ -209,25 +189,49 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
&act_pedit_ops, bind, flags); &act_pedit_ops, bind, flags);
if (ret) { if (ret) {
tcf_idr_cleanup(tn, index); tcf_idr_cleanup(tn, index);
goto out_free_ex; return ret;
} }
ret = ACT_P_CREATED; ret = ACT_P_CREATED;
} else if (err > 0) { } else if (err > 0) {
if (bind) if (bind)
goto out_free; return 0;
if (!(flags & TCA_ACT_FLAGS_REPLACE)) { if (!(flags & TCA_ACT_FLAGS_REPLACE)) {
ret = -EEXIST; ret = -EEXIST;
goto out_release; goto out_release;
} }
} else { } else {
ret = err; return err;
goto out_free_ex; }
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); err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack);
if (err < 0) { if (err < 0) {
ret = err; ret = err;
goto out_release; goto out_free_ex;
} }
nparms->tcfp_off_max_hint = 0; nparms->tcfp_off_max_hint = 0;
...@@ -278,12 +282,12 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, ...@@ -278,12 +282,12 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
put_chain: put_chain:
if (goto_ch) if (goto_ch)
tcf_chain_put_by_act(goto_ch); tcf_chain_put_by_act(goto_ch);
out_release:
tcf_idr_release(*a, bind);
out_free_ex: out_free_ex:
kfree(nparms->tcfp_keys_ex); kfree(nparms->tcfp_keys_ex);
out_free: out_free:
kfree(nparms); kfree(nparms);
out_release:
tcf_idr_release(*a, bind);
return ret; return ret;
} }
......
...@@ -55,8 +55,8 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla, ...@@ -55,8 +55,8 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla,
sample_policy, NULL); sample_policy, NULL);
if (ret < 0) if (ret < 0)
return ret; return ret;
if (!tb[TCA_SAMPLE_PARMS] || !tb[TCA_SAMPLE_RATE] ||
!tb[TCA_SAMPLE_PSAMPLE_GROUP]) if (!tb[TCA_SAMPLE_PARMS])
return -EINVAL; return -EINVAL;
parm = nla_data(tb[TCA_SAMPLE_PARMS]); parm = nla_data(tb[TCA_SAMPLE_PARMS]);
...@@ -80,6 +80,13 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla, ...@@ -80,6 +80,13 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla,
tcf_idr_release(*a, bind); tcf_idr_release(*a, bind);
return -EEXIST; 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); err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack);
if (err < 0) if (err < 0)
goto release_idr; goto release_idr;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment