Commit fd84c569 authored by David S. Miller's avatar David S. Miller

Merge branch 'act_pedit-minor-improvements'

Pedro Tammela says:

====================
net/sched: act_pedit: minor improvements

This series aims to improve the code and usability of act_pedit for
netlink users.

Patches 1-2 improves error reporting for extended keys parsing with extack.

Patch 3 checks the static offsets a priori on create/update. Currently,
this is done at the datapath for both static and runtime offsets.

Patch 4 removes a check from the datapath which is redundant since the
netlink parsing validates the key types.

Patch 5 changes the 'pr_info()' calls in the datapath to rate limited
versions.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 2f0f9465 e3c9673e
...@@ -30,12 +30,13 @@ static const struct nla_policy pedit_policy[TCA_PEDIT_MAX + 1] = { ...@@ -30,12 +30,13 @@ static const struct nla_policy pedit_policy[TCA_PEDIT_MAX + 1] = {
}; };
static const struct nla_policy pedit_key_ex_policy[TCA_PEDIT_KEY_EX_MAX + 1] = { static const struct nla_policy pedit_key_ex_policy[TCA_PEDIT_KEY_EX_MAX + 1] = {
[TCA_PEDIT_KEY_EX_HTYPE] = { .type = NLA_U16 }, [TCA_PEDIT_KEY_EX_HTYPE] =
[TCA_PEDIT_KEY_EX_CMD] = { .type = NLA_U16 }, NLA_POLICY_MAX(NLA_U16, TCA_PEDIT_HDR_TYPE_MAX),
[TCA_PEDIT_KEY_EX_CMD] = NLA_POLICY_MAX(NLA_U16, TCA_PEDIT_CMD_MAX),
}; };
static struct tcf_pedit_key_ex *tcf_pedit_keys_ex_parse(struct nlattr *nla, static struct tcf_pedit_key_ex *tcf_pedit_keys_ex_parse(struct nlattr *nla,
u8 n) u8 n, struct netlink_ext_ack *extack)
{ {
struct tcf_pedit_key_ex *keys_ex; struct tcf_pedit_key_ex *keys_ex;
struct tcf_pedit_key_ex *k; struct tcf_pedit_key_ex *k;
...@@ -56,12 +57,14 @@ static struct tcf_pedit_key_ex *tcf_pedit_keys_ex_parse(struct nlattr *nla, ...@@ -56,12 +57,14 @@ static struct tcf_pedit_key_ex *tcf_pedit_keys_ex_parse(struct nlattr *nla,
struct nlattr *tb[TCA_PEDIT_KEY_EX_MAX + 1]; struct nlattr *tb[TCA_PEDIT_KEY_EX_MAX + 1];
if (!n) { if (!n) {
NL_SET_ERR_MSG_MOD(extack, "Can't parse more extended keys than requested");
err = -EINVAL; err = -EINVAL;
goto err_out; goto err_out;
} }
n--; n--;
if (nla_type(ka) != TCA_PEDIT_KEY_EX) { if (nla_type(ka) != TCA_PEDIT_KEY_EX) {
NL_SET_ERR_MSG_ATTR(extack, ka, "Unknown attribute, expected extended key");
err = -EINVAL; err = -EINVAL;
goto err_out; goto err_out;
} }
...@@ -72,25 +75,26 @@ static struct tcf_pedit_key_ex *tcf_pedit_keys_ex_parse(struct nlattr *nla, ...@@ -72,25 +75,26 @@ static struct tcf_pedit_key_ex *tcf_pedit_keys_ex_parse(struct nlattr *nla,
if (err) if (err)
goto err_out; goto err_out;
if (!tb[TCA_PEDIT_KEY_EX_HTYPE] || if (NL_REQ_ATTR_CHECK(extack, nla, tb, TCA_PEDIT_KEY_EX_HTYPE)) {
!tb[TCA_PEDIT_KEY_EX_CMD]) { NL_SET_ERR_MSG(extack, "Missing required attribute");
err = -EINVAL; err = -EINVAL;
goto err_out; goto err_out;
} }
k->htype = nla_get_u16(tb[TCA_PEDIT_KEY_EX_HTYPE]); if (NL_REQ_ATTR_CHECK(extack, nla, tb, TCA_PEDIT_KEY_EX_CMD)) {
k->cmd = nla_get_u16(tb[TCA_PEDIT_KEY_EX_CMD]); NL_SET_ERR_MSG(extack, "Missing required attribute");
if (k->htype > TCA_PEDIT_HDR_TYPE_MAX ||
k->cmd > TCA_PEDIT_CMD_MAX) {
err = -EINVAL; err = -EINVAL;
goto err_out; goto err_out;
} }
k->htype = nla_get_u16(tb[TCA_PEDIT_KEY_EX_HTYPE]);
k->cmd = nla_get_u16(tb[TCA_PEDIT_KEY_EX_CMD]);
k++; k++;
} }
if (n) { if (n) {
NL_SET_ERR_MSG_MOD(extack, "Not enough extended keys to parse");
err = -EINVAL; err = -EINVAL;
goto err_out; goto err_out;
} }
...@@ -222,7 +226,7 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, ...@@ -222,7 +226,7 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
} }
nparms->tcfp_keys_ex = nparms->tcfp_keys_ex =
tcf_pedit_keys_ex_parse(tb[TCA_PEDIT_KEYS_EX], parm->nkeys); tcf_pedit_keys_ex_parse(tb[TCA_PEDIT_KEYS_EX], parm->nkeys, extack);
if (IS_ERR(nparms->tcfp_keys_ex)) { if (IS_ERR(nparms->tcfp_keys_ex)) {
ret = PTR_ERR(nparms->tcfp_keys_ex); ret = PTR_ERR(nparms->tcfp_keys_ex);
goto out_free; goto out_free;
...@@ -247,8 +251,16 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, ...@@ -247,8 +251,16 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
memcpy(nparms->tcfp_keys, parm->keys, ksize); memcpy(nparms->tcfp_keys, parm->keys, ksize);
for (i = 0; i < nparms->tcfp_nkeys; ++i) { for (i = 0; i < nparms->tcfp_nkeys; ++i) {
u32 offmask = nparms->tcfp_keys[i].offmask;
u32 cur = nparms->tcfp_keys[i].off; u32 cur = nparms->tcfp_keys[i].off;
/* The AT option can be added to static offsets in the datapath */
if (!offmask && cur % 4) {
NL_SET_ERR_MSG_MOD(extack, "Offsets must be on 32bit boundaries");
ret = -EINVAL;
goto put_chain;
}
/* sanitize the shift value for any later use */ /* sanitize the shift value for any later use */
nparms->tcfp_keys[i].shift = min_t(size_t, nparms->tcfp_keys[i].shift = min_t(size_t,
BITS_PER_TYPE(int) - 1, BITS_PER_TYPE(int) - 1,
...@@ -257,7 +269,7 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, ...@@ -257,7 +269,7 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
/* The AT option can read a single byte, we can bound the actual /* The AT option can read a single byte, we can bound the actual
* value with uchar max. * value with uchar max.
*/ */
cur += (0xff & nparms->tcfp_keys[i].offmask) >> nparms->tcfp_keys[i].shift; cur += (0xff & offmask) >> nparms->tcfp_keys[i].shift;
/* Each key touches 4 bytes starting from the computed offset */ /* Each key touches 4 bytes starting from the computed offset */
nparms->tcfp_off_max_hint = nparms->tcfp_off_max_hint =
...@@ -313,37 +325,28 @@ static bool offset_valid(struct sk_buff *skb, int offset) ...@@ -313,37 +325,28 @@ static bool offset_valid(struct sk_buff *skb, int offset)
return true; return true;
} }
static int pedit_skb_hdr_offset(struct sk_buff *skb, static void pedit_skb_hdr_offset(struct sk_buff *skb,
enum pedit_header_type htype, int *hoffset) enum pedit_header_type htype, int *hoffset)
{ {
int ret = -EINVAL; /* 'htype' is validated in the netlink parsing */
switch (htype) { switch (htype) {
case TCA_PEDIT_KEY_EX_HDR_TYPE_ETH: case TCA_PEDIT_KEY_EX_HDR_TYPE_ETH:
if (skb_mac_header_was_set(skb)) { if (skb_mac_header_was_set(skb))
*hoffset = skb_mac_offset(skb); *hoffset = skb_mac_offset(skb);
ret = 0;
}
break; break;
case TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK: case TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK:
case TCA_PEDIT_KEY_EX_HDR_TYPE_IP4: case TCA_PEDIT_KEY_EX_HDR_TYPE_IP4:
case TCA_PEDIT_KEY_EX_HDR_TYPE_IP6: case TCA_PEDIT_KEY_EX_HDR_TYPE_IP6:
*hoffset = skb_network_offset(skb); *hoffset = skb_network_offset(skb);
ret = 0;
break; break;
case TCA_PEDIT_KEY_EX_HDR_TYPE_TCP: case TCA_PEDIT_KEY_EX_HDR_TYPE_TCP:
case TCA_PEDIT_KEY_EX_HDR_TYPE_UDP: case TCA_PEDIT_KEY_EX_HDR_TYPE_UDP:
if (skb_transport_header_was_set(skb)) { if (skb_transport_header_was_set(skb))
*hoffset = skb_transport_offset(skb); *hoffset = skb_transport_offset(skb);
ret = 0;
}
break; break;
default: default:
ret = -EINVAL;
break; break;
} }
return ret;
} }
TC_INDIRECT_SCOPE int tcf_pedit_act(struct sk_buff *skb, TC_INDIRECT_SCOPE int tcf_pedit_act(struct sk_buff *skb,
...@@ -376,10 +379,9 @@ TC_INDIRECT_SCOPE int tcf_pedit_act(struct sk_buff *skb, ...@@ -376,10 +379,9 @@ TC_INDIRECT_SCOPE int tcf_pedit_act(struct sk_buff *skb,
for (i = parms->tcfp_nkeys; i > 0; i--, tkey++) { for (i = parms->tcfp_nkeys; i > 0; i--, tkey++) {
int offset = tkey->off; int offset = tkey->off;
int hoffset = 0;
u32 *ptr, hdata; u32 *ptr, hdata;
int hoffset;
u32 val; u32 val;
int rc;
if (tkey_ex) { if (tkey_ex) {
htype = tkey_ex->htype; htype = tkey_ex->htype;
...@@ -388,36 +390,30 @@ TC_INDIRECT_SCOPE int tcf_pedit_act(struct sk_buff *skb, ...@@ -388,36 +390,30 @@ TC_INDIRECT_SCOPE int tcf_pedit_act(struct sk_buff *skb,
tkey_ex++; tkey_ex++;
} }
rc = pedit_skb_hdr_offset(skb, htype, &hoffset); pedit_skb_hdr_offset(skb, htype, &hoffset);
if (rc) {
pr_info("tc action pedit bad header type specified (0x%x)\n",
htype);
goto bad;
}
if (tkey->offmask) { if (tkey->offmask) {
u8 *d, _d; u8 *d, _d;
if (!offset_valid(skb, hoffset + tkey->at)) { if (!offset_valid(skb, hoffset + tkey->at)) {
pr_info("tc action pedit 'at' offset %d out of bounds\n", pr_info_ratelimited("tc action pedit 'at' offset %d out of bounds\n",
hoffset + tkey->at); hoffset + tkey->at);
goto bad; goto bad;
} }
d = skb_header_pointer(skb, hoffset + tkey->at, d = skb_header_pointer(skb, hoffset + tkey->at,
sizeof(_d), &_d); sizeof(_d), &_d);
if (!d) if (!d)
goto bad; goto bad;
offset += (*d & tkey->offmask) >> tkey->shift;
}
if (offset % 4) { offset += (*d & tkey->offmask) >> tkey->shift;
pr_info("tc action pedit offset must be on 32 bit boundaries\n"); if (offset % 4) {
goto bad; pr_info_ratelimited("tc action pedit offset must be on 32 bit boundaries\n");
goto bad;
}
} }
if (!offset_valid(skb, hoffset + offset)) { if (!offset_valid(skb, hoffset + offset)) {
pr_info("tc action pedit offset %d out of bounds\n", pr_info_ratelimited("tc action pedit offset %d out of bounds\n", hoffset + offset);
hoffset + offset);
goto bad; goto bad;
} }
...@@ -434,8 +430,7 @@ TC_INDIRECT_SCOPE int tcf_pedit_act(struct sk_buff *skb, ...@@ -434,8 +430,7 @@ TC_INDIRECT_SCOPE int tcf_pedit_act(struct sk_buff *skb,
val = (*ptr + tkey->val) & ~tkey->mask; val = (*ptr + tkey->val) & ~tkey->mask;
break; break;
default: default:
pr_info("tc action pedit bad command (%d)\n", pr_info_ratelimited("tc action pedit bad command (%d)\n", cmd);
cmd);
goto bad; goto bad;
} }
......
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