From: Christopher Faulet Date: Tue, 27 Oct 2026 10:15:51 +0000 (+0100) Subject: MINOR: filters: Warn about ignored legacy filters for a proxy X-Git-Tag: v3.5-dev10~38 X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=5a476c38e4fbcee8d93b2257a2e1194ed533a9ed;p=haproxy.git MINOR: filters: Warn about ignored legacy filters for a proxy A proxy without explicit filter declaration now gets its filter mode deduced from the filters implied by its other directives. When it implies filters of both kinds, it uses the filter instance mode and the class-less ones are ignored: their configurations are legacy filter configurations with no filter instance, so they are never evaluated and the features they implement silently stop working on that proxy. Such a proxy is now reported at startup, with a warning per ignored configuration, naming the configuration and reminding the two ways to have it evaluated: declare the filter explicitly with the "filter" directive, which selects the legacy mode for the whole proxy, or set the "filter-api downgrade-to-legacy" global option. The relation between a legacy configuration and the instances of its filter relies on the callbacks table of the filter: a filter supporting both modes produces configurations with the same table from its legacy keyword parser and from its class parse callback (see flt_parse_instance_legacy()), so an instance with the same table means the filter declared its class. The check runs after the instances are finalized, when their configurations exist, and before the class references are released by the flattening. All the filters supported in-tree register their classes, so only the third-party filters relying on an implicit declaration are concerned. The documentation is updated accordingly, in the filters internals guide and in the configuration manual. --- diff --git a/doc/configuration.txt b/doc/configuration.txt index 88c50bb47..9d7537af3 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -2824,7 +2824,8 @@ filter-api default | downgrade-to-legacy directives: a proxy implying only filters known as legacy filter configurations, without any filter class, uses the legacy API, while a proxy implying at least one filter class uses the filter instance API, and - the class-less filters it may also imply are ignored. By setting this option + the class-less filters it may also imply are ignored, with a warning on + each of their legacy filter configurations. By setting this option to "downgrade-to-legacy", it is possible to force the proxies without explicit filter directives to use the legacy filter API, whatever they imply. It could be useful the time to convert outdated filters still relying diff --git a/doc/internals/api/filters.txt b/doc/internals/api/filters.txt index 2f94a9d5a..b8333fca3 100644 --- a/doc/internals/api/filters.txt +++ b/doc/internals/api/filters.txt @@ -86,8 +86,9 @@ filters do not select a mode, so a proxy using only implicit filters works in the new mode, unless the implicitly declared filters are only known as legacy filter configurations: a filter not supporting the new mode declares no class, hence no instance, and a proxy implying such filters keeps working in -the legacy mode. A proxy implying filters of both kinds uses the new mode, -where the class-less ones are ignored. The "filter-api" global option forces +legacy mode. A proxy implying filters of both kinds uses the new mode, where +the class-less ones are ignored: their legacy configurations are reported as +a warning. The "filter-api" global option forces the legacy mode for every proxy using only implicitly declared filters, whatever they imply. It is a fallback for the filters not supporting the new mode, and the explicit declarations always win. @@ -1662,7 +1663,8 @@ working as-is, nothing is required to use it with the "filter" directive. But it is invisible to the new mode until its class is declared. A proxy implying only such filters keeps working in the legacy mode, since HAProxy 3.5 deduces it from the implied declarations, but a proxy implying filters -of both kinds ignores the class-less ones: the "filter-api +of both kinds ignores the class-less ones, with a warning on each of their +legacy configurations: the "filter-api downgrade-to-legacy" global option keeps them working in the meantime, see the FAQ (section 5.7). This section lists what changed for a filter developer, then explains how to @@ -2036,7 +2038,8 @@ enabled by another directive, or is referenced by other directives. works in the legacy mode by default, since HAProxy 3.5 deduces the mode from the implied declarations, so they keep working as-is. The problem only arises for a proxy implying filters of both kinds: the class-less - ones are ignored. All the filters implied by such a proxy must then + ones are ignored, and HAProxy reports a warning for each of their legacy + configurations. All the filters implied by such a proxy must then support the new mode, or the legacy ones must be declared explicitly with the "filter" directive. diff --git a/src/filters.c b/src/filters.c index 9987ed5f3..36f6c1415 100644 --- a/src/filters.c +++ b/src/filters.c @@ -3191,6 +3191,57 @@ static int flt_has_conf_instances(const struct proxy *px) return 0; } +/* Returns true if the proxy has a filter instance of the filter owning + * the callbacks table . A filter supporting the new mode registers a + * class whose parse callback produces configurations with the same callbacks + * table as its legacy keyword parser (see flt_parse_instance_legacy()), so + * the table identifies the filter behind a configuration. Must be called + * after the instances were finalized, when their configuration exists. + */ +static int flt_conf_has_instance(struct proxy *px, const struct flt_ops *ops) +{ + struct filter_class_ref *ref; + struct filter_instance *inst; + + list_for_each_entry(ref, &px->conf.filter_refs, list) { + list_for_each_entry(inst, &ref->instances, global.list) { + if (inst->fconf && inst->fconf->ops == ops) + return 1; + } + } + return 0; +} + +/* Warns about the legacy filter configurations of the proxy that the new + * filter API ignores. Only the filter instances are evaluated in the new + * mode: a legacy filter configuration with no instance of the same filter is + * never used, and the filter it configures does not work. Such a + * configuration comes from an implicit declaration of a filter that + * registered no class, an explicit "filter" directive would have selected the + * legacy mode for the whole proxy. The relation between a configuration and + * the instances of its filter relies on the callbacks table of the filter, + * see flt_conf_has_instance(). Must be called when the proxy uses the new + * mode, after its instances were finalized and before they are flattened. + */ +static void flt_warn_ignored_conf(struct proxy *px) +{ + struct flt_conf *fconf; + + if (flt_use_legacy_filter(px) || LIST_ISEMPTY(&px->filter_configs)) + return; + + list_for_each_entry(fconf, &px->filter_configs, list) { + if (flt_conf_has_instance(px, fconf->ops)) + continue; + ha_warning("config: %s '%s' : ignoring the legacy filter configuration '%s'. " + "Declare all filters with the 'filter' directive or use the 'filter-api " + "downgrade-to-legacy' option to evaluate it with the legacy filter API.\n", + proxy_type_str(px), px->id, + fconf->id ? fconf->id : (fconf->name ? fconf->name : "")); + } +} + + /* Applies the default filter mode on the proxy , when it used no explicit * filter declaration (neither "filter" nor "filter-*" directives): the mode * is deduced from the filter configurations and the filter instances implied @@ -3261,6 +3312,11 @@ static int flt_precheck_instances_all() px->id); return err_code; } + /* The instances are finalized: the legacy configurations of the + * filters that registered no class, ignored by the new mode, + * are identified now, before the class references are released. + */ + flt_warn_ignored_conf(px); err_code |= flt_enable_filters(px); if (err_code & (ERR_ABORT|ERR_FATAL)) { ha_alert("Failed to apply the filter-enable/filter-disable directives of proxy '%s'.\n",