@@ -120,6 +120,12 @@ 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,
+ const 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 *,
@@ -1044,7 +1044,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,
@@ -1517,8 +1517,17 @@ 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,
+ (const struct tc_action_ops *)a_o,
+ userflags.value | flags, extack);
} else {
err = a_o->init(net, nla, est, &a, tp, userflags.value | flags,
extack);