Allow using custom name-prefix with constants,
just like it is for enum and flags declarations.
This is needed for generating WG_KEY_LEN in
include/uapi/linux/wireguard.h from a spec.
Signed-off-by: Asbjørn Sloth Tønnesen <redacted>
---
tools/net/ynl/pyynl/ynl_gen_c.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
@@ -973,6 +973,8 @@ class YnlFamily(SpecFamily):raw=ip.packedelse:raw=int(ip)+elifattr_spec.display_hint=='hex':+raw=bytes.fromhex(string)else:raiseException(f"Display hint '{attr_spec.display_hint}' not implemented"f" when parsing '{attr_spec['name']}'")
@@ -564,6 +564,11 @@ class YnlFamily(SpecFamily):nl_type|=Netlink.NLA_F_NESTEDsub_space=attr['nested-attributes']attr_payload=self._add_nest_attrs(value,sub_space,search_attrs)+elifattr['type']=='indexed-array'andattr['sub-type']=='nest':+nl_type|=Netlink.NLA_F_NESTED+sub_space=attr['nested-attributes']+attr_payload=self._encode_indexed_array(value,sub_space,+search_attrs)elifattr["type"]=='flag':ifnotvalue:# If value is absent or false then skip attribute creation.
@@ -617,6 +622,9 @@ class YnlFamily(SpecFamily):else:raiseException(f'Unknown type at {space}{name}{value}{attr["type"]}')+returnself._add_attr_raw(nl_type,attr_payload)++def_add_attr_raw(self,nl_type,attr_payload):pad=b'\x00'*((4-len(attr_payload)%4)%4)returnstruct.pack('HH',len(attr_payload)+4,nl_type)+attr_payload+pad
@@ -628,6 +636,15 @@ class YnlFamily(SpecFamily):sub_attrs)returnattr_payload+def_encode_indexed_array(self,vals,sub_space,search_attrs):+attr_payload=b''+nested_flag=Netlink.NLA_F_NESTED+fori,valinenumerate(vals):+idx=i|Netlink.NLA_F_NESTED+val_payload=self._add_nest_attrs(val,sub_space,search_attrs)+attr_payload+=self._add_attr_raw(idx,val_payload)+returnattr_payload+def_get_enum_or_unknown(self,enum,raw):try:name=enum.entries_by_val[raw].name
Instead of trying to define "struct nlattr *array;" in the all
the right places, then simply define it in a block scope,
as it's only used here.
Before this patch it was generated for attribute set _put()
functions, like wireguard_wgpeer_put(), but missing and caused a
compile error for the command function wireguard_set_device().
$ make -C tools/net/ynl/generated wireguard-user.o
-e CC wireguard-user.o
wireguard-user.c: In function ‘wireguard_set_device’:
wireguard-user.c:548:9: error: ‘array’ undeclared (first use in ..)
548 | array = ynl_attr_nest_start(nlh, WGDEVICE_A_PEERS);
| ^~~~~
Signed-off-by: Asbjørn Sloth Tønnesen <redacted>
---
tools/net/ynl/pyynl/ynl_gen_c.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
This patch adds support for NLA_POLICY_NESTED_ARRAY() policies.
Example spec (from future wireguard.yaml):
-
name: wgpeer
attributes:
-
name: allowedips
type: indexed-array
sub-type: nest
nested-attributes: wgallowedip
yields NLA_POLICY_NESTED_ARRAY(wireguard_wgallowedip_nl_policy).
This doesn't change any currently generated code, as it isn't
used in any specs currently used for generating code.
Signed-off-by: Asbjørn Sloth Tønnesen <redacted>
---
tools/net/ynl/pyynl/ynl_gen_c.py | 5 +++++
1 file changed, 5 insertions(+)
Add a check to verify that the sub-type is "nest", and throw an
exception if no policy could be generated, as a guard to prevent
against generating a bad policy.
This is a trivial patch with no behavioural changes intended.
Signed-off-by: Asbjørn Sloth Tønnesen <redacted>
---
tools/net/ynl/pyynl/ynl_gen_c.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
In nested arrays don't require that the intermediate
attribute type should be a valid attribute type, it
might just be an index or simple 0, it is often not
even used.
See include/net/netlink.h about NLA_NESTED_ARRAY:
The difference to NLA_NESTED is the structure:
NLA_NESTED has the nested attributes directly inside
while an array has the nested attributes at another
level down and the attribute types directly in the
nesting don't matter.
As TypeArrayNest can now be used with many other sub-types
than nest, then rename it to TypeIndexedArray, to reduce
confusion.
This is a trivial patch with no behavioural changes intended.
Signed-off-by: Asbjørn Sloth Tønnesen <redacted>
---
tools/net/ynl/pyynl/ynl_gen_c.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
@@ -792,7 +792,7 @@ class TypeMultiAttr(Type):f"{presence} = n_{self.c_name};"]-classTypeArrayNest(Type):+classTypeIndexedArray(Type):defis_multi_val(self):returnTrue
@@ -829,7 +829,7 @@ class TypeArrayNest(Type):elifself.attr['sub-type']=='nest':returnf'.type = YNL_PT_NEST, .nest = &{self.nested_render_name}_nest, 'else:-raiseException(f"Typol for ArrayNest sub-type {self.attr['sub-type']} not supported, yet")+raiseException(f"Typol for IndexedArray sub-type {self.attr['sub-type']} not supported, yet")def_attr_get(self,ri,var):local_vars=['const struct nlattr *attr2;']
@@ -859,7 +859,7 @@ class TypeArrayNest(Type):ri.cw.p(f'for (i = 0; i < {var}->_count.{self.c_name}; i++)')ri.cw.p(f"{self.nested_render_name}_put(nlh, i, &{var}->{self.c_name}[i]);")else:-raiseException(f"Put for ArrayNest sub-type {self.attr['sub-type']} not supported, yet")+raiseException(f"Put for IndexedArray sub-type {self.attr['sub-type']} not supported, yet")ri.cw.p('ynl_attr_nest_end(nlh, array);')ri.cw.block_end()
@@ -1137,7 +1137,7 @@ class AttrSet(SpecAttrSet):t=TypeNest(self.family,self,elem,value)elifelem['type']=='indexed-array'and'sub-type'inelem:ifelem["sub-type"]in['binary','nest','u32']:-t=TypeArrayNest(self.family,self,elem,value)+t=TypeIndexedArray(self.family,self,elem,value)else:raiseException(f'new_attr: unsupported sub-type {elem["sub-type"]}')elifelem['type']=='nest-type-value':
This patch moves nest packing into a helper function,
that can also be used for packing indexed arrays.
No behavioural changes intended.
Signed-off-by: Asbjørn Sloth Tønnesen <redacted>
---
tools/net/ynl/pyynl/lib/ynl.py | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
@@ -562,11 +562,8 @@ class YnlFamily(SpecFamily):ifattr["type"]=='nest':nl_type|=Netlink.NLA_F_NESTED-attr_payload=b''sub_space=attr['nested-attributes']-sub_attrs=SpaceAttrs(self.attr_sets[sub_space],value,search_attrs)-forsubname,subvalueinvalue.items():-attr_payload+=self._add_attr(sub_space,subname,subvalue,sub_attrs)+attr_payload=self._add_nest_attrs(value,sub_space,search_attrs)elifattr["type"]=='flag':ifnotvalue:# If value is absent or false then skip attribute creation.
@@ -623,6 +620,14 @@ class YnlFamily(SpecFamily):pad=b'\x00'*((4-len(attr_payload)%4)%4)returnstruct.pack('HH',len(attr_payload)+4,nl_type)+attr_payload+pad+def_add_nest_attrs(self,value,sub_space,search_attrs):+sub_attrs=SpaceAttrs(self.attr_sets[sub_space],value,search_attrs)+attr_payload=b''+forsubname,subvalueinvalue.items():+attr_payload+=self._add_attr(sub_space,subname,subvalue,+sub_attrs)+returnattr_payload+def_get_enum_or_unknown(self,enum,raw):try:name=enum.entries_by_val[raw].name
The attribute WGALLOWEDIP_A_IPADDR can contain either an IPv4
or an IPv6 address depending on WGALLOWEDIP_A_FAMILY, however
in practice it is enough to look at the attribute length.
This patch implements an ipv4-or-v6 display hint, that can
deal with this kind of attribute.
It only implements this display hint for genetlink-legacy, it
can be added to other protocol variants if needed, but we don't
want to encourage it's use.
Signed-off-by: Asbjørn Sloth Tønnesen <redacted>
---
Documentation/netlink/genetlink-legacy.yaml | 2 +-
tools/net/ynl/pyynl/lib/ynl.py | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
@@ -154,7 +154,7 @@ properties:Optional format indicator that is intended only for choosingthe right formatting mechanism when displaying values of thistype.-enum:[hex,mac,fddi,ipv4,ipv6,uuid]+enum:[hex,mac,fddi,ipv4,ipv6,ipv4-or-v6,uuid]struct:description:Name of the nested struct type.type:string
In wireguard_get_device_dump(), as generated by print_dump(),
it didn't generate a declaration of `unsigned int i`:
$ make -C tools/net/ynl/generated wireguard-user.o
-e CC wireguard-user.o
wireguard-user.c: In function ‘wireguard_get_device_dump’:
wireguard-user.c:502:22: error: ‘i’ undeclared (first use in this fn)
502 | for (i = 0; i < req->_count.peers; i++)
| ^
Copy the logic from print_req() as it correctly generated the
iterator in wireguard_set_device().
Signed-off-by: Asbjørn Sloth Tønnesen <redacted>
---
tools/net/ynl/pyynl/ynl_gen_c.py | 5 +++++
1 file changed, 5 insertions(+)
From: Donald Hunter <donald.hunter@gmail.com> Date: 2025-09-05 10:53:57
Asbjørn Sloth Tønnesen [off-list ref] writes:
Allow using custom name-prefix with constants,
just like it is for enum and flags declarations.
This is needed for generating WG_KEY_LEN in
include/uapi/linux/wireguard.h from a spec.
Signed-off-by: Asbjørn Sloth Tønnesen <redacted>
Reviewed-by: Donald Hunter <donald.hunter@gmail.com>
From: Donald Hunter <donald.hunter@gmail.com> Date: 2025-09-05 10:53:59
Asbjørn Sloth Tønnesen [off-list ref] writes:
This patch adds support for NLA_POLICY_NESTED_ARRAY() policies.
Example spec (from future wireguard.yaml):
-
name: wgpeer
attributes:
-
name: allowedips
type: indexed-array
sub-type: nest
nested-attributes: wgallowedip
yields NLA_POLICY_NESTED_ARRAY(wireguard_wgallowedip_nl_policy).
This doesn't change any currently generated code, as it isn't
used in any specs currently used for generating code.
Signed-off-by: Asbjørn Sloth Tønnesen <redacted>
Reviewed-by: Donald Hunter <donald.hunter@gmail.com>
From: Donald Hunter <donald.hunter@gmail.com> Date: 2025-09-05 10:54:00
Asbjørn Sloth Tønnesen [off-list ref] writes:
Add a check to verify that the sub-type is "nest", and throw an
exception if no policy could be generated, as a guard to prevent
against generating a bad policy.
This is a trivial patch with no behavioural changes intended.
Signed-off-by: Asbjørn Sloth Tønnesen <redacted>
Reviewed-by: Donald Hunter <donald.hunter@gmail.com>
From: Donald Hunter <donald.hunter@gmail.com> Date: 2025-09-05 10:54:02
Asbjørn Sloth Tønnesen [off-list ref] writes:
In wireguard_get_device_dump(), as generated by print_dump(),
it didn't generate a declaration of `unsigned int i`:
$ make -C tools/net/ynl/generated wireguard-user.o
-e CC wireguard-user.o
wireguard-user.c: In function ‘wireguard_get_device_dump’:
wireguard-user.c:502:22: error: ‘i’ undeclared (first use in this fn)
502 | for (i = 0; i < req->_count.peers; i++)
| ^
Copy the logic from print_req() as it correctly generated the
iterator in wireguard_set_device().
Signed-off-by: Asbjørn Sloth Tønnesen <redacted>
Reviewed-by: Donald Hunter <donald.hunter@gmail.com>
From: Donald Hunter <donald.hunter@gmail.com> Date: 2025-09-05 10:54:03
Asbjørn Sloth Tønnesen [off-list ref] writes:
Instead of trying to define "struct nlattr *array;" in the all
the right places, then simply define it in a block scope,
as it's only used here.
Before this patch it was generated for attribute set _put()
functions, like wireguard_wgpeer_put(), but missing and caused a
compile error for the command function wireguard_set_device().
$ make -C tools/net/ynl/generated wireguard-user.o
-e CC wireguard-user.o
wireguard-user.c: In function ‘wireguard_set_device’:
wireguard-user.c:548:9: error: ‘array’ undeclared (first use in ..)
548 | array = ynl_attr_nest_start(nlh, WGDEVICE_A_PEERS);
| ^~~~~
Signed-off-by: Asbjørn Sloth Tønnesen <redacted>
Reviewed-by: Donald Hunter <donald.hunter@gmail.com>
From: Donald Hunter <donald.hunter@gmail.com> Date: 2025-09-05 10:54:05
Asbjørn Sloth Tønnesen [off-list ref] writes:
As TypeArrayNest can now be used with many other sub-types
than nest, then rename it to TypeIndexedArray, to reduce
confusion.
This is a trivial patch with no behavioural changes intended.
Signed-off-by: Asbjørn Sloth Tønnesen <redacted>
Reviewed-by: Donald Hunter <donald.hunter@gmail.com>
From: Donald Hunter <donald.hunter@gmail.com> Date: 2025-09-05 10:54:06
Asbjørn Sloth Tønnesen [off-list ref] writes:
This patch moves nest packing into a helper function,
that can also be used for packing indexed arrays.
No behavioural changes intended.
Signed-off-by: Asbjørn Sloth Tønnesen <redacted>
Reviewed-by: Donald Hunter <donald.hunter@gmail.com>
@@ -564,6 +564,11 @@ class YnlFamily(SpecFamily):nl_type|=Netlink.NLA_F_NESTEDsub_space=attr['nested-attributes']attr_payload=self._add_nest_attrs(value,sub_space,search_attrs)+elifattr['type']=='indexed-array'andattr['sub-type']=='nest':+nl_type|=Netlink.NLA_F_NESTED+sub_space=attr['nested-attributes']+attr_payload=self._encode_indexed_array(value,sub_space,+search_attrs)elifattr["type"]=='flag':ifnotvalue:# If value is absent or false then skip attribute creation.
@@ -617,6 +622,9 @@ class YnlFamily(SpecFamily):else:raiseException(f'Unknown type at {space}{name}{value}{attr["type"]}')+returnself._add_attr_raw(nl_type,attr_payload)++def_add_attr_raw(self,nl_type,attr_payload):pad=b'\x00'*((4-len(attr_payload)%4)%4)returnstruct.pack('HH',len(attr_payload)+4,nl_type)+attr_payload+pad
@@ -628,6 +636,15 @@ class YnlFamily(SpecFamily):sub_attrs)returnattr_payload+def_encode_indexed_array(self,vals,sub_space,search_attrs):+attr_payload=b''+nested_flag=Netlink.NLA_F_NESTED
This line is not doing anything, right?
+ for i, val in enumerate(vals):
+ idx = i | Netlink.NLA_F_NESTED
+ val_payload = self._add_nest_attrs(val, sub_space, search_attrs)
+ attr_payload += self._add_attr_raw(idx, val_payload)
+ return attr_payload
+
def _get_enum_or_unknown(self, enum, raw):
try:
name = enum.entries_by_val[raw].name
From: Donald Hunter <donald.hunter@gmail.com> Date: 2025-09-05 10:54:09
Asbjørn Sloth Tønnesen [off-list ref] writes:
This patch add support for decoding hex input, so
that binary attributes can be read through --json.
Example (using future wireguard.yaml):
$ sudo ./tools/net/ynl/pyynl/cli.py --family wireguard \
--do set-device --json '{"ifindex":3,
"private-key":"2a ae 6c 35 c9 4f cf <... to 32 bytes>"}'
Signed-off-by: Asbjørn Sloth Tønnesen <redacted>
Reviewed-by: Donald Hunter <donald.hunter@gmail.com>
FWIW, the hex can include spaces or not when using bytes.fromhex(). When
formatting hex for output, I chose to include spaces, but I don't really
know if that was a good choice or not.
From: Donald Hunter <donald.hunter@gmail.com> Date: 2025-09-05 10:54:10
Asbjørn Sloth Tønnesen [off-list ref] writes:
The attribute WGALLOWEDIP_A_IPADDR can contain either an IPv4
or an IPv6 address depending on WGALLOWEDIP_A_FAMILY, however
in practice it is enough to look at the attribute length.
This patch implements an ipv4-or-v6 display hint, that can
deal with this kind of attribute.
It only implements this display hint for genetlink-legacy, it
can be added to other protocol variants if needed, but we don't
want to encourage it's use.
Signed-off-by: Asbjørn Sloth Tønnesen <redacted>
Reviewed-by: Donald Hunter <donald.hunter@gmail.com>
I suspect there are occurrences of ipv4 or ipv6 in the existing specs
that really should be ipv4-or-ipv6 but the python code doesn't care.
@@ -564,6 +564,11 @@ class YnlFamily(SpecFamily):nl_type|=Netlink.NLA_F_NESTEDsub_space=attr['nested-attributes']attr_payload=self._add_nest_attrs(value,sub_space,search_attrs)+elifattr['type']=='indexed-array'andattr['sub-type']=='nest':+nl_type|=Netlink.NLA_F_NESTED+sub_space=attr['nested-attributes']+attr_payload=self._encode_indexed_array(value,sub_space,+search_attrs)elifattr["type"]=='flag':ifnotvalue:# If value is absent or false then skip attribute creation.
@@ -617,6 +622,9 @@ class YnlFamily(SpecFamily):else:raiseException(f'Unknown type at {space}{name}{value}{attr["type"]}')+returnself._add_attr_raw(nl_type,attr_payload)++def_add_attr_raw(self,nl_type,attr_payload):pad=b'\x00'*((4-len(attr_payload)%4)%4)returnstruct.pack('HH',len(attr_payload)+4,nl_type)+attr_payload+pad
@@ -628,6 +636,15 @@ class YnlFamily(SpecFamily):sub_attrs)returnattr_payload+def_encode_indexed_array(self,vals,sub_space,search_attrs):+attr_payload=b''+nested_flag=Netlink.NLA_F_NESTED
This line is not doing anything, right?
Right, that line shouldn't be there, it is a remain of an early version, where
I didn't add the indexes, as NLA_NESTED_ARRAY is actually an unindexed-array.
The wireguard kernel code only sends zero types, and it doesn't care that user-
space sends an indexed array back, eg. when setting multiple allowed ips.
quoted
+ for i, val in enumerate(vals):
+ idx = i | Netlink.NLA_F_NESTED
+ val_payload = self._add_nest_attrs(val, sub_space, search_attrs)
+ attr_payload += self._add_attr_raw(idx, val_payload)
+ return attr_payload
+
def _get_enum_or_unknown(self, enum, raw):
try:
name = enum.entries_by_val[raw].name
Allow using custom name-prefix with constants,
just like it is for enum and flags declarations.
This is needed for generating WG_KEY_LEN in
include/uapi/linux/wireguard.h from a spec.
This patch adds support for NLA_POLICY_NESTED_ARRAY() policies.
Example spec (from future wireguard.yaml):
-
name: wgpeer
attributes:
-
name: allowedips
type: indexed-array
sub-type: nest
nested-attributes: wgallowedip
yields NLA_POLICY_NESTED_ARRAY(wireguard_wgallowedip_nl_policy).
This doesn't change any currently generated code, as it isn't
used in any specs currently used for generating code.
Add a check to verify that the sub-type is "nest", and throw an
exception if no policy could be generated, as a guard to prevent
against generating a bad policy.
This is a trivial patch with no behavioural changes intended.
I _think_ the expectation was that one of the other methods which
validate the types more thoroughly has to be called if this one is.
But either way:
Reviewed-by: Jakub Kicinski <kuba@kernel.org>
In wireguard_get_device_dump(), as generated by print_dump(),
it didn't generate a declaration of `unsigned int i`:
$ make -C tools/net/ynl/generated wireguard-user.o
-e CC wireguard-user.o
wireguard-user.c: In function ‘wireguard_get_device_dump’:
wireguard-user.c:502:22: error: ‘i’ undeclared (first use in this fn)
502 | for (i = 0; i < req->_count.peers; i++)
| ^
Copy the logic from print_req() as it correctly generated the
iterator in wireguard_set_device().
From: Jacob Keller <jacob.e.keller@intel.com> Date: 2025-09-06 00:16:00
On 9/4/2025 3:01 PM, Asbjørn Sloth Tønnesen wrote:
quoted hunk
Allow using custom name-prefix with constants,
just like it is for enum and flags declarations.
This is needed for generating WG_KEY_LEN in
include/uapi/linux/wireguard.h from a spec.
Signed-off-by: Asbjørn Sloth Tønnesen <redacted>
---
tools/net/ynl/pyynl/ynl_gen_c.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
Previously we always used "{family.ident_name}-", but now we get the
name-prefix and use that, falling back to the default if it doesn't
exist. Good.
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
defines.append([c_upper(family.get('c-define-name',
- f"{family.ident_name}-{const['name']}")),
+ f"{name_pfx}{const['name']}")),
const['value']])
if defines:
Instead of trying to define "struct nlattr *array;" in the all
the right places, then simply define it in a block scope,
as it's only used here.
Before this patch it was generated for attribute set _put()
functions, like wireguard_wgpeer_put(), but missing and caused a
compile error for the command function wireguard_set_device().
$ make -C tools/net/ynl/generated wireguard-user.o
-e CC wireguard-user.o
wireguard-user.c: In function ‘wireguard_set_device’:
wireguard-user.c:548:9: error: ‘array’ undeclared (first use in ..)
548 | array = ynl_attr_nest_start(nlh, WGDEVICE_A_PEERS);
| ^~~~~
Dunno about this one. In patch 4 you basically add another instance of
the "let's declare local vars at function level" approach. And here
you're going the other way. This patch will certainly work, but I felt
like I wouldn't have written it this way if I was typing in the parsers
by hand.
From: Jacob Keller <jacob.e.keller@intel.com> Date: 2025-09-06 00:19:38
On 9/4/2025 3:01 PM, Asbjørn Sloth Tønnesen wrote:
This patch adds support for NLA_POLICY_NESTED_ARRAY() policies.
Example spec (from future wireguard.yaml):
-
name: wgpeer
attributes:
-
name: allowedips
type: indexed-array
sub-type: nest
nested-attributes: wgallowedip
yields NLA_POLICY_NESTED_ARRAY(wireguard_wgallowedip_nl_policy).
This doesn't change any currently generated code, as it isn't
used in any specs currently used for generating code.
Signed-off-by: Asbjørn Sloth Tønnesen <redacted>
---
Is this keyed of off the sub-type? Does you mean that all the existing
uses of 'sub-type: nest' don't generate code today? Or that this
_attr_policy implementation is not called yet?
I checked and we have quite a number of uses:
From: Jacob Keller <jacob.e.keller@intel.com> Date: 2025-09-06 00:20:27
On 9/4/2025 3:01 PM, Asbjørn Sloth Tønnesen wrote:
Add a check to verify that the sub-type is "nest", and throw an
exception if no policy could be generated, as a guard to prevent
against generating a bad policy.
This is a trivial patch with no behavioural changes intended.
quoted
Signed-off-by: Asbjørn Sloth Tønnesen <redacted>
---
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
From: Jacob Keller <jacob.e.keller@intel.com> Date: 2025-09-06 00:21:04
On 9/4/2025 3:01 PM, Asbjørn Sloth Tønnesen wrote:
In wireguard_get_device_dump(), as generated by print_dump(),
it didn't generate a declaration of `unsigned int i`:
$ make -C tools/net/ynl/generated wireguard-user.o
-e CC wireguard-user.o
wireguard-user.c: In function ‘wireguard_get_device_dump’:
wireguard-user.c:502:22: error: ‘i’ undeclared (first use in this fn)
502 | for (i = 0; i < req->_count.peers; i++)
| ^
Copy the logic from print_req() as it correctly generated the
iterator in wireguard_set_device().
Signed-off-by: Asbjørn Sloth Tønnesen <redacted>
---
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
In nested arrays don't require that the intermediate
attribute type should be a valid attribute type, it
might just be an index or simple 0, it is often not
even used.
See include/net/netlink.h about NLA_NESTED_ARRAY:
quoted
The difference to NLA_NESTED is the structure:
NLA_NESTED has the nested attributes directly inside
while an array has the nested attributes at another
level down and the attribute types directly in the
nesting don't matter.
I don't understand, please provide more details.
This is an ArrayNest, right?
[ARRAY-ATTR]
[ENTRY]
[MEMBER1]
[MEMBER2]
[ENTRY]
[MEMBER1]
[MEMBER2]
Which level are you saying doesn't matter?
If entry is a nest it must be a valid nest.
What the comment you're quoting is saying is that the nla_type of ENTRY
doesn't matter.
From: Jacob Keller <jacob.e.keller@intel.com> Date: 2025-09-06 00:24:07
On 9/4/2025 3:01 PM, Asbjørn Sloth Tønnesen wrote:
In nested arrays don't require that the intermediate
attribute type should be a valid attribute type, it
might just be an index or simple 0, it is often not
even used.
See include/net/netlink.h about NLA_NESTED_ARRAY:
quoted
The difference to NLA_NESTED is the structure:
NLA_NESTED has the nested attributes directly inside
while an array has the nested attributes at another
level down and the attribute types directly in the
nesting don't matter.
To me, it would seem like it makes more sense to define these (even if
thats defined per family?) than to just say they aren't defined at all?
Hm.
From: Jacob Keller <jacob.e.keller@intel.com> Date: 2025-09-06 00:27:59
On 9/5/2025 3:51 AM, Donald Hunter wrote:
Asbjørn Sloth Tønnesen [off-list ref] writes:
quoted
This patch add support for decoding hex input, so
that binary attributes can be read through --json.
Example (using future wireguard.yaml):
$ sudo ./tools/net/ynl/pyynl/cli.py --family wireguard \
--do set-device --json '{"ifindex":3,
"private-key":"2a ae 6c 35 c9 4f cf <... to 32 bytes>"}'
Signed-off-by: Asbjørn Sloth Tønnesen <redacted>
Reviewed-by: Donald Hunter <donald.hunter@gmail.com>
FWIW, the hex can include spaces or not when using bytes.fromhex(). When
formatting hex for output, I chose to include spaces, but I don't really
know if that was a good choice or not.
Instead of trying to define "struct nlattr *array;" in the all
the right places, then simply define it in a block scope,
as it's only used here.
Before this patch it was generated for attribute set _put()
functions, like wireguard_wgpeer_put(), but missing and caused a
compile error for the command function wireguard_set_device().
$ make -C tools/net/ynl/generated wireguard-user.o
-e CC wireguard-user.o
wireguard-user.c: In function ‘wireguard_set_device’:
wireguard-user.c:548:9: error: ‘array’ undeclared (first use in ..)
548 | array = ynl_attr_nest_start(nlh, WGDEVICE_A_PEERS);
| ^~~~~
Dunno about this one. In patch 4 you basically add another instance of
the "let's declare local vars at function level" approach. And here
you're going the other way. This patch will certainly work, but I felt
like I wouldn't have written it this way if I was typing in the parsers
by hand.
Thanks for the reviews.
In patch 4, it is about a variable used by multiple Type classes having
presence_type() = 'count', which is currently 3 classes:
- TypeBinaryScalarArray
- TypeMultiAttr
- TypeArrayNest (later renamed to TypeIndexedArray)
In patch 5, I move code for a special variable used by one Type class,
to be contained within that class. It makes it easier to ensure that the
variable is only defined, when used, and vice versa. This comes at the
cost of the generated code looking generated.
If we should make the generated code look like it was written by humans,
then I would move the definition of these local variables into a class
method, so `i` can be generated by the generic implementation, and `array`
can be implemented in it's class. I will take a stab at this, but it might
be too much refactoring for this series, eg. `len` is also defined local
to conditional blocks multiple branches in a row.
tools/net/ynl/generated/nl80211-user.c:
nl80211_iftype_data_attrs_parse(..) {
[..]
ynl_attr_for_each_nested(attr, nested) {
unsigned int type = ynl_attr_type(attr);
if (type == NL80211_BAND_IFTYPE_ATTR_IFTYPES) {
unsigned int len;
[..]
} else if (type == NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC) {
unsigned int len;
[..]
[same pattern 8 times, so 11 times in total]
} else if (type == NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE) {
unsigned int len;
[..]
}
}
return 0;
}
(I didn't have to search for this, I saw the pattern in wireguard-user.c,
looked for it in nl80211-user.c and this was the first `len` usage there.)
That looks very generated, I would have `len` defined together with `type`,
and a switch statement would also look a lot more natural, but maybe leave
the if->switch conversion for the compiler to detect.
In nested arrays don't require that the intermediate
attribute type should be a valid attribute type, it
might just be an index or simple 0, it is often not
even used.
See include/net/netlink.h about NLA_NESTED_ARRAY:
quoted
The difference to NLA_NESTED is the structure:
NLA_NESTED has the nested attributes directly inside
while an array has the nested attributes at another
level down and the attribute types directly in the
nesting don't matter.
I don't understand, please provide more details.
This is an ArrayNest, right?
[ARRAY-ATTR]
[ENTRY]
[MEMBER1]
[MEMBER2]
[ENTRY]
[MEMBER1]
[MEMBER2]
Which level are you saying doesn't matter?
If entry is a nest it must be a valid nest.
What the comment you're quoting is saying is that the nla_type of ENTRY
doesn't matter.
I will expand this in v2, but the gist of it is that this is part of the
"split attribute counting, and later allocating an array to hold them" code.
The check that I remove for nested arrays, is an early exit during the
counting phase. Later in the allocation and parse phase it validates the
nested payload.
In include/uapi/linux/wireguard.h:
> WGDEVICE_A_PEERS: NLA_NESTED
> 0: NLA_NESTED
> WGPEER_A_PUBLIC_KEY: NLA_EXACT_LEN, len WG_KEY_LEN
> [..]
> 0: NLA_NESTED
> ...
> ...
The current check requires that the nested type is valid in the nested
attribute set, which in this case resolves to WGDEVICE_A_UNSPEC, which is
YNL_PT_REJECT, and it takes the early exit and returns YNL_PARSE_CB_ERROR.
CC: Johannes
On 9/6/25 12:19 AM, Jacob Keller wrote:
On 9/4/2025 3:01 PM, Asbjørn Sloth Tønnesen wrote:
quoted
This patch adds support for NLA_POLICY_NESTED_ARRAY() policies.
Example spec (from future wireguard.yaml):
-
name: wgpeer
attributes:
-
name: allowedips
type: indexed-array
sub-type: nest
nested-attributes: wgallowedip
yields NLA_POLICY_NESTED_ARRAY(wireguard_wgallowedip_nl_policy).
This doesn't change any currently generated code, as it isn't
used in any specs currently used for generating code.
Signed-off-by: Asbjørn Sloth Tønnesen <redacted>
---
Is this keyed of off the sub-type? Does you mean that all the existing
uses of 'sub-type: nest' don't generate code today? Or that this
_attr_policy implementation is not called yet?
Thanks for the reviews. Yeah, it is a careful wording, because we have
specs matching it, but there aren't any source files that triggers
ynl-gen to generate code based on those specs.
Therefore this patch, doesn't result in any code changes when running:
$ ./tools/net/ynl/ynl-regen.sh -f
Actually ynl-gen generates a fictive "{ .type = NLA_INDEXED_ARRAY, }"
policy, without this patch, leading to a build failure.
None of those currently have a generated netlink policy.
These are the netlink policies currently generated by ynl-gen:
$ git grep -h -B1 'YNL-GEN kernel source' | grep '^/\*[^ ]'
/* Documentation/netlink/specs/dpll.yaml */
/* Documentation/netlink/specs/ovpn.yaml */
/* Documentation/netlink/specs/team.yaml */
/* Documentation/netlink/specs/lockd.yaml */
/* Documentation/netlink/specs/nfsd.yaml */
/* Documentation/netlink/specs/netdev.yaml */
/* Documentation/netlink/specs/devlink.yaml */
/* Documentation/netlink/specs/handshake.yaml */
/* Documentation/netlink/specs/fou.yaml */
/* Documentation/netlink/specs/mptcp_pm.yaml */
/* Documentation/netlink/specs/net_shaper.yaml */
Johannes introduced NLA_NESTED_ARRAY and the NLA_POLICY_NESTED_ARRAY()
macro in commit 1501d13596b9 for use in nl80211, and it's therefore
used in net/wireless/nl80211.c, but outside of that the macro is
only sparsely adopted (only by mac80211_hwsim.c and nf_tables_api.c).
Wireguard adopts the macro in this RFC patch:
https://lore.kernel.org/netdev/20250904220255.1006675-2-ast@fiberby.net/
This patch add support for decoding hex input, so
that binary attributes can be read through --json.
Example (using future wireguard.yaml):
$ sudo ./tools/net/ynl/pyynl/cli.py --family wireguard \
--do set-device --json '{"ifindex":3,
"private-key":"2a ae 6c 35 c9 4f cf <... to 32 bytes>"}'
Signed-off-by: Asbjørn Sloth Tønnesen <redacted>
Reviewed-by: Donald Hunter <donald.hunter@gmail.com>
FWIW, the hex can include spaces or not when using bytes.fromhex(). When
formatting hex for output, I chose to include spaces, but I don't really
know if that was a good choice or not.
I also prefer the spaces for readability.
I formatted it with spaces for clarity, even without spaces it was a bit
long for one line. Spaces also has the advantage that you don't have to
think about endianness.
Should we define the display hints a bit more in a .rst, or is it OK that
they end up being implementation specific for each language library? Do we
want them to behave the same in a Rust YNL library, as they do in Python?
BTW: The rest of the key used in the example can be found with this key-gen:
$ printf "hello world" | sha1sum
[redacted key material]
CC: Johannes
On 9/6/25 12:24 AM, Jacob Keller wrote:
On 9/4/2025 3:01 PM, Asbjørn Sloth Tønnesen wrote:
quoted
In nested arrays don't require that the intermediate
attribute type should be a valid attribute type, it
might just be an index or simple 0, it is often not
even used.
See include/net/netlink.h about NLA_NESTED_ARRAY:
quoted
The difference to NLA_NESTED is the structure:
NLA_NESTED has the nested attributes directly inside
while an array has the nested attributes at another
level down and the attribute types directly in the
nesting don't matter.
To me, it would seem like it makes more sense to define these (even if
thats defined per family?) than to just say they aren't defined at all?
Hm.
I considered adding some of that metadata too, as I am actually removing
it for wireguard (in comment form, but still).
In include/uapi/linux/wireguard.h in the comment block at the top, it is
very clear that wireguard only used type 0 for all the nested array
entries, however the truth is that it doesn't care. It therefore doesn't
matter if the generated -user.* keeps track of the index in .idx, or that
cli.py decodes a JSON array and sends it with indexes, it's not needed,
but it still works.
In practice I don't think we will break any clients if we enforced it, and
validated that wireguard only accepts type 0 entries, in it's nested arrays.
For the other families, I don't know how well defined it is, Johannes have
stated that nl80211 doesn't care which types are used, but I have no idea
how consistent clients have abused that statement to send random data,
or do they all just send zeros?
This would make a lot more sense if 'array-nest' hadn't been renamed to
'indexed-array' in ynl, because it feels wrong to add 'unindexed: true' now.
We could also call it 'all-zero-indexed: true'.
In cli.py this gives some extra issues, as seen in [1], the nested arrays
are outputted as '[{0: {..}}, {0: {..}}, ..]', but on input has the format
'[{..},{..}, ..]' because it has to be JSON-compatible on input.
If we had an attribute like 'all-zero-indexed' then cli.py, could also output
'[{..},{..}, ..]'.
[1] https://lore.kernel.org/netdev/20250904220255.1006675-3-ast@fiberby.net/
The attribute WGALLOWEDIP_A_IPADDR can contain either an IPv4
or an IPv6 address depending on WGALLOWEDIP_A_FAMILY, however
in practice it is enough to look at the attribute length.
This patch implements an ipv4-or-v6 display hint, that can
deal with this kind of attribute.
It only implements this display hint for genetlink-legacy, it
can be added to other protocol variants if needed, but we don't
want to encourage it's use.
Signed-off-by: Asbjørn Sloth Tønnesen <redacted>
Reviewed-by: Donald Hunter <donald.hunter@gmail.com>
I suspect there are occurrences of ipv4 or ipv6 in the existing specs
that really should be ipv4-or-ipv6 but the python code doesn't care.
I haven't been able to find any, containing 'ip' or 'addr'.
Speaking of display hints, then WGPEER_A_ENDPOINT is another interesting
case, it is struct sockaddr_in or struct sockaddr_in6, I have left that
as a plain binary for now, but maybe that could be a struct map, based
on struct length.
attribute-sets:
-
name: wgpeer
[..]
attributes:
[..]
-
name: endpoint
type: binary
struct-map:
- sockaddr_in
- sockaddr_in6
With the requirement being, that all structs must have a unique length.
In patch 4, it is about a variable used by multiple Type classes having
presence_type() = 'count', which is currently 3 classes:
- TypeBinaryScalarArray
- TypeMultiAttr
- TypeArrayNest (later renamed to TypeIndexedArray)
In patch 5, I move code for a special variable used by one Type class,
to be contained within that class. It makes it easier to ensure that the
variable is only defined, when used, and vice versa. This comes at the
cost of the generated code looking generated.
So you're agreeing?
If we should make the generated code look like it was written by humans,
then I would move the definition of these local variables into a class
method, so `i` can be generated by the generic implementation, and `array`
can be implemented in it's class. I will take a stab at this, but it might
be too much refactoring for this series, eg. `len` is also defined local
to conditional blocks multiple branches in a row.
tools/net/ynl/generated/nl80211-user.c:
nl80211_iftype_data_attrs_parse(..) {
[..]
ynl_attr_for_each_nested(attr, nested) {
unsigned int type = ynl_attr_type(attr);
if (type == NL80211_BAND_IFTYPE_ATTR_IFTYPES) {
unsigned int len;
[..]
} else if (type == NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC) {
unsigned int len;
[..]
[same pattern 8 times, so 11 times in total]
} else if (type == NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE) {
unsigned int len;
[..]
}
}
return 0;
}
It's pretty easily doable, I already gave up on not calling _attr_get()
for sub-messages.
That looks very generated, I would have `len` defined together with `type`,
and a switch statement would also look a lot more natural, but maybe leave
the if->switch conversion for the compiler to detect.
@@ -243,7 +243,7 @@ from lib import SpecSubMessage, SpecSubMessageFormatraiseException(f"Attr get not implemented for class type {self.type}")defattr_get(self,ri,var,first):-lines,init_lines,local_vars=self._attr_get(ri,var)+lines,init_lines,_=self._attr_get(ri,var)iftype(lines)isstr:lines=[lines]iftype(init_lines)isstr:
I don't understand, please provide more details.
This is an ArrayNest, right?
[ARRAY-ATTR]
[ENTRY]
[MEMBER1]
[MEMBER2]
[ENTRY]
[MEMBER1]
[MEMBER2]
Which level are you saying doesn't matter?
If entry is a nest it must be a valid nest.
What the comment you're quoting is saying is that the nla_type of ENTRY
doesn't matter.
I will expand this in v2, but the gist of it is that this is part of the
"split attribute counting, and later allocating an array to hold them" code.
The check that I remove for nested arrays, is an early exit during the
counting phase. Later in the allocation and parse phase it validates the
nested payload.
In include/uapi/linux/wireguard.h:
> WGDEVICE_A_PEERS: NLA_NESTED
> 0: NLA_NESTED
> WGPEER_A_PUBLIC_KEY: NLA_EXACT_LEN, len WG_KEY_LEN
> [..]
> 0: NLA_NESTED
> ...
> ...
The current check requires that the nested type is valid in the nested
attribute set, which in this case resolves to WGDEVICE_A_UNSPEC, which is
YNL_PT_REJECT, and it takes the early exit and returns YNL_PARSE_CB_ERROR.
I see your point now. We're validating ENTRY as an attribute in the
parent attribute set, but it's just a meaningless id.
I think we need more fixing here. The real parsing loop will only
validate what's _inside_ the [MEMBER]. Which doesn't matter all
that much to nests, but look at what happens if subtype is a scalar.
We'll just call ynl_attr_get_u32(), type is never really validate.
I think we need this, and make the codegen feed in the ARRAY-ATTR type
to validate ENTRY?
From: Johannes Berg <johannes@sipsolutions.net> Date: 2025-09-08 07:54:23
On Sat, 2025-09-06 at 14:13 +0000, Asbjørn Sloth Tønnesen wrote:
Johannes introduced NLA_NESTED_ARRAY and the NLA_POLICY_NESTED_ARRAY()
macro in commit 1501d13596b9 for use in nl80211, and it's therefore
used in net/wireless/nl80211.c, but outside of that the macro is
only sparsely adopted (only by mac80211_hwsim.c and nf_tables_api.c).
Wireguard adopts the macro in this RFC patch:
https://lore.kernel.org/netdev/20250904220255.1006675-2-ast@fiberby.net/
I think the general consensus now is that preference should be towards
arrays being expressed by giving the attribute holding the array
multiple times, i.e. each occurrence of an attribute holds a single
entry of the array:
[header][type1:a1][type2:b][type1:a2][type1:a3]
resulting in an array
[a1, a2, a3] and a separate value "b",
rather than a nested array:
[header][type1:[1:a1][2:a2][3:a3]][type2:b]
Of course if each entry has multiple values, then you'd still need
nesting:
[header][type1:[subtype1:x1][subtype2:x2]][type1:[subtype1:y1][subtype2:y2]]
would be an array
[[x1, x2], [y1, y2]].
I can't get rid of the nested array types in nl80211 though, of course.
I'm not sure the nl80211 ynl code was ever merged, but it wasn't
authoritative anyway, just for some limited userspace generation, so I'm
not sure the whole ynl handling this is needed at all?
johannes
From: Johannes Berg <johannes@sipsolutions.net> Date: 2025-09-08 07:55:42
On Sat, 2025-09-06 at 15:10 +0000, Asbjørn Sloth Tønnesen wrote:
For the other families, I don't know how well defined it is, Johannes have
stated that nl80211 doesn't care which types are used, but I have no idea
how consistent clients have abused that statement to send random data,
or do they all just send zeros?
I think most clients probably send incrementing numbers (1, 2, 3, ...),
but maybe some start at 0, some sometimes might use band numbers and
thus have sparse values, etc.
But as I just wrote, I'm not really sure it should be used at all.
joahnnes
On Sat, 2025-09-06 at 14:13 +0000, Asbjørn Sloth Tønnesen wrote:
quoted
Johannes introduced NLA_NESTED_ARRAY and the NLA_POLICY_NESTED_ARRAY()
macro in commit 1501d13596b9 for use in nl80211, and it's therefore
used in net/wireless/nl80211.c, but outside of that the macro is
only sparsely adopted (only by mac80211_hwsim.c and nf_tables_api.c).
Wireguard adopts the macro in this RFC patch:
https://lore.kernel.org/netdev/20250904220255.1006675-2-ast@fiberby.net/
> I think the general consensus now is that preference should be towards
> arrays being expressed by giving the attribute holding the array
> multiple times, i.e. each occurrence of an attribute holds a single
> entry of the array:
>
> [header][type1:a1][type2:b][type1:a2][type1:a3]
>
> resulting in an array
>
> [a1, a2, a3] and a separate value "b",
>
> rather than a nested array:
>
> [header][type1:[1:a1][2:a2][3:a3]][type2:b]
>
>
> Of course if each entry has multiple values, then you'd still need
> nesting:
>
> [header][type1:[subtype1:x1][subtype2:x2]][type1:[subtype1:y1][subtype2:y2]]
>
> would be an array
>
> [[x1, x2], [y1, y2]].
Thank you for the consensus write up. Should we prohibit indexed-array with sub-type
nest for families with a genetlink protocol?
It is currently only used in families with a netlink-raw or genetlink-legacy protocol.
I can't get rid of the nested array types in nl80211 though, of course.
Wireguard is already in the same boat. It is not using the term, nor the policy,
but it is doing the validation in the handler through, so it can adopt a
NLA_POLICY_NESTED_ARRAY() policy, instead of a plain '{ .type = NLA_NESTED }'.
Comments on the protocol in include/uapi/linux/wireguard.h:
> WGDEVICE_A_PEERS: NLA_NESTED
> 0: NLA_NESTED
> WGPEER_A_PUBLIC_KEY: NLA_EXACT_LEN, len WG_KEY_LEN
> [..]
> 0: NLA_NESTED
> ...
> ...
Given that, as Jacob pointed out, there are more families with nested arrays in
their YNL spec, than those using NLA_NESTED_ARRAY, then it appears that there
are more families already in the boat.
From: Donald Hunter <donald.hunter@gmail.com> Date: 2025-09-08 10:35:05
Asbjørn Sloth Tønnesen [off-list ref] writes:
On 9/6/25 12:27 AM, Jacob Keller wrote:
quoted
On 9/5/2025 3:51 AM, Donald Hunter wrote:
quoted
Asbjørn Sloth Tønnesen [off-list ref] writes:
quoted
This patch add support for decoding hex input, so
that binary attributes can be read through --json.
Example (using future wireguard.yaml):
$ sudo ./tools/net/ynl/pyynl/cli.py --family wireguard \
--do set-device --json '{"ifindex":3,
"private-key":"2a ae 6c 35 c9 4f cf <... to 32 bytes>"}'
Signed-off-by: Asbjørn Sloth Tønnesen <redacted>
Reviewed-by: Donald Hunter <donald.hunter@gmail.com>
FWIW, the hex can include spaces or not when using bytes.fromhex(). When
formatting hex for output, I chose to include spaces, but I don't really
know if that was a good choice or not.
I also prefer the spaces for readability.
I formatted it with spaces for clarity, even without spaces it was a bit
long for one line. Spaces also has the advantage that you don't have to
think about endianness.
Should we define the display hints a bit more in a .rst, or is it OK that
they end up being implementation specific for each language library? Do we
want them to behave the same in a Rust YNL library, as they do in Python?
From: Johannes Berg <johannes@sipsolutions.net> Date: 2025-09-08 13:22:53
On Mon, 2025-09-08 at 09:08 +0000, Asbjørn Sloth Tønnesen wrote:
Thank you for the consensus write up. Should we prohibit indexed-array with sub-type
nest for families with a genetlink protocol?
It is currently only used in families with a netlink-raw or genetlink-legacy protocol.
I have no strong opinion on that, but I guess maybe so? At least print
out a warning for anyone who's trying to add such a new thing perhaps,
so that new stuff that isn't just a port (to ynl) or annotation of
existing APIs doesn't add it.
quoted
I can't get rid of the nested array types in nl80211 though, of course.
Wireguard is already in the same boat. [...]
Oh, sorry. I didn't look at the linked patch and thought it was adding
such a new thing. Looking now, I see it just makes the policy validate
it instead of (only) doing it in the code. (FWIW, in the code you could
then also set the policy argument for nla_parse_nested() calls to NULL.)
Given that, as Jacob pointed out, there are more families with nested arrays in
their YNL spec, than those using NLA_NESTED_ARRAY, then it appears that there
are more families already in the boat.
@@ -973,6 +973,8 @@ class YnlFamily(SpecFamily):raw=ip.packedelse:raw=int(ip)+elifattr_spec.display_hint=='hex':+raw=bytes.fromhex(string)
I'm working on a spec for macsec and ended up with a similar change,
but doing instead:
+ elif attr_spec.display_hint == 'hex':
+ raw = int(string, 16)
since the destination attribute is u32/u64 and not binary for macsec.
So maybe this should be:
+ if attr_spec['type'] == 'binary':
+ raw = bytes.fromhex(string)
+ else:
+ raw = int(string, 16)
to cover both cases?
I think it matches better what's already in _formatted_string.
(I don't mind having the current patch go in and making this change
together with the macsec spec when it's ready)
else:
raise Exception(f"Display hint '{attr_spec.display_hint}' not implemented"
f" when parsing '{attr_spec['name']}'")
--
2.51.0
@@ -973,6 +973,8 @@ class YnlFamily(SpecFamily):raw=ip.packedelse:raw=int(ip)+elifattr_spec.display_hint=='hex':+raw=bytes.fromhex(string)
I'm working on a spec for macsec and ended up with a similar change,
but doing instead:
+ elif attr_spec.display_hint == 'hex':
+ raw = int(string, 16)
since the destination attribute is u32/u64 and not binary for macsec.
So maybe this should be:
+ if attr_spec['type'] == 'binary':
+ raw = bytes.fromhex(string)
+ else:
+ raw = int(string, 16)
to cover both cases?
I think it matches better what's already in _formatted_string.
(I don't mind having the current patch go in and making this change
together with the macsec spec when it's ready)
Cool, I will include it in v2, which I hope to get out tomorrow.
From: Jacob Keller <jacob.e.keller@intel.com> Date: 2025-09-09 23:03:05
On 9/6/2025 7:13 AM, Asbjørn Sloth Tønnesen wrote:
CC: Johannes
On 9/6/25 12:19 AM, Jacob Keller wrote:
quoted
On 9/4/2025 3:01 PM, Asbjørn Sloth Tønnesen wrote:
quoted
This patch adds support for NLA_POLICY_NESTED_ARRAY() policies.
Example spec (from future wireguard.yaml):
-
name: wgpeer
attributes:
-
name: allowedips
type: indexed-array
sub-type: nest
nested-attributes: wgallowedip
yields NLA_POLICY_NESTED_ARRAY(wireguard_wgallowedip_nl_policy).
This doesn't change any currently generated code, as it isn't
used in any specs currently used for generating code.
Signed-off-by: Asbjørn Sloth Tønnesen <redacted>
---
Is this keyed of off the sub-type? Does you mean that all the existing
uses of 'sub-type: nest' don't generate code today? Or that this
_attr_policy implementation is not called yet?
Thanks for the reviews. Yeah, it is a careful wording, because we have
specs matching it, but there aren't any source files that triggers
ynl-gen to generate code based on those specs.
Ok. That's what I thought and just wanted to be certain, since I saw
several uses in the code. Thanks for explaining!
From: Jacob Keller <jacob.e.keller@intel.com> Date: 2025-09-10 16:58:48
On 9/6/2025 8:10 AM, Asbjørn Sloth Tønnesen wrote:
CC: Johannes
On 9/6/25 12:24 AM, Jacob Keller wrote:
quoted
On 9/4/2025 3:01 PM, Asbjørn Sloth Tønnesen wrote:
quoted
In nested arrays don't require that the intermediate
attribute type should be a valid attribute type, it
might just be an index or simple 0, it is often not
even used.
See include/net/netlink.h about NLA_NESTED_ARRAY:
quoted
The difference to NLA_NESTED is the structure:
NLA_NESTED has the nested attributes directly inside
while an array has the nested attributes at another
level down and the attribute types directly in the
nesting don't matter.
To me, it would seem like it makes more sense to define these (even if
thats defined per family?) than to just say they aren't defined at all?
Hm.
I considered adding some of that metadata too, as I am actually removing
it for wireguard (in comment form, but still).
In include/uapi/linux/wireguard.h in the comment block at the top, it is
very clear that wireguard only used type 0 for all the nested array
entries, however the truth is that it doesn't care. It therefore doesn't
matter if the generated -user.* keeps track of the index in .idx, or that
cli.py decodes a JSON array and sends it with indexes, it's not needed,
but it still works.
In practice I don't think we will break any clients if we enforced it, and
validated that wireguard only accepts type 0 entries, in it's nested arrays.
For the other families, I don't know how well defined it is, Johannes have
stated that nl80211 doesn't care which types are used, but I have no idea
how consistent clients have abused that statement to send random data,
or do they all just send zeros?
Changing it at this point could be a significant backwards compat break,
as some clients might somehow send data that wasn't zero-initialized,
and checking would break them. At this point I guess it makes sense to
leave it as is... It would increase code cost and complexity for no gain.
This would make a lot more sense if 'array-nest' hadn't been renamed to
'indexed-array' in ynl, because it feels wrong to add 'unindexed: true' now.
We could also call it 'all-zero-indexed: true'.
In cli.py this gives some extra issues, as seen in [1], the nested arrays
are outputted as '[{0: {..}}, {0: {..}}, ..]', but on input has the format
'[{..},{..}, ..]' because it has to be JSON-compatible on input.
If we had an attribute like 'all-zero-indexed' then cli.py, could also output
'[{..},{..}, ..]'.
This part would be cool. If we know the index is "uninteresting",
eliding it so that the input and output formats match is good.
In patch 4, it is about a variable used by multiple Type classes having
presence_type() = 'count', which is currently 3 classes:
- TypeBinaryScalarArray
- TypeMultiAttr
- TypeArrayNest (later renamed to TypeIndexedArray)
In patch 5, I move code for a special variable used by one Type class,
to be contained within that class. It makes it easier to ensure that the
variable is only defined, when used, and vice versa. This comes at the
cost of the generated code looking generated.
So you're agreeing?
quoted
If we should make the generated code look like it was written by humans,
then I would move the definition of these local variables into a class
method, so `i` can be generated by the generic implementation, and `array`
can be implemented in it's class. I will take a stab at this, but it might
be too much refactoring for this series, eg. `len` is also defined local
to conditional blocks multiple branches in a row.
tools/net/ynl/generated/nl80211-user.c:
nl80211_iftype_data_attrs_parse(..) {
[..]
ynl_attr_for_each_nested(attr, nested) {
unsigned int type = ynl_attr_type(attr);
if (type == NL80211_BAND_IFTYPE_ATTR_IFTYPES) {
unsigned int len;
[..]
} else if (type == NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC) {
unsigned int len;
[..]
[same pattern 8 times, so 11 times in total]
} else if (type == NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE) {
unsigned int len;
[..]
}
}
return 0;
}
It's pretty easily doable, I already gave up on not calling _attr_get()
for sub-messages.
quoted
That looks very generated, I would have `len` defined together with `type`,
and a switch statement would also look a lot more natural, but maybe leave
the if->switch conversion for the compiler to detect.
@@ -243,7 +243,7 @@ from lib import SpecSubMessage, SpecSubMessageFormatraiseException(f"Attr get not implemented for class type {self.type}")defattr_get(self,ri,var,first):-lines,init_lines,local_vars=self._attr_get(ri,var)+lines,init_lines,_=self._attr_get(ri,var)iftype(lines)isstr:lines=[lines]iftype(init_lines)isstr:
I left this for you to submit, there is a trivial conflict with patch 8
in my v2 posting.
Hah, no, please take this and submit as yours if you can. You can add
me as Suggested-by. I already dropped it form my tree.
Maintainers tend to throw random snippets of code at people, it's just
quicker than explaining but we have enough commits in our name..