Skip to content

feat(irtranslator): attach xRoute source metadata to Envoy routes#13620

Merged
davidjumani merged 31 commits into
kgateway-dev:mainfrom
mihir-dixit2k27:route-metadata-only
Jul 10, 2026
Merged

feat(irtranslator): attach xRoute source metadata to Envoy routes#13620
davidjumani merged 31 commits into
kgateway-dev:mainfrom
mihir-dixit2k27:route-metadata-only

Conversation

@mihir-dixit2k27

@mihir-dixit2k27 mihir-dixit2k27 commented Mar 8, 2026

Copy link
Copy Markdown
Contributor

Description

Motivation: Envoy routes generated by kgateway currently carry no
information about the originating xRoute resource. This makes
debugging, distributed tracing correlation, and access-log filtering
against route origin difficult. This was requested in #[issue number].

What changed:

  • irtranslator/policy.go — added addRouteSourceMetadata helper and
    routeSourceMetadataKey constant. The helper attaches a
    dev.kgateway.route_source filter metadata entry to every Envoy route
    carrying the originating xRoute's kind, group, name,
    namespace, and rule name. All fields are nil-safe — empty strings
    and nil Parents are no-ops.

  • irtranslator/route.go — calls addRouteSourceMetadata inside
    envoyRoutes after initRoutes, before plugin execution, so every
    generated route gets metadata regardless of which plugins run.

  • irtranslator/route_test.go — added TestAddRouteSourceMetadata
    with table-driven cases: full metadata, missing kind/rule fields, nil
    Parent (no-op), and empty rule name (field omitted).

  • Golden files updated via REFRESH_GOLDEN=true to include the new
    metadata in translator snapshot output.

Output example — new metadata on a generated Envoy route:

metadata:
  filterMetadata:
    io.kgateway.route_source:
      group: gateway.networking.k8s.io
      kind: HTTPRoute
      name: example-route
      namespace: infra
      rule: httproute-example-route-infra-0-0

Related issues: Fixes #13563

Phase scope: This is Phase 1 — automatic source metadata only.
User-defined custom metadata via TrafficPolicy or annotations is
explicitly out of scope and can build on this foundation.

Change Type

/kind feature

Changelog

Envoy routes generated by kgateway now carry a `io.kgateway.route_source` 
filter metadata entry with the originating xRoute's kind, group, name, 
namespace, and rule name — enabling tracing correlation and access-log 
filtering against route origin.

Additional Notes

  • TestDiscoveryNamespaceSelector has a pre-existing flake on main
    unrelated to these changes — verified by running the test suite on
    main before this branch was created.
  • No new external dependencies added — structpb and envoycorev3
    are already transitive dependencies in go.mod.
  • The metadata key dev.kgateway.route_source follows the existing
    filter metadata namespace convention used elsewhere in the codebase.

Copilot AI review requested due to automatic review settings March 8, 2026 19:23
@gateway-bot gateway-bot added kind/feature Categorizes issue or PR as related to a new feature. release-note labels Mar 8, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds standard Envoy route filter_metadata identifying the originating Gateway API xRoute (and rule) to improve observability/debuggability (tracing correlation, access-log filtering) across generated routes.

Changes:

  • Introduces addRouteSourceMetadata and routeSourceMetadataKey to attach io.kgateway.route_source filter metadata onto Envoy routes.
  • Hooks metadata attachment into route generation (envoyRoutes) prior to route plugin execution.
  • Adds unit coverage for the metadata helper and refreshes goldens to include the new metadata.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
pkg/kgateway/translator/irtranslator/policy.go Adds helper + key constant to populate per-route filter_metadata describing route source.
pkg/kgateway/translator/irtranslator/route.go Calls helper during Envoy route construction so metadata is attached consistently.
pkg/kgateway/translator/irtranslator/route_test.go Adds table-driven tests validating metadata behavior (including preservation of existing metadata).

You can also share your feedback on Copilot code review. Take the survey.

Comment thread pkg/kgateway/translator/irtranslator/policy.go Outdated
Comment thread pkg/kgateway/translator/irtranslator/route_test.go Outdated
Comment thread pkg/kgateway/translator/irtranslator/route_test.go
@andy-fong
andy-fong self-requested a review March 9, 2026 14:25
Comment thread pkg/kgateway/translator/irtranslator/route.go Outdated

@andy-fong andy-fong left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I am not ultimately familiar with these but on search for envoyroutev3 on the codebase, a couple areas comes up that might need further investigation:

  1. in this route.go, there is a case for setFallBackConfig(), do we need metadata there?
  2. in the directresponse plugin, it also seems to generate route, check and test if we need metadata there as well.

Comment thread pkg/kgateway/translator/irtranslator/policy.go Outdated
@andy-fong

Copy link
Copy Markdown
Contributor

Also, can you test out what is the output if merging of route happens? How does the metadata look like?

mihir-dixit2k27 and others added 2 commits April 2, 2026 21:05
- Change route source metadata key prefix from io.kgateway to dev.kgateway
- Add comments explaining why setFallBackConfig and directresponse plugins
  currently do not inject route metadata

Signed-off-by: mihir-dixit2k27 <[email protected]>
@mihir-dixit2k27

Copy link
Copy Markdown
Contributor Author

Also, can you test out what is the output if merging of route happens? How does the metadata look like?

Tested this. When two route rules merge into a single Envoy route, addRouteSourceMetadata
is called sequentially on the same metadata object. Because the function overwrites the
dev.kgateway.route_source key unconditionally:

