On Thu, Apr 10, 2025 at 4:13 AM Mark Michelson via dev < ovs-dev@openvswitch.org> wrote:
> In current OVN, an engine_node has two function callbacks that are > optional, is_valid() and clear_tracked_data(). There are individual > macros that allow for each of these optional functions to be defined in > the engine_node. With two optional callbacks, this means there are four > possible macros: > > - vanilla engine node (no is_valid(), no clear_tracked_data()) > - has clear_tracked_data(), does not have is_valid() > - has is_valid(), does not have clear_tracked_data() > - has both is_valid() and clear_tracked_data() > > In OVN we have bespoke macros for the first, second, and fourth > scenarios [1]. > > The main issues with this are: > - This does not scale well if engine_nodes need new optional callbacks. > - The macro names are quite long. > > This patch offers a new alternative. It alters the ENGINE_NODE macro so > that it can take a variable number of arguments. Some preprocessor magic > uses the number of arguments passed in to call a specific variant > (ENGINE_NODE2, ENGINE_NODE3, or ENGINE_NODE4 currently, > since these are the possible number of inputs to ENGINE_NODE). Depending > on the variant called, additional optional elements of the resulting > engine_node can be set. Convenience macros are provided for the two > optional callbacks. > > Under the hood, there's a lot going on. But from the engine node > developer's perspective, it's much easier to declare engine nodes, since > there is only one macro to declare an engine node, and its arguments > help define which optional callbacks are defined. > > [1] There is one engine_node (acl_id) that falls into the third > scenario but rather than use a custom macro, it just defines its > is_valid() callback after the initial engine_node definition. > > Signed-off-by: Mark Michelson <mmich...@redhat.com> > --- > controller/ovn-controller.c | 22 ++++++++++----------- > lib/inc-proc-eng.h | 38 +++++++++++++++++++++++-------------- > lib/ovn-util.h | 36 +++++++++++++++++++++++++++++++++++ > northd/inc-proc-northd.c | 20 +++++++++---------- > 4 files changed, 80 insertions(+), 36 deletions(-) > > diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c > index 440c76ca1..80e6b2b3f 100644 > --- a/controller/ovn-controller.c > +++ b/controller/ovn-controller.c > @@ -5598,30 +5598,28 @@ main(int argc, char *argv[]) > > /* Define inc-proc-engine nodes. */ > ENGINE_NODE(sb_ro, "sb_ro"); > - ENGINE_NODE_WITH_CLEAR_TRACK_DATA(template_vars, "template_vars"); > - ENGINE_NODE_WITH_CLEAR_TRACK_DATA_IS_VALID(ct_zones, "ct_zones"); > - ENGINE_NODE_WITH_CLEAR_TRACK_DATA(ovs_interface_shadow, > - "ovs_interface_shadow"); > - ENGINE_NODE_WITH_CLEAR_TRACK_DATA(runtime_data, "runtime_data"); > + ENGINE_NODE(template_vars, "template_vars", CLEAR_TRACKED_DATA); > + ENGINE_NODE(ct_zones, "ct_zones", CLEAR_TRACKED_DATA, IS_VALID); > + ENGINE_NODE(ovs_interface_shadow, "ovs_interface_shadow", > CLEAR_TRACKED_DATA); > + ENGINE_NODE(runtime_data, "runtime_data", CLEAR_TRACKED_DATA); > ENGINE_NODE(non_vif_data, "non_vif_data"); > ENGINE_NODE(mff_ovn_geneve, "mff_ovn_geneve"); > ENGINE_NODE(ofctrl_is_connected, "ofctrl_is_connected"); > - ENGINE_NODE_WITH_CLEAR_TRACK_DATA(activated_ports, "activated_ports"); > + ENGINE_NODE(activated_ports, "activated_ports", CLEAR_TRACKED_DATA); > ENGINE_NODE(postponed_ports, "postponed_ports"); > ENGINE_NODE(pflow_output, "physical_flow_output"); > - ENGINE_NODE_WITH_CLEAR_TRACK_DATA(lflow_output, > "logical_flow_output"); > + ENGINE_NODE(lflow_output, "logical_flow_output", CLEAR_TRACKED_DATA); > ENGINE_NODE(controller_output, "controller_output"); > - ENGINE_NODE_WITH_CLEAR_TRACK_DATA(addr_sets, "addr_sets"); > - ENGINE_NODE_WITH_CLEAR_TRACK_DATA(port_groups, "port_groups"); > + ENGINE_NODE(addr_sets, "addr_sets", CLEAR_TRACKED_DATA); > + ENGINE_NODE(port_groups, "port_groups", CLEAR_TRACKED_DATA); > ENGINE_NODE(northd_options, "northd_options"); > ENGINE_NODE(dhcp_options, "dhcp_options"); > ENGINE_NODE(if_status_mgr, "if_status_mgr"); > - ENGINE_NODE_WITH_CLEAR_TRACK_DATA(lb_data, "lb_data"); > + ENGINE_NODE(lb_data, "lb_data", CLEAR_TRACKED_DATA); > ENGINE_NODE(mac_cache, "mac_cache"); > ENGINE_NODE(bfd_chassis, "bfd_chassis"); > ENGINE_NODE(dns_cache, "dns_cache"); > - ENGINE_NODE(acl_id, "acl_id"); > - en_acl_id.is_valid = en_acl_id_is_valid; > + ENGINE_NODE(acl_id, "acl_id", IS_VALID); > ENGINE_NODE(route, "route"); > ENGINE_NODE(route_table_notify, "route_table_notify"); > ENGINE_NODE(route_exchange, "route_exchange"); > diff --git a/lib/inc-proc-eng.h b/lib/inc-proc-eng.h > index 12e232020..e4c71d773 100644 > --- a/lib/inc-proc-eng.h > +++ b/lib/inc-proc-eng.h > @@ -397,29 +397,39 @@ engine_noop_handler(struct engine_node *node > OVS_UNUSED, void *data OVS_UNUSED) > void engine_ovsdb_node_add_index(struct engine_node *, const char *name, > struct ovsdb_idl_index *); > > -/* Macro to define an engine node. */ > -#define ENGINE_NODE_DEF(NAME, NAME_STR, CLEAR_TRACKED_DATA, IS_VALID) \ > +#define ENGINE_NODE_DEF_START(NAME, NAME_STR) \ > struct engine_node en_##NAME = { \ > .name = NAME_STR, \ > .data = NULL, \ > .state = EN_STALE, \ > .init = en_##NAME##_init, \ > .run = en_##NAME##_run, \ > - .cleanup = en_##NAME##_cleanup, \ > - .is_valid = IS_VALID, \ > - .clear_tracked_data = CLEAR_TRACKED_DATA, \ > - }; > + .cleanup = en_##NAME##_cleanup, > > -#define ENGINE_NODE(NAME, NAME_STR) \ > - ENGINE_NODE_DEF(NAME, NAME_STR, NULL, NULL) > +#define ENGINE_NODE_DEF_END }; > > -#define ENGINE_NODE_WITH_CLEAR_TRACK_DATA(NAME, NAME_STR) \ > - ENGINE_NODE_DEF(NAME, NAME_STR, en_##NAME##_clear_tracked_data, NULL) > +#define ENGINE_NODE2(NAME, NAME_STR) \ > + ENGINE_NODE_DEF_START(NAME, NAME_STR) \ > + ENGINE_NODE_DEF_END > > -#define ENGINE_NODE_WITH_CLEAR_TRACK_DATA_IS_VALID(NAME, NAME_STR) \ > - ENGINE_NODE_DEF(NAME, NAME_STR, \ > - en_##NAME##_clear_tracked_data, \ > - en_##NAME##_is_valid) > +#define CLEAR_TRACKED_DATA(NAME) \ > + .clear_tracked_data = en_##NAME##_clear_tracked_data > + > +#define IS_VALID(NAME) \ > + .is_valid = en_##NAME##_is_valid > + > +#define ENGINE_NODE3(NAME, NAME_STR, ARG1) \ > + ENGINE_NODE_DEF_START(NAME, #NAME) \ > + ARG1(NAME), \ > + ENGINE_NODE_DEF_END > + > +#define ENGINE_NODE4(NAME, NAME_STR, ARG1, ARG2) \ > + ENGINE_NODE_DEF_START(NAME, #NAME) \ > + ARG1(NAME), \ > + ARG2(NAME), \ > + ENGINE_NODE_DEF_END > + > +#define ENGINE_NODE(...) VFUNC(ENGINE_NODE, __VA_ARGS__) > > /* Macro to define member functions of an engine node which represents > * a table of OVSDB */ > diff --git a/lib/ovn-util.h b/lib/ovn-util.h > index 0fff9b463..de15757a9 100644 > --- a/lib/ovn-util.h > +++ b/lib/ovn-util.h > @@ -496,4 +496,40 @@ const struct sbrec_port_binding *lport_lookup_by_name( > struct ovsdb_idl_index *sbrec_port_binding_by_name, > const char *name); > > +/* __NARG__ provides a way to count the number of arguments passed to a > + * variadic macro. As defined below, it's capable of counting up to > + * 16 arguments. This should be more than enough for our purposes. However > + * the __ARG_N and __RSEQ_N macros can be updated to include more numbers > + * if we wish to be able to count higher. > + * */ > +#define __NARG__(...) __NARG_I_(__VA_ARGS__,__RSEQ_N()) > +#define __NARG_I_(...) __ARG_N(__VA_ARGS__) > +#define __ARG_N( \ > + _1, _2, _3, _4, _5, _6, _7, _8, _9, \ > + _10, _11, _12, _13, _14, _15, _16, N,...) N > +#define __RSEQ_N() \ > + 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 > + > +/* VFUNC provides a way to overload macros so that they can > + * accept a variable number of arguments. > + * > + * It works by using __NARG__ to count the number of arguments > + * that were passed into the macro. Then this is concatenated > + * to the end of the macro name. Then this concatenated macro > + * is called. > + * > + * As an example, let's say we have > + * # define FOO(...) VFUNC(FOO, __VA_ARGS) > + * > + * Then if a caller were to call FOO(bar) > + * then we would count one argument (bar), concatenate > + * the 1 to the end of FOO, and end up calling FOO1(bar). > + * > + * If a caller were to call FOO(bar, baz), then the > + * result would be to call FOO2(bar, baz). > + */ > +#define _VFUNC_(name, n) name##n > +#define _VFUNC(name, n) _VFUNC_(name, n) > +#define VFUNC(func, ...) _VFUNC(func, __NARG__(__VA_ARGS__)) (__VA_ARGS__) > + > #endif /* OVN_UTIL_H */ > diff --git a/northd/inc-proc-northd.c b/northd/inc-proc-northd.c > index 7f92c0cb7..823593e7e 100644 > --- a/northd/inc-proc-northd.c > +++ b/northd/inc-proc-northd.c > @@ -147,7 +147,7 @@ enum sb_engine_node { > > /* Define engine nodes for other nodes. They should be defined as static > to > * avoid sparse errors. */ > -static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(northd, "northd"); > +static ENGINE_NODE(northd, "northd", CLEAR_TRACKED_DATA); > static ENGINE_NODE(sync_from_sb, "sync_from_sb"); > static ENGINE_NODE(sampling_app, "sampling_app"); > static ENGINE_NODE(lflow, "lflow"); > @@ -157,16 +157,16 @@ static ENGINE_NODE(northd_output, "northd_output"); > static ENGINE_NODE(sync_meters, "sync_meters"); > static ENGINE_NODE(sync_to_sb, "sync_to_sb"); > static ENGINE_NODE(sync_to_sb_addr_set, "sync_to_sb_addr_set"); > -static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(port_group, "port_group"); > +static ENGINE_NODE(port_group, "port_group", CLEAR_TRACKED_DATA); > static ENGINE_NODE(fdb_aging, "fdb_aging"); > static ENGINE_NODE(fdb_aging_waker, "fdb_aging_waker"); > static ENGINE_NODE(sync_to_sb_lb, "sync_to_sb_lb"); > static ENGINE_NODE(sync_to_sb_pb, "sync_to_sb_pb"); > -static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(global_config, "global_config"); > -static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(lb_data, "lb_data"); > -static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(lr_nat, "lr_nat"); > -static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(lr_stateful, "lr_stateful"); > -static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(ls_stateful, "ls_stateful"); > +static ENGINE_NODE(global_config, "global_config", CLEAR_TRACKED_DATA); > +static ENGINE_NODE(lb_data, "lb_data", CLEAR_TRACKED_DATA); > +static ENGINE_NODE(lr_nat, "lr_nat", CLEAR_TRACKED_DATA); > +static ENGINE_NODE(lr_stateful, "lr_stateful", CLEAR_TRACKED_DATA); > +static ENGINE_NODE(ls_stateful, "ls_stateful", CLEAR_TRACKED_DATA); > static ENGINE_NODE(route_policies, "route_policies"); > static ENGINE_NODE(routes, "routes"); > static ENGINE_NODE(bfd, "bfd"); > @@ -175,10 +175,10 @@ static ENGINE_NODE(ecmp_nexthop, "ecmp_nexthop"); > static ENGINE_NODE(multicast_igmp, "multicast_igmp"); > static ENGINE_NODE(acl_id, "acl_id"); > static ENGINE_NODE(advertised_route_sync, "advertised_route_sync"); > -static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(learned_route_sync, > - "learned_route_sync"); > +static ENGINE_NODE(learned_route_sync, "learned_route_sync", > + CLEAR_TRACKED_DATA); > static ENGINE_NODE(dynamic_routes, "dynamic_routes"); > -static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(group_ecmp_route, > "group_ecmp_route"); > +static ENGINE_NODE(group_ecmp_route, "group_ecmp_route", > CLEAR_TRACKED_DATA); > > void inc_proc_northd_init(struct ovsdb_idl_loop *nb, > struct ovsdb_idl_loop *sb) > -- > 2.47.0 > > _______________________________________________ > dev mailing list > d...@openvswitch.org > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > > With the checkpatch warning fixed: Acked-by: Ales Musil <amu...@redhat.com> Thanks, Ales _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev