From: Miroslav Zagorac Date: Fri, 16 Oct 2026 19:32:49 +0000 (+0200) Subject: MINOR: filters: initialize the filter classes before the register stage X-Git-Tag: v3.5-dev10~119 X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=8a32f6c6216fda4016f96936ff2846b82d84a31c;p=haproxy.git MINOR: filters: initialize the filter classes before the register stage The filter classes of HAProxy are initialized from the register stage, where the internal classes are registered too. A module registering its own class from that stage is refused, since whether it runs before or after this initialization depends on the link order, and the objects of an addon are linked first: its classes are registered too early, always. Initializing the classes from the prepare stage leaves the whole register stage to the modules, which then register their classes in time for "haproxy -vv" to report them, the filter classes being listed while the arguments are parsed, between the register and the init stages. Nothing else moves: the classes are initialized in the same order, and the placement of a class still decides the evaluation order of the filters. The filter documentation was updated to match. --- diff --git a/doc/configuration.txt b/doc/configuration.txt index 2f047285d..e79376453 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -31514,7 +31514,8 @@ reading. Their sole purpose is to explain how to decipher them. Here are listed officially supported filters with the list of parameters they accept. Depending on compile options, some of these filters might be -unavailable. The list of available filter classes is reported in haproxy -vv. +unavailable. The list of available filter classes, including the ones added by +the addons built into the binary, is reported in haproxy -vv. A filter is declared on a proxy in one of two modes: diff --git a/doc/internals/api/filters.txt b/doc/internals/api/filters.txt index d52f414cf..55522b7e4 100644 --- a/doc/internals/api/filters.txt +++ b/doc/internals/api/filters.txt @@ -149,7 +149,9 @@ Note that additional parameters on the filter line must be parsed by the filter itself. The "filter" directive is only supported by filters registering a keyword with flt_register_keywords() (see section 3.2.2). -The list of available filter classes is reported by 'haproxy -vv' : +The list of available filter classes is reported by 'haproxy -vv'. It contains +the built-in classes and the ones other modules register from the STG_REGISTER +stage (see section 3.2) : $> haproxy -vv HAProxy version 1.7-dev2-3a1d4a-33 2016/03/21 @@ -547,7 +549,7 @@ it supports, relative to an already placed class, with filter_place_class() : return -1; return 0; } - INITCALL1(STG_INIT, my_filter_register_class); + INITCALL0(STG_REGISTER, my_filter_register_class); filter_place_class() accepts the three sides, FLT_SIDE_GLOBAL, FLT_SIDE_REQ and FLT_SIDE_RES, and may be called once per side : @@ -575,9 +577,14 @@ startup because it would be useless. The placements define the default evaluation order of the instances of the class relative to the other classes, which may then be refined per proxy with "filter-sequence" (section 2.2). -WARNING : filter_register_class() must be called after the built-in classes - were initialized, so from an initcall of the STG_INIT stage or a later - one. Otherwise the class registration fails. +WARNING : filter_register_class() and filter_place_class() must be called after + the built-in classes were initialized at the STG_PREPARE stage. Call + them from an STG_REGISTER initcall. From STG_PREPARE, the result + depends on the link order, and an addon is linked first, so its + registration always fails. 'haproxy -vv' is handled right after the + STG_REGISTER stage and only lists the classes registered so far. A + class registered from a later stage still works and is listed by the + "show filter classes" CLI command, but not by 'haproxy -vv'. Then the filter internal configuration must be defined. For instance : @@ -1717,9 +1724,10 @@ are left untouched. directive uses the keyword name. 2. Register the class and place it on each side it supports, relative to an - already placed class. For a filter maintained out of the HAProxy tree, - use the public API from an initcall, because the registration must happen - after the built-in classes were initialized : + already placed class. For a filter maintained out of the HAProxy tree, use + the public API from an STG_REGISTER initcall. The built-in classes are + initialized before this stage, and 'haproxy -vv' only lists the classes + registered by its end (see section 3.2) : static int my_filter_register_class(void) { @@ -1736,7 +1744,7 @@ are left untouched. return -1; return 0; } - INITCALL1(STG_INIT, my_filter_register_class); + INITCALL0(STG_REGISTER, my_filter_register_class); filter_register_class_full() registers the class and places it at the same position on both sides in a single call, which is enough for most @@ -1868,11 +1876,12 @@ enabled by another directive, or is referenced by other directives. only drives the side-independent operations (configuration checks, initialization and destruction). - * A class must be registered after the built-in classes were initialized, - from a STG_INIT initcall or a later stage, otherwise the registration - fails. For a filter inside the HAProxy tree, the class is registered in - filter_init_classes() to explicitly define its default order with the - other internal classes. + * A class must be registered after the built-in classes were initialized, from + a STG_REGISTER initcall. From STG_PREPARE, the registration fails or + succeeds depending on the link order. A class registered after STG_REGISTER + works, but 'haproxy -vv' does not list it. For a filter inside the HAProxy + tree, the class is registered in filter_init_classes() to explicitly define + its default order with the other internal classes. * The instance id is optional for a class that does not set FLT_CLS_FL_MULTI: the parse callback may receive a NULL 'inst->id'. A diff --git a/src/filters.c b/src/filters.c index ab1184b3d..ba5d1ae9f 100644 --- a/src/filters.c +++ b/src/filters.c @@ -3510,7 +3510,10 @@ int flt_parse_instance_legacy(struct proxy *px, struct filter_instance *inst, ch * not support the "filter-config" directive). The class is initialized and * added to the global registry of the known classes, and appended at the end * of the global order. It is not usable on any channel side until placed with - * filter_place_class(). Must be called after filter_init_classes(). + * filter_place_class(). Must be called after filter_init_classes(), which + * runs at the prepare stage: a class registered from the register stage on + * is added in time for "haproxy -vv" to list it, a class registered later + * is reported by the CLI alone. * Returns 0 on success, -1 on error (too early call, duplicate name). */ int filter_register_class(struct filter_class *cls, const char *name, @@ -3662,7 +3665,10 @@ int filter_register_class_full(struct filter_class *cls, const char *name, /* Init function responsible to initialize all intenral filter classes and to * insert them is global list above. The default evaluation order of all - * internal filters is defined in this function. + * internal filters is defined in this function. It runs from the prepare stage + * so that a class registered by another module from the register stage is + * initialized in time: "haproxy -vv" reports the available filter classes from + * the argument parsing, which happens between the two. * * Exemple to register a new filter class: * @@ -3683,7 +3689,7 @@ int filter_register_class_full(struct filter_class *cls, const char *name, * return -1; * return 0; * } - * INITCALL1(STG_INIT, myfilter_register_class); + * INITCALL1(STG_REGISTER, myfilter_register_class); */ static void filter_init_classes(void) { @@ -3794,7 +3800,7 @@ REGISTER_POST_CHECK(flt_init_all); REGISTER_PER_THREAD_INIT(flt_init_all_per_thread); REGISTER_PER_THREAD_DEINIT(flt_deinit_all_per_thread); -INITCALL0(STG_REGISTER, filter_init_classes); +INITCALL0(STG_PREPARE, filter_init_classes); /* * Local variables: