Merge branch 'netlink-specs-add-a-spec-for-nl80211-wiphy'

Donald Hunter says:

====================
netlink: specs: add a spec for nl80211 wiphy

Add a rudimentary YNL spec for nl80211 that includes get-wiphy and
get-interface, along with some required enhancements to YNL and the
netlink schemas.

Patch 1 is a minor cleanup to prepare for patch 2
Patches 2-4 are new features for YNL
Patches 5-7 are updates to ynl_gen_c
Patches 8-9 are schema updates for feature parity
Patch 10 is the new nl80211 spec
====================

Link: https://patch.msgid.link/20250211120127.84858-1-donald.hunter@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski
2025-02-12 19:32:26 -08:00
7 changed files with 2063 additions and 21 deletions

View File

@@ -161,7 +161,7 @@ properties:
type: string
type: &attr-type
enum: [ unused, pad, flag, binary,
uint, sint, u8, u16, u32, u64, s32, s64,
uint, sint, u8, u16, u32, u64, s8, s16, s32, s64,
string, nest, indexed-array, nest-type-value ]
doc:
description: Documentation of the attribute.

View File

@@ -152,6 +152,9 @@ properties:
the right formatting mechanism when displaying values of this
type.
enum: [ hex, mac, fddi, ipv4, ipv6, uuid ]
struct:
description: Name of the nested struct type.
type: string
# End genetlink-legacy
attribute-sets:
@@ -204,7 +207,7 @@ properties:
type: &attr-type
description: The netlink attribute type
enum: [ unused, pad, flag, binary, bitfield32,
uint, sint, u8, u16, u32, u64, s32, s64,
uint, sint, u8, u16, u32, u64, s8, s16, s32, s64,
string, nest, indexed-array, nest-type-value ]
doc:
description: Documentation of the attribute.

View File

@@ -124,7 +124,7 @@ properties:
type: string
type: &attr-type
enum: [ unused, pad, flag, binary,
uint, sint, u8, u16, u32, u64, s32, s64,
uint, sint, u8, u16, u32, u64, s8, s16, s32, s64,
string, nest, indexed-array, nest-type-value ]
doc:
description: Documentation of the attribute.

File diff suppressed because it is too large Load Diff

View File

@@ -23,6 +23,7 @@ CFLAGS_handshake:=$(call get_hdr_inc,_LINUX_HANDSHAKE_H,handshake.h)
CFLAGS_mptcp_pm:=$(call get_hdr_inc,_LINUX_MPTCP_PM_H,mptcp_pm.h)
CFLAGS_net_shaper:=$(call get_hdr_inc,_LINUX_NET_SHAPER_H,net_shaper.h)
CFLAGS_netdev:=$(call get_hdr_inc,_LINUX_NETDEV_H,netdev.h)
CFLAGS_nl80211:=$(call get_hdr_inc,__LINUX_NL802121_H,nl80211.h)
CFLAGS_nlctrl:=$(call get_hdr_inc,__LINUX_GENERIC_NETLINK_H,genetlink.h)
CFLAGS_nfsd:=$(call get_hdr_inc,_LINUX_NFSD_NETLINK_H,nfsd_netlink.h)
CFLAGS_ovs_datapath:=$(call get_hdr_inc,__LINUX_OPENVSWITCH_H,openvswitch.h)

View File

@@ -536,9 +536,11 @@ class YnlFamily(SpecFamily):
try:
return int(value)
except (ValueError, TypeError) as e:
if 'enum' not in attr_spec:
raise e
return self._encode_enum(attr_spec, value)
if 'enum' in attr_spec:
return self._encode_enum(attr_spec, value)
if attr_spec.display_hint:
return self._from_string(value, attr_spec)
raise e
def _add_attr(self, space, name, value, search_attrs):
try:
@@ -571,7 +573,10 @@ class YnlFamily(SpecFamily):
if isinstance(value, bytes):
attr_payload = value
elif isinstance(value, str):
attr_payload = bytes.fromhex(value)
if attr.display_hint:
attr_payload = self._from_string(value, attr)
else:
attr_payload = bytes.fromhex(value)
elif isinstance(value, dict) and attr.struct_name:
attr_payload = self._encode_struct(attr.struct_name, value)
else:
@@ -627,6 +632,11 @@ class YnlFamily(SpecFamily):
decoded = self._decode_struct(attr.raw, attr_spec.struct_name)
elif attr_spec.sub_type:
decoded = attr.as_c_array(attr_spec.sub_type)
if 'enum' in attr_spec:
decoded = [ self._decode_enum(x, attr_spec) for x in decoded ]
elif attr_spec.display_hint:
decoded = [ self._formatted_string(x, attr_spec.display_hint)
for x in decoded ]
else:
decoded = attr.as_bin()
if attr_spec.display_hint:
@@ -644,15 +654,17 @@ class YnlFamily(SpecFamily):
subattrs = self._decode(NlAttrs(item.raw), attr_spec['nested-attributes'])
decoded.append({ item.type: subattrs })
elif attr_spec["sub-type"] == 'binary':
subattrs = item.as_bin()
subattr = item.as_bin()
if attr_spec.display_hint:
subattrs = self._formatted_string(subattrs, attr_spec.display_hint)
decoded.append(subattrs)
subattr = self._formatted_string(subattr, attr_spec.display_hint)
decoded.append(subattr)
elif attr_spec["sub-type"] in NlAttr.type_formats:
subattrs = item.as_scalar(attr_spec['sub-type'], attr_spec.byte_order)
if attr_spec.display_hint:
subattrs = self._formatted_string(subattrs, attr_spec.display_hint)
decoded.append(subattrs)
subattr = item.as_scalar(attr_spec['sub-type'], attr_spec.byte_order)
if 'enum' in attr_spec:
subattr = self._decode_enum(subattr, attr_spec)
elif attr_spec.display_hint:
subattr = self._formatted_string(subattr, attr_spec.display_hint)
decoded.append(subattr)
else:
raise Exception(f'Unknown {attr_spec["sub-type"]} with name {attr_spec["name"]}')
return decoded
@@ -899,6 +911,18 @@ class YnlFamily(SpecFamily):
formatted = raw
return formatted
def _from_string(self, string, attr_spec):
if attr_spec.display_hint in ['ipv4', 'ipv6']:
ip = ipaddress.ip_address(string)
if attr_spec['type'] == 'binary':
raw = ip.packed
else:
raw = int(ip)
else:
raise Exception(f"Display hint '{attr_spec.display_hint}' not implemented"
f" when parsing '{attr_spec['name']}'")
return raw
def handle_ntf(self, decoded):
msg = dict()
if self.include_raw:

