mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-14 12:21:15 -04:00
Merge branch 'tools-ynl-prepare-for-wireguard'
Asbjørn Sloth Tønnesen says: ==================== tools: ynl: prepare for wireguard This series contains the last batch of YNL changes to support the wireguard YNL conversion. ==================== Link: https://patch.msgid.link/20250915144301.725949-1-ast@fiberby.net Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
@@ -154,7 +154,7 @@ properties:
|
||||
Optional format indicator that is intended only for choosing
|
||||
the right formatting mechanism when displaying values of this
|
||||
type.
|
||||
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
|
||||
|
||||
@@ -106,7 +106,6 @@ ynl_gemsg_start_req(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version);
|
||||
struct nlmsghdr *
|
||||
ynl_gemsg_start_dump(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version);
|
||||
|
||||
int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr);
|
||||
int ynl_submsg_failed(struct ynl_parse_arg *yarg, const char *field_name,
|
||||
const char *sel_name);
|
||||
|
||||
@@ -467,4 +466,13 @@ ynl_attr_put_sint(struct nlmsghdr *nlh, __u16 type, __s64 data)
|
||||
else
|
||||
ynl_attr_put_s64(nlh, type, data);
|
||||
}
|
||||
|
||||
int __ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr,
|
||||
unsigned int type);
|
||||
|
||||
static inline int ynl_attr_validate(struct ynl_parse_arg *yarg,
|
||||
const struct nlattr *attr)
|
||||
{
|
||||
return __ynl_attr_validate(yarg, attr, ynl_attr_type(attr));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -360,15 +360,15 @@ static int ynl_cb_done(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg)
|
||||
|
||||
/* Attribute validation */
|
||||
|
||||
int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr)
|
||||
int __ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr,
|
||||
unsigned int type)
|
||||
{
|
||||
const struct ynl_policy_attr *policy;
|
||||
unsigned int type, len;
|
||||
unsigned char *data;
|
||||
unsigned int len;
|
||||
|
||||
data = ynl_attr_data(attr);
|
||||
len = ynl_attr_data_len(attr);
|
||||
type = ynl_attr_type(attr);
|
||||
if (type > yarg->rsp_policy->max_attr) {
|
||||
yerr(yarg->ys, YNL_ERROR_INTERNAL,
|
||||
"Internal error, validating unknown attribute");
|
||||
|
||||
@@ -561,11 +561,13 @@ class YnlFamily(SpecFamily):
|
||||
|
||||
if attr["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)
|
||||
for subname, subvalue in value.items():
|
||||
attr_payload += self._add_attr(sub_space, subname, subvalue, sub_attrs)
|
||||
attr_payload = self._add_nest_attrs(value, sub_space, search_attrs)
|
||||
elif attr['type'] == 'indexed-array' and attr['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)
|
||||
elif attr["type"] == 'flag':
|
||||
if not value:
|
||||
# If value is absent or false then skip attribute creation.
|
||||
@@ -619,9 +621,28 @@ class YnlFamily(SpecFamily):
|
||||
else:
|
||||
raise Exception(f'Unknown type at {space} {name} {value} {attr["type"]}')
|
||||
|
||||
return self._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)
|
||||
return struct.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''
|
||||
for subname, subvalue in value.items():
|
||||
attr_payload += self._add_attr(sub_space, subname, subvalue,
|
||||
sub_attrs)
|
||||
return attr_payload
|
||||
|
||||
def _encode_indexed_array(self, vals, sub_space, search_attrs):
|
||||
attr_payload = b''
|
||||
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
|
||||
@@ -935,7 +956,7 @@ class YnlFamily(SpecFamily):
|
||||
formatted = hex(raw)
|
||||
else:
|
||||
formatted = bytes.hex(raw, ' ')
|
||||
elif display_hint in [ 'ipv4', 'ipv6' ]:
|
||||
elif display_hint in [ 'ipv4', 'ipv6', 'ipv4-or-v6' ]:
|
||||
formatted = format(ipaddress.ip_address(raw))
|
||||
elif display_hint == 'uuid':
|
||||
formatted = str(uuid.UUID(bytes=raw))
|
||||
@@ -944,12 +965,17 @@ class YnlFamily(SpecFamily):
|
||||
return formatted
|
||||
|
||||
def _from_string(self, string, attr_spec):
|
||||
if attr_spec.display_hint in ['ipv4', 'ipv6']:
|
||||
if attr_spec.display_hint in ['ipv4', 'ipv6', 'ipv4-or-v6']:
|
||||
ip = ipaddress.ip_address(string)
|
||||
if attr_spec['type'] == 'binary':
|
||||
raw = ip.packed
|
||||
else:
|
||||
raw = int(ip)
|
||||
elif attr_spec.display_hint == 'hex':
|
||||
if attr_spec['type'] == 'binary':
|
||||
raw = bytes.fromhex(string)
|
||||
else:
|
||||
raw = int(string, 16)
|
||||
else:
|
||||
raise Exception(f"Display hint '{attr_spec.display_hint}' not implemented"
|
||||
f" when parsing '{attr_spec['name']}'")
|
||||
|
||||
@@ -242,7 +242,7 @@ class Type(SpecAttr):
|
||||
raise Exception(f"Attr get not implemented for class type {self.type}")
|
||||
|
||||
def attr_get(self, ri, var, first):
|
||||
lines, init_lines, local_vars = self._attr_get(ri, var)
|
||||
lines, init_lines, _ = self._attr_get(ri, var)
|
||||
if type(lines) is str:
|
||||
lines = [lines]
|
||||
if type(init_lines) is str:
|
||||
@@ -250,10 +250,6 @@ class Type(SpecAttr):
|
||||
|
||||
kw = 'if' if first else 'else if'
|
||||
ri.cw.block_start(line=f"{kw} (type == {self.enum_name})")
|
||||
if local_vars:
|
||||
for local in local_vars:
|
||||
ri.cw.p(local)
|
||||
ri.cw.nl()
|
||||
|
||||
if not self.is_multi_val():
|
||||
ri.cw.p("if (ynl_attr_validate(yarg, attr))")
|
||||
@@ -791,7 +787,7 @@ class TypeMultiAttr(Type):
|
||||
f"{presence} = n_{self.c_name};"]
|
||||
|
||||
|
||||
class TypeArrayNest(Type):
|
||||
class TypeIndexedArray(Type):
|
||||
def is_multi_val(self):
|
||||
return True
|
||||
|
||||
@@ -815,19 +811,26 @@ class TypeArrayNest(Type):
|
||||
f'unsigned int n_{self.c_name}']
|
||||
return super().arg_member(ri)
|
||||
|
||||
def _attr_policy(self, policy):
|
||||
if self.attr['sub-type'] == 'nest':
|
||||
return f'NLA_POLICY_NESTED_ARRAY({self.nested_render_name}_nl_policy)'
|
||||
return super()._attr_policy(policy)
|
||||
|
||||
def _attr_typol(self):
|
||||
if self.attr['sub-type'] in scalars:
|
||||
return f'.type = YNL_PT_U{c_upper(self.sub_type[1:])}, '
|
||||
elif self.attr['sub-type'] == 'binary' and 'exact-len' in self.checks:
|
||||
return f'.type = YNL_PT_BINARY, .len = {self.checks["exact-len"]}, '
|
||||
else:
|
||||
elif self.attr['sub-type'] == 'nest':
|
||||
return f'.type = YNL_PT_NEST, .nest = &{self.nested_render_name}_nest, '
|
||||
else:
|
||||
raise Exception(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;']
|
||||
get_lines = [f'attr_{self.c_name} = attr;',
|
||||
'ynl_attr_for_each_nested(attr2, attr) {',
|
||||
'\tif (ynl_attr_validate(yarg, attr2))',
|
||||
'\tif (__ynl_attr_validate(yarg, attr2, type))',
|
||||
'\t\treturn YNL_PARSE_CB_ERROR;',
|
||||
f'\tn_{self.c_name}++;',
|
||||
'}']
|
||||
@@ -847,7 +850,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:
|
||||
raise Exception(f"Put for ArrayNest sub-type {self.attr['sub-type']} not supported, yet")
|
||||
raise Exception(f"Put for IndexedArray sub-type {self.attr['sub-type']} not supported, yet")
|
||||
ri.cw.p('ynl_attr_nest_end(nlh, array);')
|
||||
|
||||
def _setter_lines(self, ri, member, presence):
|
||||
@@ -1124,7 +1127,7 @@ class AttrSet(SpecAttrSet):
|
||||
t = TypeNest(self.family, self, elem, value)
|
||||
elif elem['type'] == 'indexed-array' and 'sub-type' in elem:
|
||||
if elem["sub-type"] in ['binary', 'nest', 'u32']:
|
||||
t = TypeArrayNest(self.family, self, elem, value)
|
||||
t = TypeIndexedArray(self.family, self, elem, value)
|
||||
else:
|
||||
raise Exception(f'new_attr: unsupported sub-type {elem["sub-type"]}')
|
||||
elif elem['type'] == 'nest-type-value':
|
||||
@@ -2033,6 +2036,20 @@ def put_enum_to_str(family, cw, enum):
|
||||
_put_enum_to_str_helper(cw, enum.render_name, map_name, 'value', enum=enum)
|
||||
|
||||
|
||||
def put_local_vars(struct):
|
||||
local_vars = []
|
||||
has_array = False
|
||||
has_count = False
|
||||
for _, arg in struct.member_list():
|
||||
has_array |= arg.type == 'indexed-array'
|
||||
has_count |= arg.presence_type() == 'count'
|
||||
if has_array:
|
||||
local_vars.append('struct nlattr *array;')
|
||||
if has_count:
|
||||
local_vars.append('unsigned int i;')
|
||||
return local_vars
|
||||
|
||||
|
||||
def put_req_nested_prototype(ri, struct, suffix=';'):
|
||||
func_args = ['struct nlmsghdr *nlh',
|
||||
'unsigned int attr_type',
|
||||
@@ -2055,15 +2072,7 @@ def put_req_nested(ri, struct):
|
||||
init_lines.append(f"hdr = ynl_nlmsg_put_extra_header(nlh, {struct_sz});")
|
||||
init_lines.append(f"memcpy(hdr, &obj->_hdr, {struct_sz});")
|
||||
|
||||
has_anest = False
|
||||
has_count = False
|
||||
for _, arg in struct.member_list():
|
||||
has_anest |= arg.type == 'indexed-array'
|
||||
has_count |= arg.presence_type() == 'count'
|
||||
if has_anest:
|
||||
local_vars.append('struct nlattr *array;')
|
||||
if has_count:
|
||||
local_vars.append('unsigned int i;')
|
||||
local_vars += put_local_vars(struct)
|
||||
|
||||
put_req_nested_prototype(ri, struct, suffix='')
|
||||
ri.cw.block_start()
|
||||
@@ -2100,33 +2109,41 @@ def _multi_parse(ri, struct, init_lines, local_vars):
|
||||
else:
|
||||
raise Exception("Per-op fixed header not supported, yet")
|
||||
|
||||
array_nests = set()
|
||||
indexed_arrays = set()
|
||||
multi_attrs = set()
|
||||
needs_parg = False
|
||||
var_set = set()
|
||||
for arg, aspec in struct.member_list():
|
||||
if aspec['type'] == 'indexed-array' and 'sub-type' in aspec:
|
||||
if aspec["sub-type"] in {'binary', 'nest'}:
|
||||
local_vars.append(f'const struct nlattr *attr_{aspec.c_name} = NULL;')
|
||||
array_nests.add(arg)
|
||||
indexed_arrays.add(arg)
|
||||
elif aspec['sub-type'] in scalars:
|
||||
local_vars.append(f'const struct nlattr *attr_{aspec.c_name} = NULL;')
|
||||
array_nests.add(arg)
|
||||
indexed_arrays.add(arg)
|
||||
else:
|
||||
raise Exception(f'Not supported sub-type {aspec["sub-type"]}')
|
||||
if 'multi-attr' in aspec:
|
||||
multi_attrs.add(arg)
|
||||
needs_parg |= 'nested-attributes' in aspec
|
||||
needs_parg |= 'sub-message' in aspec
|
||||
if array_nests or multi_attrs:
|
||||
|
||||
try:
|
||||
_, _, l_vars = aspec._attr_get(ri, '')
|
||||
var_set |= set(l_vars) if l_vars else set()
|
||||
except Exception:
|
||||
pass # _attr_get() not implemented by simple types, ignore
|
||||
local_vars += list(var_set)
|
||||
if indexed_arrays or multi_attrs:
|
||||
local_vars.append('int i;')
|
||||
if needs_parg:
|
||||
local_vars.append('struct ynl_parse_arg parg;')
|
||||
init_lines.append('parg.ys = yarg->ys;')
|
||||
|
||||
all_multi = array_nests | multi_attrs
|
||||
all_multi = indexed_arrays | multi_attrs
|
||||
|
||||
for anest in sorted(all_multi):
|
||||
local_vars.append(f"unsigned int n_{struct[anest].c_name} = 0;")
|
||||
for arg in sorted(all_multi):
|
||||
local_vars.append(f"unsigned int n_{struct[arg].c_name} = 0;")
|
||||
|
||||
ri.cw.block_start()
|
||||
ri.cw.write_func_lvar(local_vars)
|
||||
@@ -2146,8 +2163,8 @@ def _multi_parse(ri, struct, init_lines, local_vars):
|
||||
else:
|
||||
ri.cw.p('hdr = ynl_nlmsg_data_offset(nlh, sizeof(struct genlmsghdr));')
|
||||
ri.cw.p(f"memcpy(&dst->_hdr, hdr, sizeof({struct.fixed_header}));")
|
||||
for anest in sorted(all_multi):
|
||||
aspec = struct[anest]
|
||||
for arg in sorted(all_multi):
|
||||
aspec = struct[arg]
|
||||
ri.cw.p(f"if (dst->{aspec.c_name})")
|
||||
ri.cw.p(f'return ynl_error_parse(yarg, "attribute already present ({struct.attr_set.name}.{aspec.name})");')
|
||||
|
||||
@@ -2165,8 +2182,8 @@ def _multi_parse(ri, struct, init_lines, local_vars):
|
||||
ri.cw.block_end()
|
||||
ri.cw.nl()
|
||||
|
||||
for anest in sorted(array_nests):
|
||||
aspec = struct[anest]
|
||||
for arg in sorted(indexed_arrays):
|
||||
aspec = struct[arg]
|
||||
|
||||
ri.cw.block_start(line=f"if (n_{aspec.c_name})")
|
||||
ri.cw.p(f"dst->{aspec.c_name} = calloc(n_{aspec.c_name}, sizeof(*dst->{aspec.c_name}));")
|
||||
@@ -2191,8 +2208,8 @@ def _multi_parse(ri, struct, init_lines, local_vars):
|
||||
ri.cw.block_end()
|
||||
ri.cw.nl()
|
||||
|
||||
for anest in sorted(multi_attrs):
|
||||
aspec = struct[anest]
|
||||
for arg in sorted(multi_attrs):
|
||||
aspec = struct[arg]
|
||||
ri.cw.block_start(line=f"if (n_{aspec.c_name})")
|
||||
ri.cw.p(f"dst->{aspec.c_name} = calloc(n_{aspec.c_name}, sizeof(*dst->{aspec.c_name}));")
|
||||
ri.cw.p(f"dst->_count.{aspec.c_name} = n_{aspec.c_name};")
|
||||
@@ -2347,10 +2364,7 @@ def print_req(ri):
|
||||
local_vars += ['size_t hdr_len;',
|
||||
'void *hdr;']
|
||||
|
||||
for _, attr in ri.struct["request"].member_list():
|
||||
if attr.presence_type() == 'count':
|
||||
local_vars += ['unsigned int i;']
|
||||
break
|
||||
local_vars += put_local_vars(ri.struct['request'])
|
||||
|
||||
print_prototype(ri, direction, terminate=False)
|
||||
ri.cw.block_start()
|
||||
@@ -2417,6 +2431,9 @@ def print_dump(ri):
|
||||
local_vars += ['size_t hdr_len;',
|
||||
'void *hdr;']
|
||||
|
||||
if 'request' in ri.op[ri.op_mode]:
|
||||
local_vars += put_local_vars(ri.struct['request'])
|
||||
|
||||
ri.cw.write_func_lvar(local_vars)
|
||||
|
||||
ri.cw.p('yds.yarg.ys = ys;')
|
||||
@@ -3208,8 +3225,9 @@ def render_uapi(family, cw):
|
||||
cw.block_end(line=';')
|
||||
cw.nl()
|
||||
elif const['type'] == 'const':
|
||||
name_pfx = const.get('name-prefix', f"{family.ident_name}-")
|
||||
defines.append([c_upper(family.get('c-define-name',
|
||||
f"{family.ident_name}-{const['name']}")),
|
||||
f"{name_pfx}{const['name']}")),
|
||||
const['value']])
|
||||
|
||||
if defines:
|
||||
|
||||
Reference in New Issue
Block a user