diff --git a/include/net/act_api.h b/include/net/act_api.h index b18c699681ca..ec52b28ddfc5 100644 --- a/include/net/act_api.h +++ b/include/net/act_api.h @@ -93,7 +93,8 @@ struct tc_action_ops { 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, + int bind, bool rtnl_held, struct nla_bitfield32 *rf, + struct tcf_proto *tp, struct netlink_ext_ack *extack); int (*walk)(struct net *, struct sk_buff *, struct netlink_callback *, int, @@ -176,10 +177,12 @@ int tcf_action_exec(struct sk_buff *skb, struct tc_action **actions, 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[], size_t *attr_size, - bool rtnl_held, struct netlink_ext_ack *extack); + bool rtnl_held, struct nla_bitfield32 *root_flags, + 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 nla_bitfield32 *root_flags, bool rtnl_held, struct netlink_ext_ack *extack); int tcf_action_dump(struct sk_buff *skb, struct tc_action *actions[], int bind, diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h index a6aa466fac9e..d92f3d0f2c79 100644 --- a/include/uapi/linux/pkt_cls.h +++ b/include/uapi/linux/pkt_cls.h @@ -16,6 +16,7 @@ enum { TCA_ACT_STATS, TCA_ACT_PAD, TCA_ACT_COOKIE, + TCA_ACT_ROOT_FLAGS, __TCA_ACT_MAX }; diff --git a/net/sched/act_api.c b/net/sched/act_api.c index 69d4676a402f..ef7b0bb735c7 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -842,6 +842,7 @@ static const struct nla_policy tcf_action_policy[TCA_ACT_MAX + 1] = { 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 nla_bitfield32 *root_flags, bool rtnl_held, struct netlink_ext_ack *extack) { @@ -852,6 +853,7 @@ struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp, struct nlattr *tb[TCA_ACT_MAX + 1]; struct nlattr *kind; int err; + struct nla_bitfield32 rf = {0, 0}; if (name == NULL) { err = nla_parse_nested_deprecated(tb, TCA_ACT_MAX, nla, @@ -884,6 +886,10 @@ struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp, } } + if (!root_flags && tb[TCA_ACT_ROOT_FLAGS]) { + rf = nla_get_bitfield32(tb[TCA_ACT_ROOT_FLAGS]); + root_flags = &rf; + } a_o = tc_lookup_action_n(act_name); if (a_o == NULL) { #ifdef CONFIG_MODULES @@ -914,10 +920,10 @@ struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp, /* backward compatibility for policer */ if (name == NULL) err = a_o->init(net, tb[TCA_ACT_OPTIONS], est, &a, ovr, bind, - rtnl_held, tp, extack); + rtnl_held, root_flags, tp, extack); else err = a_o->init(net, nla, est, &a, ovr, bind, rtnl_held, - tp, extack); + root_flags, tp, extack); if (err < 0) goto err_mod; @@ -955,7 +961,8 @@ struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp, 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[], size_t *attr_size, - bool rtnl_held, struct netlink_ext_ack *extack) + bool rtnl_held, struct nla_bitfield32 *root_flags, + struct netlink_ext_ack *extack) { struct nlattr *tb[TCA_ACT_MAX_PRIO + 1]; struct tc_action *act; @@ -970,7 +977,7 @@ 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, - rtnl_held, extack); + root_flags, rtnl_held, extack); if (IS_ERR(act)) { err = PTR_ERR(act); goto err; @@ -1350,6 +1357,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 nla_bitfield32 *root_flags, struct netlink_ext_ack *extack) { size_t attr_size = 0; @@ -1358,7 +1366,8 @@ static int tcf_action_add(struct net *net, struct nlattr *nla, for (loop = 0; loop < 10; loop++) { ret = tcf_action_init(net, NULL, nla, NULL, NULL, ovr, 0, - actions, &attr_size, true, extack); + actions, &attr_size, true, root_flags, + extack); if (ret != -EAGAIN) break; } @@ -1385,6 +1394,7 @@ 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 = skb ? NETLINK_CB(skb).portid : 0; + struct nla_bitfield32 root_flags = {0, 0}; int ret = 0, ovr = 0; if ((n->nlmsg_type != RTM_GETACTION) && @@ -1412,8 +1422,11 @@ static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n, */ if (n->nlmsg_flags & NLM_F_REPLACE) ovr = 1; + if (tb[TCA_ROOT_FLAGS]) + root_flags = nla_get_bitfield32(tb[TCA_ROOT_FLAGS]); + ret = tcf_action_add(net, tca[TCA_ACT_TAB], n, portid, ovr, - extack); + &root_flags, extack); break; case RTM_DELACTION: ret = tca_action_gd(net, tca[TCA_ACT_TAB], n, diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 8717c0b26c90..9dc5bf0d637e 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -2946,7 +2946,7 @@ int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb, act = tcf_action_init_1(net, tp, tb[exts->police], rate_tlv, "police", ovr, TCA_ACT_BIND, rtnl_held, - extack); + NULL, extack); if (IS_ERR(act)) return PTR_ERR(act); @@ -2959,7 +2959,7 @@ int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb, err = tcf_action_init(net, tp, tb[exts->action], rate_tlv, NULL, ovr, TCA_ACT_BIND, exts->actions, &attr_size, - rtnl_held, extack); + rtnl_held, NULL, extack); if (err < 0) return err; exts->nr_actions = err;