@@ -109,6 +109,7 @@ struct tc_action_ops {
char kind[ACTNAMSIZ];
enum tca_id id; /* identifier should match kind */
unsigned int net_id;
+ refcount_t dyn_ref;
size_t size;
struct module *owner;
int (*act)(struct sk_buff *, const struct tc_action *,
@@ -120,6 +121,11 @@ struct tc_action_ops {
struct nlattr *est, struct tc_action **act,
struct tcf_proto *tp,
u32 flags, struct netlink_ext_ack *extack);
+ /* This should be merged with the original init action */
+ int (*init_ops)(struct net *net, struct nlattr *nla,
+ struct nlattr *est, struct tc_action **act,
+ struct tcf_proto *tp, struct tc_action_ops *ops,
+ u32 flags, struct netlink_ext_ack *extack);
int (*walk)(struct net *, struct sk_buff *,
struct netlink_callback *, int,
const struct tc_action_ops *,
@@ -1023,7 +1023,7 @@ int tcf_register_action(struct tc_action_ops *act,
struct tc_action_ops *a;
int ret;
- if (!act->act || !act->dump || !act->init)
+ if (!act->act || !act->dump || (!act->init && !act->init_ops))
return -EINVAL;
/* We have to register pernet ops before making the action ops visible,
@@ -1484,8 +1484,16 @@ struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
}
}
- err = a_o->init(net, tb[TCA_ACT_OPTIONS], est, &a, tp,
- userflags.value | flags, extack);
+ /* When we arrive here we guarantee that a_o->init or
+ * a_o->init_ops exist.
+ */
+ if (a_o->init)
+ err = a_o->init(net, tb[TCA_ACT_OPTIONS], est, &a, tp,
+ userflags.value | flags, extack);
+ else
+ err = a_o->init_ops(net, tb[TCA_ACT_OPTIONS], est, &a,
+ tp, a_o, userflags.value | flags,
+ extack);
} else {
err = a_o->init(net, nla, est, &a, tp, userflags.value | flags,
extack);