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
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.
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
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.
return 0;
}
+/* Returns true if the proxy <px> has a filter instance of the filter owning
+ * the callbacks table <ops>. 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 <px> 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 : "<unnamed>"));
+ }
+}
+
+
/* Applies the default filter mode on the proxy <px>, 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
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",