Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 14 additions & 8 deletions include/net/act_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,14 @@ struct tc_action {
#define TCA_ACT_HW_STATS_ANY (TCA_ACT_HW_STATS_IMMEDIATE | \
TCA_ACT_HW_STATS_DELAYED)

/* Reserve 16 bits for user-space. See TCA_ACT_FLAGS_NO_PERCPU_STATS. */
#define TCA_ACT_FLAGS_USER_BITS 16
#define TCA_ACT_FLAGS_USER_MASK 0xffff
#define TCA_ACT_FLAGS_POLICE (1U << TCA_ACT_FLAGS_USER_BITS)
#define TCA_ACT_FLAGS_BIND (1U << (TCA_ACT_FLAGS_USER_BITS + 1))
#define TCA_ACT_FLAGS_REPLACE (1U << (TCA_ACT_FLAGS_USER_BITS + 2))
#define TCA_ACT_FLAGS_NO_RTNL (1U << (TCA_ACT_FLAGS_USER_BITS + 3))

/* Update lastuse only if needed, to avoid dirtying a cache line.
* We use a temp variable to avoid fetching jiffies twice.
*/
Expand Down Expand Up @@ -99,8 +107,8 @@ struct tc_action_ops {
void (*cleanup)(struct tc_action *);
int (*lookup)(struct net *net, struct tc_action **a, u32 index);
int (*init)(struct net *net, struct nlattr *nla,
struct nlattr *est, struct tc_action **act, int ovr,
int bind, bool rtnl_held, struct tcf_proto *tp,
struct nlattr *est, struct tc_action **act,
struct tcf_proto *tp,
u32 flags, struct netlink_ext_ack *extack);
int (*walk)(struct net *, struct sk_buff *,
struct netlink_callback *, int,
Expand Down Expand Up @@ -179,18 +187,16 @@ int tcf_action_destroy(struct tc_action *actions[], int bind);
int tcf_action_exec(struct sk_buff *skb, struct tc_action **actions,
int nr_actions, struct tcf_result *res);
int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla,
struct nlattr *est, char *name, int ovr, int bind,
struct nlattr *est,
struct tc_action *actions[], int init_res[], size_t *attr_size,
bool rtnl_held, struct netlink_ext_ack *extack);
struct tc_action_ops *tc_action_load_ops(char *name, struct nlattr *nla,
u32 flags, struct netlink_ext_ack *extack);
struct tc_action_ops *tc_action_load_ops(struct nlattr *nla, bool police,
bool rtnl_held,
struct netlink_ext_ack *extack);
struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
struct nlattr *nla, struct nlattr *est,
char *name, int ovr, int bind,
struct tc_action_ops *a_o, int *init_res,
bool rtnl_held,
struct netlink_ext_ack *extack);
u32 flags, struct netlink_ext_ack *extack);
int tcf_action_dump(struct sk_buff *skb, struct tc_action *actions[], int bind,
int ref, bool terse);
int tcf_action_dump_old(struct sk_buff *skb, struct tc_action *a, int, int);
Expand Down
2 changes: 1 addition & 1 deletion include/net/pkt_cls.h
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ tcf_exts_exec(struct sk_buff *skb, struct tcf_exts *exts,

int tcf_exts_validate(struct net *net, struct tcf_proto *tp,
struct nlattr **tb, struct nlattr *rate_tlv,
struct tcf_exts *exts, bool ovr, bool rtnl_held,
struct tcf_exts *exts, u32 flags,
struct netlink_ext_ack *extack);
void tcf_exts_destroy(struct tcf_exts *exts);
void tcf_exts_change(struct tcf_exts *dst, struct tcf_exts *src);
Expand Down
2 changes: 1 addition & 1 deletion include/net/sch_generic.h
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ struct tcf_proto_ops {
int (*change)(struct net *net, struct sk_buff *,
struct tcf_proto*, unsigned long,
u32 handle, struct nlattr **,
void **, bool, bool,
void **, u32,
struct netlink_ext_ack *);
int (*delete)(struct tcf_proto *tp, void *arg,
bool *last, bool rtnl_held,
Expand Down
79 changes: 65 additions & 14 deletions include/net/tc_act/tc_pedit.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,28 @@

#include <net/act_api.h>
#include <linux/tc_act/tc_pedit.h>
#include <linux/types.h>

struct tcf_pedit_key_ex {
enum pedit_header_type htype;
enum pedit_cmd cmd;
};

struct tcf_pedit {
struct tc_action common;
unsigned char tcfp_nkeys;
unsigned char tcfp_flags;
struct tcf_pedit_parms {
struct tc_pedit_key *tcfp_keys;
struct tcf_pedit_key_ex *tcfp_keys_ex;
unsigned char tcfp_nkeys;
unsigned char tcfp_flags;
struct rcu_head rcu;
};

struct tcf_pedit {
struct tc_action common;
struct tcf_pedit_parms __rcu *parms;
};

#define to_pedit(a) ((struct tcf_pedit *)a)
#define to_pedit_parms(a) (rcu_dereference(to_pedit(a)->parms))

static inline bool is_tcf_pedit(const struct tc_action *a)
{
Expand All @@ -31,37 +38,81 @@ static inline bool is_tcf_pedit(const struct tc_action *a)

static inline int tcf_pedit_nkeys(const struct tc_action *a)
{
return to_pedit(a)->tcfp_nkeys;
struct tcf_pedit_parms *parms;
int nkeys;

rcu_read_lock();
parms = to_pedit_parms(a);
nkeys = parms->tcfp_nkeys;
rcu_read_unlock();

return nkeys;
}

static inline u32 tcf_pedit_htype(const struct tc_action *a, int index)
{
if (to_pedit(a)->tcfp_keys_ex)
return to_pedit(a)->tcfp_keys_ex[index].htype;
u32 htype = TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK;
struct tcf_pedit_parms *parms;

rcu_read_lock();
parms = to_pedit_parms(a);
if (parms->tcfp_keys_ex)
htype = parms->tcfp_keys_ex[index].htype;
rcu_read_unlock();

return TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK;
return htype;
}

static inline u32 tcf_pedit_cmd(const struct tc_action *a, int index)
{
if (to_pedit(a)->tcfp_keys_ex)
return to_pedit(a)->tcfp_keys_ex[index].cmd;
struct tcf_pedit_parms *parms;
u32 cmd = __PEDIT_CMD_MAX;

return __PEDIT_CMD_MAX;
rcu_read_lock();
parms = to_pedit_parms(a);
if (parms->tcfp_keys_ex)
cmd = parms->tcfp_keys_ex[index].cmd;
rcu_read_unlock();

return cmd;
}

static inline u32 tcf_pedit_mask(const struct tc_action *a, int index)
{
return to_pedit(a)->tcfp_keys[index].mask;
struct tcf_pedit_parms *parms;
u32 mask;

rcu_read_lock();
parms = to_pedit_parms(a);
mask = parms->tcfp_keys[index].mask;
rcu_read_unlock();

return mask;
}

static inline u32 tcf_pedit_val(const struct tc_action *a, int index)
{
return to_pedit(a)->tcfp_keys[index].val;
struct tcf_pedit_parms *parms;
u32 val;

rcu_read_lock();
parms = to_pedit_parms(a);
val = parms->tcfp_keys[index].val;
rcu_read_unlock();

return val;
}

static inline u32 tcf_pedit_offset(const struct tc_action *a, int index)
{
return to_pedit(a)->tcfp_keys[index].off;
struct tcf_pedit_parms *parms;
u32 off;

rcu_read_lock();
parms = to_pedit_parms(a);
off = parms->tcfp_keys[index].off;
rcu_read_unlock();

return off;
}
#endif /* __NET_TC_PED_H */
1 change: 1 addition & 0 deletions include/uapi/linux/pkt_cls.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ enum {
__TCA_ACT_MAX
};

/* See other TCA_ACT_FLAGS_ * flags in include/net/act_api.h. */
#define TCA_ACT_FLAGS_NO_PERCPU_STATS 1 /* Don't use percpu allocator for
* actions stats.
*/
Expand Down
61 changes: 31 additions & 30 deletions net/sched/act_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -500,7 +500,7 @@ int tcf_idr_create(struct tc_action_net *tn, u32 index, struct nlattr *est,
p->tcfa_tm.install = jiffies;
p->tcfa_tm.lastuse = jiffies;
p->tcfa_tm.firstuse = 0;
p->tcfa_flags = flags;
p->tcfa_flags = flags & TCA_ACT_FLAGS_USER_MASK;
if (est) {
err = gen_new_estimator(&p->tcfa_bstats, p->cpu_bstats,
&p->tcfa_rate_est,
Expand Down Expand Up @@ -949,7 +949,7 @@ void tcf_idr_insert_many(struct tc_action *actions[])
}
}

struct tc_action_ops *tc_action_load_ops(char *name, struct nlattr *nla,
struct tc_action_ops *tc_action_load_ops(struct nlattr *nla, bool police,
bool rtnl_held,
struct netlink_ext_ack *extack)
{
Expand All @@ -959,7 +959,7 @@ struct tc_action_ops *tc_action_load_ops(char *name, struct nlattr *nla,
struct nlattr *kind;
int err;

if (name == NULL) {
if (!police) {
err = nla_parse_nested_deprecated(tb, TCA_ACT_MAX, nla,
tcf_action_policy, extack);
if (err < 0)
Expand All @@ -975,7 +975,7 @@ struct tc_action_ops *tc_action_load_ops(char *name, struct nlattr *nla,
return ERR_PTR(err);
}
} else {
if (strlcpy(act_name, name, IFNAMSIZ) >= IFNAMSIZ) {
if (strlcpy(act_name, "police", IFNAMSIZ) >= IFNAMSIZ) {
NL_SET_ERR_MSG(extack, "TC action name too long");
return ERR_PTR(-EINVAL);
}
Expand Down Expand Up @@ -1012,20 +1012,19 @@ struct tc_action_ops *tc_action_load_ops(char *name, struct nlattr *nla,

struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
struct nlattr *nla, struct nlattr *est,
char *name, int ovr, int bind,
struct tc_action_ops *a_o, int *init_res,
bool rtnl_held,
struct netlink_ext_ack *extack)
u32 flags, struct netlink_ext_ack *extack)
{
struct nla_bitfield32 flags = { 0, 0 };
bool police = flags & TCA_ACT_FLAGS_POLICE;
struct nla_bitfield32 userflags = { 0, 0 };
u8 hw_stats = TCA_ACT_HW_STATS_ANY;
struct nlattr *tb[TCA_ACT_MAX + 1];
struct tc_cookie *cookie = NULL;
struct tc_action *a;
int err;

/* backward compatibility for policer */
if (name == NULL) {
if (!police) {
err = nla_parse_nested_deprecated(tb, TCA_ACT_MAX, nla,
tcf_action_policy, extack);
if (err < 0)
Expand All @@ -1040,22 +1039,22 @@ struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
}
hw_stats = tcf_action_hw_stats_get(tb[TCA_ACT_HW_STATS]);
if (tb[TCA_ACT_FLAGS])
flags = nla_get_bitfield32(tb[TCA_ACT_FLAGS]);
userflags = nla_get_bitfield32(tb[TCA_ACT_FLAGS]);

err = a_o->init(net, tb[TCA_ACT_OPTIONS], est, &a, ovr, bind,
rtnl_held, tp, flags.value, extack);
err = a_o->init(net, tb[TCA_ACT_OPTIONS], est, &a, tp,
userflags.value | flags, extack);
} else {
err = a_o->init(net, nla, est, &a, ovr, bind, rtnl_held,
tp, flags.value, extack);
err = a_o->init(net, nla, est, &a, tp, userflags.value | flags,
extack);
}
if (err < 0)
goto err_out;
*init_res = err;

if (!name && tb[TCA_ACT_COOKIE])
if (!police && tb[TCA_ACT_COOKIE])
tcf_set_action_cookie(&a->act_cookie, cookie);

if (!name)
if (!police)
a->hw_stats = hw_stats;

return a;
Expand All @@ -1071,9 +1070,9 @@ struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
/* Returns numbers of initialized actions or negative error. */

int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla,
struct nlattr *est, char *name, int ovr, int bind,
struct tc_action *actions[], int init_res[], size_t *attr_size,
bool rtnl_held, struct netlink_ext_ack *extack)
struct nlattr *est, struct tc_action *actions[],
int init_res[], size_t *attr_size, u32 flags,
struct netlink_ext_ack *extack)
{
struct tc_action_ops *ops[TCA_ACT_MAX_PRIO] = {};
struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
Expand All @@ -1090,7 +1089,9 @@ int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla,
for (i = 1; i <= TCA_ACT_MAX_PRIO && tb[i]; i++) {
struct tc_action_ops *a_o;

a_o = tc_action_load_ops(name, tb[i], rtnl_held, extack);
a_o = tc_action_load_ops(tb[i], flags & TCA_ACT_FLAGS_POLICE,
!(flags & TCA_ACT_FLAGS_NO_RTNL),
extack);
if (IS_ERR(a_o)) {
err = PTR_ERR(a_o);
goto err_mod;
Expand All @@ -1099,9 +1100,8 @@ int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla,
}

for (i = 1; i <= TCA_ACT_MAX_PRIO && tb[i]; i++) {
act = tcf_action_init_1(net, tp, tb[i], est, name, ovr, bind,
ops[i - 1], &init_res[i - 1], rtnl_held,
extack);
act = tcf_action_init_1(net, tp, tb[i], est, ops[i - 1],
&init_res[i - 1], flags, extack);
if (IS_ERR(act)) {
err = PTR_ERR(act);
goto err;
Expand All @@ -1121,7 +1121,7 @@ int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla,
goto err_mod;

err:
tcf_action_destroy(actions, bind);
tcf_action_destroy(actions, flags & TCA_ACT_FLAGS_BIND);
err_mod:
for (i = 0; i < TCA_ACT_MAX_PRIO; i++) {
if (ops[i])
Expand Down Expand Up @@ -1511,7 +1511,7 @@ tcf_add_notify(struct net *net, struct nlmsghdr *n, struct tc_action *actions[],
}

static int tcf_action_add(struct net *net, struct nlattr *nla,
struct nlmsghdr *n, u32 portid, int ovr,
struct nlmsghdr *n, u32 portid, u32 flags,
struct netlink_ext_ack *extack)
{
size_t attr_size = 0;
Expand All @@ -1520,8 +1520,8 @@ static int tcf_action_add(struct net *net, struct nlattr *nla,
int init_res[TCA_ACT_MAX_PRIO] = {};

for (loop = 0; loop < 10; loop++) {
ret = tcf_action_init(net, NULL, nla, NULL, NULL, ovr, 0,
actions, init_res, &attr_size, true, extack);
ret = tcf_action_init(net, NULL, nla, NULL, actions, init_res,
&attr_size, flags, extack);
if (ret != -EAGAIN)
break;
}
Expand Down Expand Up @@ -1552,7 +1552,8 @@ static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n,
struct net *net = sock_net(skb->sk);
struct nlattr *tca[TCA_ROOT_MAX + 1];
u32 portid = NETLINK_CB(skb).portid;
int ret = 0, ovr = 0;
u32 flags = 0;
int ret = 0;

if ((n->nlmsg_type != RTM_GETACTION) &&
!netlink_capable(skb, CAP_NET_ADMIN))
Expand All @@ -1578,8 +1579,8 @@ static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n,
* is zero) then just set this
*/
if (n->nlmsg_flags & NLM_F_REPLACE)
ovr = 1;
ret = tcf_action_add(net, tca[TCA_ACT_TAB], n, portid, ovr,
flags = TCA_ACT_FLAGS_REPLACE;
ret = tcf_action_add(net, tca[TCA_ACT_TAB], n, portid, flags,
extack);
break;
case RTM_DELACTION:
Expand Down
Loading
Loading