metadata.FilterMetadata[routeSourceMetadataKey] = &structpb.Struct{Fields: fields}

the last rule processed wins. Actual test output:

{
  "filter_metadata": {
    "dev.kgateway.route_source": {
      "group": "gateway.networking.k8s.io",
      "kind": "HTTPRoute",
      "name": "test-route",
      "namespace": "default",
      "rule": "rule2-merged"
    }
  }
}

So if rule1 and rule2 merge, only rule2's source is reported — rule1 is silently dropped.
Happy to change this behavior (e.g. keep the first rule, or store a list) if you'd prefer
different semantics for merged routes.

Gate addRouteSourceMetadata behind a KGW_ROUTE_SOURCE_METADATA_ENABLED
environment variable (default: false). This makes the dev.kgateway.route_source
filter metadata attachment opt-in, addressing reviewer feedback on PR kgateway-dev#13620.

Changes:
- api/settings/settings.go: add RouteSourceMetadataEnabled bool field
- pkg/kgateway/translator/irtranslator/route.go: gate addRouteSourceMetadata call
- pkg/kgateway/translator/irtranslator/gateway.go: thread flag through Translator struct
- pkg/kgateway/translator/translator.go: wire setting from Settings
- install/helm/kgateway/values.yaml: add routeSourceMetadataEnabled: false
- install/helm/kgateway/templates/deployment.yaml: add KGW_ROUTE_SOURCE_METADATA_ENABLED env var

No golden files changed as the flag is off by default.

Signed-off-by: Mihir Dixit <[email protected]>
@mihir-dixit2k27
mihir-dixit2k27 requested a review from a team as a code owner April 9, 2026 18:13

@andy-fong andy-fong left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@mihir-dixit2k27 Thank you again for the contribution. Can you add translator test to this now that we don't have to modify all the golden file.

mihir-dixit2k27 and others added 2 commits April 13, 2026 15:59
TestRouteSourceMetadataFlag covers both states of routeSourceMetadataEnabled
without modifying any golden files:
- off (default): no dev.kgateway.route_source key present in filter metadata
- on: all five fields (kind, group, name, namespace, rule) are populated

The test replicates the flag gate in envoyRoutes() directly, so it runs
without a fully-wired GatewayIR or backend list.

Signed-off-by: Mihir Dixit <[email protected]>
mihir-dixit2k27 and others added 3 commits May 1, 2026 04:55
The function and its constant were dropped when main was merged into
the branch. Also restores TestAddRouteSourceMetadata and
TestRouteSourceMetadataFlag which cover the helper and flag gate.

Signed-off-by: Mihir Dixit <[email protected]>
TestEnvVarCoverage enforces that every Settings field has a non-default
value in allEnvVarsSet(). Add KGW_ROUTE_SOURCE_METADATA_ENABLED and
wire RouteSourceMetadataEnabled into the all-values-set expected struct.

Signed-off-by: Mihir Dixit <[email protected]>
@mihir-dixit2k27

Copy link
Copy Markdown
Contributor Author

@mihir-dixit2k27 Thank you again for the contribution. Can you add translator test to this now that we don't have to modify all the golden file.

Ready for re-review @andy-fong

mihir-dixit2k27 and others added 3 commits May 23, 2026 02:51
TestAddRouteSourceMetadata and TestRouteSourceMetadataFlag were dropped
during a main merge conflict resolution, leaving three imports unused and
causing both lint and unit test failures. Restore both test functions on
top of the current branch state which already contains all main changes.

Signed-off-by: Mihir Dixit <[email protected]>
…ml merge conflict

Upstream main added KGW_ENABLE_AWS_EC2_DISCOVERY and KGW_AWS_EC2_REFRESH_INTERVAL
in the same location as our KGW_ROUTE_SOURCE_METADATA_ENABLED, causing a GitHub
PR merge conflict. Include both sets of changes and add the corresponding
values.yaml defaults.

Signed-off-by: Mihir Dixit <[email protected]>
@andy-fong andy-fong self-assigned this Jun 10, 2026
@puertomontt

Copy link
Copy Markdown
Contributor

re: will route replacement carry metadata?

It depends

  1. Per-route replacement — keeps the metadata ✅

When a single route is invalid (bad builtin filter, invalid config, validateRoutePreEnvoy
failure, etc.), finalizeRoute (route.go:338-374) mutates the same out object in place: it swaps
Action to a 500 direct response and clears headers/TPFC — but it does not touch Metadata. Since
envoyRoutes set out.Metadata at line 253 before the action was computed, the replaced route
retains it.

  1. Whole-vhost / whole-RouteConfiguration replacement — loses the metadata.

When a vhost-plugin fails, strict batch validation fails, or route-config plugins fail
(route.go:114, :194, :426), the entire vhost/RC is discarded and replaced by setFallBackConfig —
a brand-new synthetic catch-all / → 500 route with no Metadata. All per-route source metadata is
gone, because many routes collapse into one synthetic route with no single source to attribute.

This is correct because the fallback route isn't produced by any xRoute — it's a synthetic error route that kgateway emits because a listener/vhost/RC-level policy failed

@davidjumani
davidjumani enabled auto-merge July 9, 2026 00:28
@davidjumani
davidjumani added this pull request to the merge queue Jul 10, 2026
Merged via the queue into kgateway-dev:main with commit f71e448 Jul 10, 2026
32 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kind/feature Categorizes issue or PR as related to a new feature. release-note

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add route-level Envoy metadata with support for custom values

7 participants