Skip to content

Prioritize backends using an ACL during selection#138

Draft
thomasklinger1234 wants to merge 4 commits intonigoroll:masterfrom
thomasklinger1234:feat/prefer-via-acl
Draft

Prioritize backends using an ACL during selection#138
thomasklinger1234 wants to merge 4 commits intonigoroll:masterfrom
thomasklinger1234:feat/prefer-via-acl

Conversation

@thomasklinger1234
Copy link
Copy Markdown

Summary

This PR aims to serve as a discussion point for #132.

The VCL interface for directory is extended with a new ACL prefer parameter that - if set - will prioritize backends matching this ACL during resolution. The idea is to implement use cases such as "prefer IPv6" or "prefer nearest datacenter".

Contrary to whitelist, the prefer parameter will only be active during the resolve method in the director and does not filter out backends. This is important in particular for varnishadm backend.list which still shows all backends available. If there are not matches for the preferred ACL, the existing logic applies.

Notable changes

  • Add a new prefer parameter to dynamic.director(...)
  • Extend varnishadm backend.list -j -p JSON output with the preferred field
  • All dynamic_ref instances have a marker preferred
  • dom_find has been updated

Open topics

  • Add new VTC tests
  • Update README.rst

Extends the VMOD interface for directors with a new optional ACL
"prefer". This ACL can be used to prioritize certain IPs or ranges
upon backend selection later. In this step, the VMOD interface is
extended and dynamic_refs are marked with a "prefer" field based on the
result of VRT_acl_match.
varnishadm backend.list in JSON mode now prints if a backend is
preferred or not.
Introduce a new dom_find variant that runs in two passes:

1. Check for a healthy dynamic_ref
2. Check for an alternative healthy AND preferred dynamic_ref

The new variant of dom_find introduces some internal changes:

- use VTAILQ_FOREACH instead of the do/while loop for easy iteration
- currently, dom->current is updated in dom_find instead of dom_resolve
  (might need to updated later to prevent misusage)
- dom->current is used as the primary iterator instead of a separate
  start parameter

A follow up patch needs to add a new VTC test and change the name back
to dom_find OR keep dom_find in place and switch if "preferred" has been
set
@thomasklinger1234 thomasklinger1234 marked this pull request as draft March 26, 2026 14:20
Comment thread src/vmod_dynamic.c
/* find a healthy dynamic_ref */

static struct dynamic_ref *
dom_find(VRT_CTX, struct dynamic_domain *dom, struct dynamic_ref *start,
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly, I tried to keep the function as is but did not find a good way to easily integrate backend selection flow for preferred with the existing implementation. If there is a better way, I am open to refactor!

Comment thread src/vmod_dynamic.c
if (VTAILQ_EMPTY(&dom->refs))
return (NULL);

r = dom->current == NULL ? VTAILQ_FIRST(&dom->refs) : VTAILQ_NEXT(dom->current, list);
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dom->current is not heavily used for iteration. This is probably not the best way

Comment thread src/vmod_dynamic.c
VCL_BOOL *healthy, VCL_TIME *changed, unsigned wait)
{
struct dynamic_ref *next, *alt;
dom_find_v2(VRT_CTX, struct dynamic_domain *dom, VCL_BOOL *healthy, VCL_TIME *changed, unsigned wait) {
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be renamed to dom_find

Comment thread src/vmod_dynamic.h
unsigned magic;
#define DYNAMIC_REF_MAGIC 0x79a19d81
unsigned keep;
unsigned preferred;
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this be extended to something like score or priority? In general, the task at hand is a special scoring problem. This would match the way that HAProxy implements their prefer-ipv6 feature.

@thomasklinger1234
Copy link
Copy Markdown
Author

thomasklinger1234 commented Mar 26, 2026

Currently in draft for discussion, feedback and verification. My tests show good and correct results but I have not tested edge cases yet.

The VCL i have used is

vcl 4.1;

import dynamic from "<workdir>/src/.libs/libvmod_dynamic.so";

import std;
import directors;

backend default {
	.host = "127.0.0.1";
	.port = "80";
	.max_connections = 30;
	.wait_limit = 60;
	.wait_timeout = 10s;
}

acl ipv6_only { "::"/0; }
#acl ipv4_only { "0"/0; }
#acl ipv_all { "0"/0; "::"/0; }

sub vcl_init {
        new dyn_default = dynamic.director(
            ttl = 30s,
            port = 80,
            domain_usage_timeout = 3s,
            first_lookup_timeout = 3s,
            retry_after = 10s,
            keep = 10,
            host_header = "example.com",
            authority = "example.com",
            prefer = ipv6_only,
        );
        new dyn_default_dir = directors.round_robin();
        dyn_default.debug(1);
        dyn_default_dir.add_backend(dyn_default.backend(
            "example.com",
            "80",
        ));
}

sub vcl_recv {

}

sub vcl_backend_fetch {
    set bereq.http.host = "example.com";
    set bereq.backend = dyn_default.backend("example.com", "80");
}

@nigoroll
Copy link
Copy Markdown
Owner

@thomasklinger1234 I do very much appreciate your efforts, thank you.

Incidentally I have now come back to this topic and would like to try an idea: Generalize this a bit and try to reuse the service code.
Please give me a moment.

@nigoroll nigoroll mentioned this pull request Mar 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants