From: Christopher Faulet Date: Thu, 15 Oct 2026 07:04:14 +0000 (+0200) Subject: MINOR: filters: Support the global side in filter_place_class() X-Git-Tag: v3.5-dev10~163 X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=853b5c1a6aaeef2fcec0fcf9476a763714176e81;p=haproxy.git MINOR: filters: Support the global side in filter_place_class() The filter classes are anchored in three independent orders: the global one, which drives the side-independent operations (configuration checks, initialization and destruction), and the request and response ones, which drive the stream evaluation order. Until now the global order could only follow the class registration order, filter_place_class() only accepted FLT_SIDE_REQ and FLT_SIDE_RES, and the per-side anchors were two anonymous inline structs, which made the global order impossible to refine and the placement code side-specific. The three orders now share a common anchor type, struct filter_class_side, holding the before/after constraint lists, the link in the order list and a placed flag. The class registry (filter_class.list) stays a flat list in registration order, used by filter_find_class() and "haproxy -vv", while the global order is a new distinct list, global_filter_classes, rooted in filter_class.global.list. As for the channel sides, the global order is a placement tree: a registered class is appended at the end of it, and filter_place_class() re-parents it relative to another class. filter_place_class() now accepts FLT_SIDE_GLOBAL. Any registered class may be used as a reference on that side, since the global order contains all of them, whereas a channel side still requires the reference class to be placed on that same side. Moving a class in the global order does not change its request or response positions, and the three placements remain independent. Two new errors are reported: a class cannot be placed relative to itself, and a class cannot be placed twice on the same side. filter_register_class_full() places the class on the global side as well, so the helper keeps placing the class symmetrically in every order. Its error path now detaches the class from all its orders, through the new flt_unplace_class() helper, instead of only unlinking it from the registry. The default order of the internal classes does not change: the same classes are appended to the global order, which is required for the global class references to be created at proxy initialization. This only makes the global order refinable by modules and lifts the last asymmetry between the three orders. The documentation is updated accordingly, in both the configuration manual and the internals guide, together with the example in the comment of filter_init_classes(). --- diff --git a/doc/configuration.txt b/doc/configuration.txt index 055ee2813..d62059922 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -31523,6 +31523,16 @@ A filter is declared on a proxy in one of two modes: "filter-sequence" directive. The instances are disabled by default and are activated with the "enabled" token or the "filter-enable" directive. +Each filter class is placed in three independent orders: a global one, used +for the side-independent operations (configuration checks, initialization and +destruction), and a request and a response one, used for the evaluation order +of the instances on the corresponding channel. The request and the response +orders are independent, so a class may be evaluated at a different position +depending on the direction, and the global order may be changed without +affecting them. The resulting orders of a proxy may be inspected with the +"show filter classes" CLI command, and the "show filter instances" one reports +the resulting order of the instances. + The mode is selected by the configuration itself: as soon as a legacy "filter" directive is used in a proxy, the proxy works in legacy mode and the "filter-*" directives must not be used in the same proxy, including when they diff --git a/doc/internals/api/filters.txt b/doc/internals/api/filters.txt index 55503e9c0..d52f414cf 100644 --- a/doc/internals/api/filters.txt +++ b/doc/internals/api/filters.txt @@ -483,6 +483,14 @@ working, a keyword parser must also be registered (see section 3.2.2). The filter class is described by the following structure : + /* Anchor of a class in one of the three class orders */ + struct filter_class_side { + struct list before; /* classes moved before all instances of this class */ + struct list after; /* classes moved after all instances of this class */ + struct list list; /* link in the order list, once the class is placed */ + unsigned int placed; /* != 0 once the class was explicitly placed */ + }; + struct filter_class { const char *name; /* The filter class name, must be uniq */ unsigned int flags; /* FLT_CLS_FL_* */ @@ -493,18 +501,11 @@ The filter class is described by the following structure : int (*parse)(char **args, struct proxy *px, struct filter_instance *inst, char **err); - struct { - struct list before; /* classes moved before current class for request */ - struct list after; /* classes moved after current class for request */ - struct list list; /* classes registered on request analysis */ - } req; - struct { - struct list before; /* classes moved before current class on response */ - struct list after; /* classes moved after current class on response */ - struct list list; /* classes registered on response analysis */ - } res; - - struct list list; /* Link in global list of filter classes */ + struct filter_class_side global; /* placement in the global order */ + struct filter_class_side req; /* placement in the request order */ + struct filter_class_side res; /* placement in the response order */ + + struct list list; /* Link in the global registry of filter classes */ }; * 'filter_class.name' is the name used by the "filter-config" directive and @@ -520,14 +521,14 @@ The filter class is described by the following structure : section 3.2.1). It may be NULL, but in this case the class cannot be used with "filter-config" at all. - * 'filter_class.req' and 'filter_class.res' anchor the class in the request - and response class orders (see below). + * 'filter_class.global', 'filter_class.req' and 'filter_class.res' anchor the + class in the three class orders (see below). * 'filter_class.list' links the class in the global registry. -The class is registered with filter_register_class(). It must then be placed, -on each side it supports, relative to an already placed class, with -filter_place_class() : +The class is registered with filter_register_class(). At this point it is +appended at the end of the global order. It must then be placed, on each side +it supports, relative to an already placed class, with filter_place_class() : static struct filter_class flt_my_filter_cls; @@ -536,8 +537,10 @@ filter_place_class() : if (filter_register_class(&flt_my_filter_cls, "my-filter", my_filter_parse_instance) < 0) return -1; - /* Evaluate the filter before SPOE on the request path and after the Lua - * filters on the response path. */ + /* Evaluate the filter before cache-store globally, before SPOE on the + * request path and after the Lua filters on the response path. */ + if (filter_place_class(&flt_my_filter_cls, FLT_SIDE_GLOBAL, "cache-store", FLT_POS_BEFORE) < 0) + return -1; if (filter_place_class(&flt_my_filter_cls, FLT_SIDE_REQ, "spoe", FLT_POS_BEFORE) < 0) return -1; if (filter_place_class(&flt_my_filter_cls, FLT_SIDE_RES, "lua", FLT_POS_AFTER) < 0) @@ -546,14 +549,31 @@ filter_place_class() : } INITCALL1(STG_INIT, 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 : + + * FLT_SIDE_REQ and FLT_SIDE_RES define the evaluation order of the instances + of the class on the corresponding channel. The reference class must be + placed on the same side, because a channel order only contains the classes + used on that channel. The order of the request and the response sides may + differ, it is common for a class to sit at two different positions. + + * FLT_SIDE_GLOBAL defines the order of the side-independent operations: the + configuration checks, the initialization and the destruction. It follows + the class registration order until a class is explicitly placed, and it is + independent of the channel placements. Any registered class may be used as + a reference on this side, since the global order contains all of them. + Moving a class in the global order does not change its request or response + positions. + filter_register_class_full() is a helper for the common case where the class is -placed on both sides at the same position relative to the same class. +placed at the same position relative to the same class, on the global side and +on both channel sides. -A class placed on neither side is rejected at startup because it would be -useless. A class may be placed on both sides with different positions. The -placement defines the default evaluation order of the instances of the class -relative to the other classes. The global order follows the class registration -order. +A class placed on neither the request nor the response side is rejected at +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 @@ -1843,9 +1863,10 @@ enabled by another directive, or is referenced by other directives. side, but the user may change it per proxy with "filter-sequence". A filter must not assume a fixed position relative to the other filters unless it owns the placement of the classes involved and knows that the - sequences cannot change it. The global order, which follows the class - registration order, only drives the side-independent operations - (configuration checks, initialization and destruction). + sequences cannot change it. The global order, which is the class + registration order refined by the placements on the FLT_SIDE_GLOBAL side, + 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 @@ -1935,8 +1956,9 @@ enabled by another directive, or is referenced by other directives. In the new mode, by the class placement on the request and response sides (section 3.2) and, possibly, by the "filter-sequence" directive on a per proxy basis (section 2.2). The global order follows the class registration - order. A filter must not assume a fixed order relative to other filters - unless it owns the corresponding placements or sequences. + order, refined by the placements on the FLT_SIDE_GLOBAL side. A filter must + not assume a fixed order relative to other filters unless it owns the + corresponding placements or sequences. In legacy mode, the declaration order of the "filter" directives is used. diff --git a/include/haproxy/filters-t.h b/include/haproxy/filters-t.h index a88626cdc..3115b2dbf 100644 --- a/include/haproxy/filters-t.h +++ b/include/haproxy/filters-t.h @@ -275,6 +275,18 @@ enum flt_pos { /* filter class flags */ #define FLT_CLS_FL_MULTI 0x01 /* Set if several class instances are allowed per proxy */ +/* Anchor of a filter class in one of the three class orders. The classes moved + * before or after all the instances of this class are linked in the 'before' + * and 'after' constraint lists, while the class itself is linked in the order + * list once it was placed. + */ +struct filter_class_side { + struct list before; /* classes moved before all instances of this class */ + struct list after; /* classes moved after all instances of this class */ + struct list list; /* link in the order list, once the class is placed */ + unsigned int placed; /* != 0 once the class was explicitly placed */ +}; + struct filter_class { const char *name; /* The filter class name, must be unique */ unsigned int flags; /* FLT_CLS_FL_* */ @@ -283,18 +295,11 @@ struct filter_class { * the filter configuration (inst->fconf). */ int (*parse)(char **args, struct proxy *px, struct filter_instance *inst, char **err); - struct { - struct list before; /* classes moved before current class for request */ - struct list after; /* classes moved after current class for request */ - struct list list; /* classes registered on request analysis */ - } req; - struct { - struct list before; /* classes moved before current class on response */ - struct list after; /* classes moved after current class on response */ - struct list list; /* classes registered on response analysis */ - } res; + struct filter_class_side global; /* placement in the global order */ + struct filter_class_side req; /* placement in the request order */ + struct filter_class_side res; /* placement in the response order */ - struct list list; /* Link in global list of filter classes */ + struct list list; /* Link in the global registry of filter classes */ }; /* Per-proxy reference to a filter class, in the global, request or response diff --git a/src/filters.c b/src/filters.c index 59145d556..a76a146ff 100644 --- a/src/filters.c +++ b/src/filters.c @@ -55,10 +55,16 @@ struct filter_class flt_bwlim_out_cls; struct filter_class flt_fcgi_cls; #endif -/* Global list of all filter classes */ +/* Global registry of all filter classes, in registration order. Used for the + * class lookup and by "haproxy -vv". + */ static struct list filter_classes = LIST_HEAD_INIT(filter_classes); -/* Ordered list of filter classes dedicated to the request/response processing */ +/* Ordered lists of the filter classes, one per evaluation order. The global + * order follows the registration order until a class is explicitly placed, the + * request and the response orders only contain the placed classes. + */ +static struct list global_filter_classes = LIST_HEAD_INIT(global_filter_classes); static struct list req_filter_classes = LIST_HEAD_INIT(req_filter_classes); static struct list res_filter_classes = LIST_HEAD_INIT(res_filter_classes); @@ -131,13 +137,38 @@ static struct filter_instance *flt_inst_from_list(struct list *entry, unsigned i return LIST_ELEM(entry, struct filter_instance *, global.list); } +/* Returns the anchor of in the evaluation order of , one of + * FLT_SIDE_GLOBAL, FLT_SIDE_REQ or FLT_SIDE_RES. + */ +static struct filter_class_side *flt_class_side(struct filter_class *cls, unsigned int side) +{ + if (side == FLT_SIDE_REQ) + return &cls->req; + if (side == FLT_SIDE_RES) + return &cls->res; + return &cls->global; +} + +/* Returns the head of the class order of . The global order is its own + * list, distinct from the registry of the registered classes. + */ +static struct list *flt_class_order(unsigned int side) +{ + if (side == FLT_SIDE_REQ) + return &req_filter_classes; + if (side == FLT_SIDE_RES) + return &res_filter_classes; + return &global_filter_classes; +} + +/* Returns the class linked in , in the order of . */ static struct filter_class *flt_class_from_list(struct list *entry, unsigned int side) { if (side == FLT_SIDE_REQ) return LIST_ELEM(entry, struct filter_class *, req.list); if (side == FLT_SIDE_RES) return LIST_ELEM(entry, struct filter_class *, res.list); - return LIST_ELEM(entry, struct filter_class *, list); + return LIST_ELEM(entry, struct filter_class *, global.list); } /* Initialize all links before any fallible operation, so error cleanup can @@ -3137,24 +3168,23 @@ void flt_deinit_new_proxy(struct proxy *px) } } -/* Dump classes in global registration order or in a channel's placement tree. */ +/* Dump classes walking the placement tree of . The classes placed + * before the current one are dumped first, then the class itself, then the + * ones placed after it. + */ static void cli_dump_flt_classes(struct buffer *out, struct list *classes, unsigned int side, int *first) { struct filter_class *cls; + struct filter_class_side *cs; struct list *entry; for (entry = classes->n; entry != classes; entry = entry->n) { cls = flt_class_from_list(entry, side); - if (side == FLT_SIDE_REQ) - cli_dump_flt_classes(out, &cls->req.before, side, first); - else if (side == FLT_SIDE_RES) - cli_dump_flt_classes(out, &cls->res.before, side, first); + cs = flt_class_side(cls, side); + cli_dump_flt_classes(out, &cs->before, side, first); chunk_appendf(out, "%s%s", *first ? "" : " > ", cls->name); *first = 0; - if (side == FLT_SIDE_REQ) - cli_dump_flt_classes(out, &cls->req.after, side, first); - else if (side == FLT_SIDE_RES) - cli_dump_flt_classes(out, &cls->res.after, side, first); + cli_dump_flt_classes(out, &cs->after, side, first); } } @@ -3176,8 +3206,7 @@ static int cli_parse_show_flt_classes(char **args, char *payload, struct appctx for (i = 0; i < sizeof(sides) / sizeof(sides[0]); i++) { if (selected && selected != sides[i]) continue; - classes = (sides[i] == FLT_SIDE_REQ ? &req_filter_classes : - sides[i] == FLT_SIDE_RES ? &res_filter_classes : &filter_classes); + classes = flt_class_order(sides[i]); first = 1; chunk_appendf(&trash, "%s: ", flt_side_name(sides[i])); cli_dump_flt_classes(&trash, classes, sides[i], &first); @@ -3358,18 +3387,23 @@ static inline void flt_init_class(struct filter_class *cls, const char *name, un cls->name = name; cls->flags = flags; cls->parse = parse; + LIST_INIT(&cls->global.before); + LIST_INIT(&cls->global.after); + LIST_INIT(&cls->global.list); + cls->global.placed = 0; + LIST_INIT(&cls->req.before); LIST_INIT(&cls->req.after); LIST_INIT(&cls->req.list); + cls->req.placed = 0; LIST_INIT(&cls->res.before); LIST_INIT(&cls->res.after); LIST_INIT(&cls->res.list); - - LIST_INIT(&cls->list); + cls->res.placed = 0; } -/* Finds a filter class by name in the global list, NULL if unknown. */ +/* Finds a filter class by name in the global registry, NULL if unknown. */ struct filter_class *filter_find_class(const char *name) { struct filter_class *cls; @@ -3381,27 +3415,20 @@ struct filter_class *filter_find_class(const char *name) return NULL; } -/* Create class references in global registration order, or following a - * side's class placement tree. Returns 0 on success, -1 on error. +/* Create class references in the class order of , following the class + * placement tree. Returns 0 on success, -1 on error. */ static int flt_init_class_refs_side(struct proxy *px, struct list *classes, unsigned int side) { struct filter_class *cls; + struct filter_class_side *cs; struct filter_class_ref *ref; - struct list *entry, *before, *after; + struct list *entry; for (entry = classes->n; entry != classes; entry = entry->n) { cls = flt_class_from_list(entry, side); - before = after = NULL; - if (side == FLT_SIDE_REQ) { - before = &cls->req.before; - after = &cls->req.after; - } - else if (side == FLT_SIDE_RES) { - before = &cls->res.before; - after = &cls->res.after; - } - if (before && flt_init_class_refs_side(px, before, side) < 0) + cs = flt_class_side(cls, side); + if (flt_init_class_refs_side(px, &cs->before, side) < 0) return -1; ref = calloc(1, sizeof(*ref)); @@ -3413,29 +3440,28 @@ static int flt_init_class_refs_side(struct proxy *px, struct list *classes, unsi LIST_INIT(&ref->reordered_after); LIST_APPEND(flt_class_refs(px, side), &ref->list); - if (after && flt_init_class_refs_side(px, after, side) < 0) + if (flt_init_class_refs_side(px, &cs->after, side) < 0) return -1; } return 0; } /* Creates the filter class references of the proxy : one global reference - * per registered class, plus references on each side it is placed on. - * The global order follows filter_classes, independently of the side placement. + * per registered class, plus references on each side the class is placed on. + * The order of each side follows the class placement tree of that side. * It is called during the proxy initialization, so all filter classes must be * registered first. * Returns 0 on success, -1 on error. */ int flt_init_class_refs(struct proxy *px) { - if (flt_init_class_refs_side(px, &filter_classes, FLT_SIDE_GLOBAL) < 0) + if (flt_init_class_refs_side(px, &global_filter_classes, FLT_SIDE_GLOBAL) < 0) goto error; if (flt_init_class_refs_side(px, &req_filter_classes, FLT_SIDE_REQ) < 0) goto error; if (flt_init_class_refs_side(px, &res_filter_classes, FLT_SIDE_RES) < 0) goto error; return 0; - error: flt_free_instances(px); return -1; @@ -3480,9 +3506,9 @@ int flt_parse_instance_legacy(struct proxy *px, struct filter_instance *inst, ch /* Registers a new filter class, with the parsing function used to * finalize the filter instances of this class (may be NULL if the class does * not support the "filter-config" directive). The class is initialized and - * added to the global "filter_classes" list only — it is not usable on any side - * until placed with filter_place_class(). Must be called after - * filter_init_classes(). + * 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(). * Returns 0 on success, -1 on error (too early call, duplicate name). */ int filter_register_class(struct filter_class *cls, const char *name, @@ -3508,16 +3534,21 @@ int filter_register_class(struct filter_class *cls, const char *name, flt_init_class(cls, name, 0, parse); LIST_APPEND(&filter_classes, &cls->list); + LIST_APPEND(&global_filter_classes, &cls->global.list); ret = 0; out: return ret; } - -/* Places on (FLT_SIDE_REQ or FLT_SIDE_RES), before or after the - * reference class . The class is appended in the reference class' - * req/res .before or .after constraint list; the final evaluation order is - * resolved later. The global ordered lists are never touched here. Call it - * once per side; the positions may differ per side. +/* Places in the order of (FLT_SIDE_GLOBAL, FLT_SIDE_REQ or + * FLT_SIDE_RES), before or after the reference class . The class is + * appended in the reference class' .before or .after constraint list of that + * side; the final evaluation order is resolved later. + * + * The global side is the order used for the side-independent operations + * (configuration checks, initialization and destruction), while the request + * and the response sides drive the stream evaluation order. + * + * Call it once per side; the positions may differ per side. * Returns 0 on success, -1 on error (unknown ref, ref not present on that side, * class already placed on that side). */ @@ -3525,14 +3556,15 @@ int filter_place_class(struct filter_class *cls, unsigned int side, const char *ref_name, enum flt_pos pos) { struct filter_class *ref; + struct filter_class_side *cs, *ref_cs; int ret = -1; if (!filter_classes_initialized) { ha_alert("filters: class '%s' placed before internal classes were initialized\n", cls->name); goto out; } - if (side != FLT_SIDE_REQ && side != FLT_SIDE_RES) { - ha_alert("filters: class '%s' placement requires a request or response side\n", cls->name); + if (side != FLT_SIDE_GLOBAL && side != FLT_SIDE_REQ && side != FLT_SIDE_RES) { + ha_alert("filters: class '%s' placement requires a global, request or response side\n", cls->name); goto out; } ref = filter_find_class(ref_name); @@ -3540,40 +3572,66 @@ int filter_place_class(struct filter_class *cls, unsigned int side, ha_alert("filters: unknown reference class '%s' for class '%s'\n", ref_name, cls->name); goto out; } + if (ref == cls) { + ha_alert("filters: class '%s' cannot be placed relative to itself\n", cls->name); + goto out; + } - if (side == FLT_SIDE_REQ) { - if (LIST_INLIST(&cls->req.list)) { - ha_alert("filters: class '%s' already placed on request side\n", cls->name); - goto out; - } - if (!LIST_INLIST(&ref->req.list)) { - ha_alert("filters: reference class '%s' has no request side\n", ref_name); - goto out; - } - LIST_APPEND((pos == FLT_POS_BEFORE) ? &ref->req.before : &ref->req.after, - &cls->req.list); + cs = flt_class_side(cls, side); + ref_cs = flt_class_side(ref, side); + + if (cs->placed) { + ha_alert("filters: class '%s' already placed on the %s side\n", + cls->name, flt_side_name(side)); + goto out; } - else { - if (LIST_INLIST(&cls->res.list)) { - ha_alert("filters: class '%s' already placed on response side\n", cls->name); - goto out; - } - if (!LIST_INLIST(&ref->res.list)) { - ha_alert("filters: reference class '%s' has no response side\n", ref_name); - goto out; - } - LIST_APPEND((pos == FLT_POS_BEFORE) ? &ref->res.before : &ref->res.after, - &cls->res.list); + + if (side == FLT_SIDE_GLOBAL) { + /* The class is already linked in the global order, it was + * appended there at registration. Move it to the requested + * position, relative to the reference class. + */ + LIST_DEL_INIT(&cs->list); } + else if (!LIST_INLIST(&ref_cs->list)) { + /* A channel order only contains the classes used on that + * channel, so the reference must be placed on it. The global + * order accepts any registered class as a reference, since it + * contains all of them. + */ + ha_alert("filters: reference class '%s' has no %s side\n", + ref_name, flt_side_name(side)); + goto out; + } + + LIST_APPEND((pos == FLT_POS_BEFORE) ? &ref_cs->before : &ref_cs->after, &cs->list); + cs->placed = 1; ret = 0; out: return ret; } -/* Registers a new filter class named and places it on both sides, - * before or after the reference class . Convenience function for - * the common symmetric case, equivalent to filter_register_class() followed - * by filter_place_class() on FLT_SIDE_REQ and FLT_SIDE_RES. +/* Detaches from the three class orders. Used by the registration + * cleanup path, when the class is about to be dropped. + */ +static void flt_unplace_class(struct filter_class *cls) +{ + unsigned int side; + + for (side = FLT_SIDE_REQ; side <= FLT_SIDE_GLOBAL; side <<= 1) { + struct filter_class_side *cs = flt_class_side(cls, side); + + if (LIST_INLIST(&cs->list)) + LIST_DEL_INIT(&cs->list); + cs->placed = 0; + } +} + +/* Registers a new filter class named and places it on the global side + * and on both channel sides, before or after the reference class . + * Convenience function for the common symmetric case, equivalent to + * filter_register_class() followed by filter_place_class() on + * FLT_SIDE_GLOBAL, FLT_SIDE_REQ and FLT_SIDE_RES. * Returns 0 on success, -1 on error. */ int filter_register_class_full(struct filter_class *cls, const char *name, int (*parse)(char **args, struct proxy *px, @@ -3582,6 +3640,8 @@ int filter_register_class_full(struct filter_class *cls, const char *name, { if (filter_register_class(cls, name, parse) < 0) goto err; + if (filter_place_class(cls, FLT_SIDE_GLOBAL, ref_name, pos) < 0) + goto cleanup_on_err; if (filter_place_class(cls, FLT_SIDE_REQ, ref_name, pos) < 0) goto cleanup_on_err; if (filter_place_class(cls, FLT_SIDE_RES, ref_name, pos) < 0) @@ -3590,8 +3650,9 @@ int filter_register_class_full(struct filter_class *cls, const char *name, return 0; cleanup_on_err: - LIST_DELETE(&cls->list); - LIST_INIT(&cls->list); + /* detach the class from the class orders and from the registry */ + flt_unplace_class(cls); + LIST_DEL_INIT(&cls->list); /* fallthrough */ err: return -1; @@ -3610,7 +3671,10 @@ int filter_register_class_full(struct filter_class *cls, const char *name, * if (filter_register_class(&flt_myfilter_cls, "myfilter", myfilter_parse_def) < 0) * return -1; * - * // before spoe on request, after lua on response + * // before spoe on request, after lua on response, before cache-store + * // for the global order + * if (filter_place_class(&flt_myfilter_cls, FLT_SIDE_GLOBAL, "cache-store", FLT_POS_BEFORE) < 0) + * return -1; * if (filter_place_class(&flt_myfilter_cls, FLT_SIDE_REQ, "spoe", FLT_POS_BEFORE) < 0) * return -1; * if (filter_place_class(&flt_myfilter_cls, FLT_SIDE_RES, "lua", FLT_POS_AFTER) < 0) @@ -3640,6 +3704,10 @@ static void filter_init_classes(void) flt_init_class(&flt_fcgi_cls, fcgi_filter_cls_name, 0, fcgi_flt_parse_instance); #endif + /* Registry: all the known classes, in registration order. It is a flat + * list, and it stays flat whatever the placements are, so that + * filter_find_class() always finds every registered class. + */ LIST_APPEND(&filter_classes, &flt_trace_cls.list); LIST_APPEND(&filter_classes, &flt_cache_store_cls.list); LIST_APPEND(&filter_classes, &flt_decomp_req_cls.list); @@ -3658,6 +3726,28 @@ static void filter_init_classes(void) LIST_APPEND(&filter_classes, &flt_fcgi_cls.list); #endif + /* Global order: the same classes, in the global evaluation order. It + * is a placement tree, the classes are re-parented by + * filter_place_class() on FLT_SIDE_GLOBAL. + */ + LIST_APPEND(&global_filter_classes, &flt_trace_cls.global.list); + LIST_APPEND(&global_filter_classes, &flt_cache_store_cls.global.list); + LIST_APPEND(&global_filter_classes, &flt_decomp_req_cls.global.list); + LIST_APPEND(&global_filter_classes, &flt_decomp_res_cls.global.list); +#if defined(USE_SPOE) + LIST_APPEND(&global_filter_classes, &flt_spoe_cls.global.list); +#endif +#if defined(USE_LUA) + LIST_APPEND(&global_filter_classes, &flt_lua_cls.global.list); +#endif + LIST_APPEND(&global_filter_classes, &flt_http_comp_req_cls.global.list); + LIST_APPEND(&global_filter_classes, &flt_http_comp_res_cls.global.list); + LIST_APPEND(&global_filter_classes, &flt_bwlim_in_cls.global.list); + LIST_APPEND(&global_filter_classes, &flt_bwlim_out_cls.global.list); +#if defined(USE_FCGI) + LIST_APPEND(&global_filter_classes, &flt_fcgi_cls.global.list); +#endif + LIST_APPEND(&req_filter_classes, &flt_trace_cls.req.list); LIST_APPEND(&req_filter_classes, &flt_decomp_req_cls.req.list); #if defined(USE_LUA)