--- /dev/null
+From fbf5df34a4dbcd09d433dd4f0916bf9b2ddb16de Mon Sep 17 00:00:00 2001
+From: Jakub Kicinski <kuba@kernel.org>
+Date: Sun, 10 May 2026 12:29:01 -0700
+Subject: tools: ynl: add scope qualifier for definitions
+
+From: Jakub Kicinski <kuba@kernel.org>
+
+commit fbf5df34a4dbcd09d433dd4f0916bf9b2ddb16de upstream.
+
+Using definitions in kernel policies is awkward right now.
+On one hand we want defines for max values and such.
+On the other we don't have a way of adding kernel-only defines.
+Adding unnecessary defines to uAPI is a bad idea, we won't
+be able to delete them. And when it comes to policy user
+space should just query it via the policy dump, not use
+hard coded defines.
+
+Add a "scope" property to definitions, which will let us tell
+the codegen that a definition is for kernel use only. Support
+following values:
+ - uapi: render into the uAPI header (default, today's behavior)
+ - kernel: render to kernel header only
+ - user: same as kernel but for the user-side generated header
+
+Definitions may have a header property (definition is "external",
+provided by existing header). Extend the scope to headers, too.
+If definition has both scope and header properties we will only
+generate the includes in the right scope.
+
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Link: https://patch.msgid.link/20260510192904.3987113-8-kuba@kernel.org
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ Documentation/netlink/genetlink-c.yaml | 9 ++++++++
+ Documentation/netlink/genetlink-legacy.yaml | 9 ++++++++
+ Documentation/netlink/genetlink.yaml | 9 ++++++++
+ Documentation/netlink/netlink-raw.yaml | 9 ++++++++
+ tools/net/ynl/pyynl/ynl_gen_c.py | 31 ++++++++++++++++++++++++++--
+ 5 files changed, 65 insertions(+), 2 deletions(-)
+
+--- a/Documentation/netlink/genetlink-c.yaml
++++ b/Documentation/netlink/genetlink-c.yaml
+@@ -69,6 +69,15 @@ properties:
+ header:
+ description: For C-compatible languages, header which already defines this value.
+ type: string
++ scope:
++ description: |
++ Visibility of this definition. "uapi" (default) renders into
++ the uAPI header, "kernel" renders into the kernel-side
++ generated header, "user" renders into the user-side
++ generated header. When combined with `header:`, the
++ definition is not rendered, and the named header is
++ included only by code matching the scope.
++ enum: [ uapi, kernel, user ]
+ type:
+ enum: [ const, enum, flags ]
+ doc:
+--- a/Documentation/netlink/genetlink-legacy.yaml
++++ b/Documentation/netlink/genetlink-legacy.yaml
+@@ -83,6 +83,15 @@ properties:
+ header:
+ description: For C-compatible languages, header which already defines this value.
+ type: string
++ scope:
++ description: |
++ Visibility of this definition. "uapi" (default) renders into
++ the uAPI header, "kernel" renders into the kernel-side
++ generated header, "user" renders into the user-side
++ generated header. When combined with `header:`, the
++ definition is not rendered, and the named header is
++ included only by code matching the scope.
++ enum: [ uapi, kernel, user ]
+ type:
+ enum: [ const, enum, flags, struct ] # Trim
+ doc:
+--- a/Documentation/netlink/genetlink.yaml
++++ b/Documentation/netlink/genetlink.yaml
+@@ -55,6 +55,15 @@ properties:
+ header:
+ description: For C-compatible languages, header which already defines this value.
+ type: string
++ scope:
++ description: |
++ Visibility of this definition. "uapi" (default) renders into
++ the uAPI header, "kernel" renders into the kernel-side
++ generated header, "user" renders into the user-side
++ generated header. When combined with `header:`, the
++ definition is not rendered, and the named header is
++ included only by code matching the scope.
++ enum: [ uapi, kernel, user ]
+ type:
+ enum: [ const, enum, flags ]
+ doc:
+--- a/Documentation/netlink/netlink-raw.yaml
++++ b/Documentation/netlink/netlink-raw.yaml
+@@ -81,6 +81,15 @@ properties:
+ header:
+ description: For C-compatible languages, header which already defines this value.
+ type: string
++ scope:
++ description: |
++ Visibility of this definition. "uapi" (default) renders into
++ the uAPI header, "kernel" renders into the kernel-side
++ generated header, "user" renders into the user-side
++ generated header. When combined with `header:`, the
++ definition is not rendered, and the named header is
++ included only by code matching the scope.
++ enum: [ uapi, kernel, user ]
+ type:
+ enum: [ const, enum, flags, struct ] # Trim
+ doc:
+--- a/tools/net/ynl/pyynl/ynl_gen_c.py
++++ b/tools/net/ynl/pyynl/ynl_gen_c.py
+@@ -3212,6 +3212,8 @@ def render_uapi(family, cw):
+ for const in family['definitions']:
+ if const.get('header'):
+ continue
++ if const.get('scope', 'uapi') != 'uapi':
++ continue
+
+ if const['type'] != 'const':
+ cw.writes_defines(defines)
+@@ -3339,6 +3341,25 @@ def render_uapi(family, cw):
+ cw.p(f'#endif /* {hdr_prot} */')
+
+
++def render_scoped_consts(family, cw, scope):
++ defines = []
++ for const in family['definitions']:
++ if const['type'] != 'const':
++ continue
++ if const.get('header'):
++ continue
++ if const.get('scope') != scope:
++ continue
++ name_pfx = const.get('name-prefix', f"{family.ident_name}-")
++ defines.append([
++ c_upper(family.get('c-define-name',
++ f"{name_pfx}{const['name']}")),
++ const['value']])
++ if defines:
++ cw.writes_defines(defines)
++ cw.nl()
++
++
+ def _render_user_ntf_entry(ri, op):
+ if not ri.family.is_classic():
+ ri.cw.block_start(line=f"[{op.enum_name}] = ")
+@@ -3504,8 +3525,12 @@ def main():
+ cw.p('#include "ynl.h"')
+ headers = []
+ for definition in parsed['definitions'] + parsed['attribute-sets']:
+- if 'header' in definition:
+- headers.append(definition['header'])
++ if 'header' not in definition:
++ continue
++ scope = definition.get('scope', 'uapi')
++ if scope != 'uapi' and scope != args.mode:
++ continue
++ headers.append(definition['header'])
+ if args.mode == 'user':
+ headers.append(parsed.uapi_header)
+ seen_header = []
+@@ -3522,6 +3547,7 @@ def main():
+ for one in args.user_header:
+ cw.p(f'#include "{one}"')
+ else:
++ render_scoped_consts(parsed, cw, 'user')
+ cw.p('struct ynl_sock;')
+ cw.nl()
+ render_user_family(parsed, cw, True)
+@@ -3529,6 +3555,7 @@ def main():
+
+ if args.mode == "kernel":
+ if args.header:
++ render_scoped_consts(parsed, cw, 'kernel')
+ for _, struct in sorted(parsed.pure_nested_structs.items()):
+ if struct.request:
+ cw.p('/* Common nested types */')