View File

@@ -74,6 +74,8 @@ class Type(SpecAttr):
self.c_name = c_lower(self.name)
if self.c_name in _C_KW:
self.c_name += '_'
if self.c_name[0].isdigit():
self.c_name = '_' + self.c_name
# Added by resolve():
self.enum_name = None
@@ -686,7 +688,10 @@ class TypeArrayNest(Type):
raise Exception(f"Sub-type {self.attr['sub-type']} not supported yet")
def _attr_typol(self):
return f'.type = YNL_PT_NEST, .nest = &{self.nested_render_name}_nest, '
if self.attr['sub-type'] in scalars:
return f'.type = YNL_PT_U{c_upper(self.sub_type[1:])}, '
else:
return f'.type = YNL_PT_NEST, .nest = &{self.nested_render_name}_nest, '
def _attr_get(self, ri, var):
local_vars = ['const struct nlattr *attr2;']
@@ -888,7 +893,7 @@ class AttrSet(SpecAttrSet):
elif elem['type'] == 'nest':
t = TypeNest(self.family, self, elem, value)
elif elem['type'] == 'indexed-array' and 'sub-type' in elem:
if elem["sub-type"] == 'nest':
if elem["sub-type"] in ['nest', 'u32']:
t = TypeArrayNest(self.family, self, elem, value)
else:
raise Exception(f'new_attr: unsupported sub-type {elem["sub-type"]}')
@@ -1440,7 +1445,7 @@ class CodeWriter:
self._ifdef_block = config_option
scalars = {'u8', 'u16', 'u32', 'u64', 's32', 's64', 'uint', 'sint'}
scalars = {'u8', 'u16', 'u32', 'u64', 's8', 's16', 's32', 's64', 'uint', 'sint'}
direction_to_suffix = {
'reply': '_rsp',
@@ -1672,6 +1677,9 @@ def _multi_parse(ri, struct, init_lines, local_vars):
if aspec["sub-type"] == 'nest':
local_vars.append(f'const struct nlattr *attr_{aspec.c_name};')
array_nests.add(arg)
elif aspec['sub-type'] in scalars:
local_vars.append(f'const struct nlattr *attr_{aspec.c_name};')
array_nests.add(arg)
else:
raise Exception(f'Not supported sub-type {aspec["sub-type"]}')
if 'multi-attr' in aspec:
@@ -1727,11 +1735,17 @@ def _multi_parse(ri, struct, init_lines, local_vars):
ri.cw.p(f"dst->{aspec.c_name} = calloc(n_{aspec.c_name}, sizeof(*dst->{aspec.c_name}));")
ri.cw.p(f"dst->n_{aspec.c_name} = n_{aspec.c_name};")
ri.cw.p('i = 0;')
ri.cw.p(f"parg.rsp_policy = &{aspec.nested_render_name}_nest;")
if 'nested-attributes' in aspec:
ri.cw.p(f"parg.rsp_policy = &{aspec.nested_render_name}_nest;")
ri.cw.block_start(line=f"ynl_attr_for_each_nested(attr, attr_{aspec.c_name})")
ri.cw.p(f"parg.data = &dst->{aspec.c_name}[i];")
ri.cw.p(f"if ({aspec.nested_render_name}_parse(&parg, attr, ynl_attr_type(attr)))")
ri.cw.p('return YNL_PARSE_CB_ERROR;')
if 'nested-attributes' in aspec:
ri.cw.p(f"parg.data = &dst->{aspec.c_name}[i];")
ri.cw.p(f"if ({aspec.nested_render_name}_parse(&parg, attr, ynl_attr_type(attr)))")
ri.cw.p('return YNL_PARSE_CB_ERROR;')
elif aspec.sub_type in scalars:
ri.cw.p(f"dst->{aspec.c_name}[i] = ynl_attr_get_{aspec.sub_type}(attr);")
else:
raise Exception(f"Nest parsing type not supported in {aspec['name']}")
ri.cw.p('i++;')
ri.cw.block_end()
ri.cw.block_end()