Skip to content

Commit

Permalink
tools: ynl-gen: introduce support for bitfield32 attribute type
Browse files Browse the repository at this point in the history
Introduce support for attribute type bitfield32.
Note that since the generated code works with struct nla_bitfield32,
the generator adds netlink.h to the list of includes for userspace
headers in case any bitfield32 is present.

Note that this is added only to genetlink-legacy scheme as requested
by Jakub Kicinski.

Signed-off-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
Link: https://lore.kernel.org/r/20231021112711.660606-3-jiri@resnulli.us
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  • Loading branch information
Jiri Pirko authored and Jakub Kicinski committed Oct 23, 2023
1 parent f862ed2 commit 4e2846f
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 5 deletions.
2 changes: 1 addition & 1 deletion Documentation/netlink/genetlink-legacy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ properties:
type: string
type: &attr-type
description: The netlink attribute type
enum: [ unused, pad, flag, binary,
enum: [ unused, pad, flag, binary, bitfield32,
uint, sint, u8, u16, u32, u64, s32, s64,
string, nest, array-nest, nest-type-value ]
doc:
Expand Down
2 changes: 1 addition & 1 deletion Documentation/userspace-api/netlink/genetlink-legacy.rst
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ members

- ``name`` - The attribute name of the struct member
- ``type`` - One of the scalar types ``u8``, ``u16``, ``u32``, ``u64``, ``s8``,
``s16``, ``s32``, ``s64``, ``string`` or ``binary``.
``s16``, ``s32``, ``s64``, ``string``, ``binary`` or ``bitfield32``.
- ``byte-order`` - ``big-endian`` or ``little-endian``
- ``doc``, ``enum``, ``enum-as-flags``, ``display-hint`` - Same as for
:ref:`attribute definitions <attribute_properties>`
Expand Down
6 changes: 6 additions & 0 deletions tools/net/ynl/lib/ynl.c
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,12 @@ int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr)
yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
"Invalid attribute (string %s)", policy->name);
return -1;
case YNL_PT_BITFIELD32:
if (len == sizeof(struct nla_bitfield32))
break;
yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
"Invalid attribute (bitfield32 %s)", policy->name);
return -1;
default:
yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
"Invalid attribute (unknown %s)", policy->name);
Expand Down
1 change: 1 addition & 0 deletions tools/net/ynl/lib/ynl.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ enum ynl_policy_type {
YNL_PT_U64,
YNL_PT_UINT,
YNL_PT_NUL_STR,
YNL_PT_BITFIELD32,
};

struct ynl_policy_attr {
Expand Down
13 changes: 10 additions & 3 deletions tools/net/ynl/lib/ynl.py
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,8 @@ def _add_attr(self, space, name, value):
elif attr['type'] in NlAttr.type_formats:
format = NlAttr.get_format(attr['type'], attr.byte_order)
attr_payload = format.pack(int(value))
elif attr['type'] in "bitfield32":
attr_payload = struct.pack("II", int(value["value"]), int(value["selector"]))
else:
raise Exception(f'Unknown type at {space} {name} {value} {attr["type"]}')

Expand Down Expand Up @@ -545,14 +547,19 @@ def _decode(self, attrs, space):
decoded = attr.as_auto_scalar(attr_spec['type'], attr_spec.byte_order)
elif attr_spec["type"] in NlAttr.type_formats:
decoded = attr.as_scalar(attr_spec['type'], attr_spec.byte_order)
if 'enum' in attr_spec:
decoded = self._decode_enum(decoded, attr_spec)
elif attr_spec["type"] == 'array-nest':
decoded = self._decode_array_nest(attr, attr_spec)
elif attr_spec["type"] == 'bitfield32':
value, selector = struct.unpack("II", attr.raw)
if 'enum' in attr_spec:
value = self._decode_enum(value, attr_spec)
selector = self._decode_enum(selector, attr_spec)
decoded = {"value": value, "selector": selector}
else:
raise Exception(f'Unknown {attr_spec["type"]} with name {attr_spec["name"]}')

if 'enum' in attr_spec:
decoded = self._decode_enum(decoded, attr_spec)

if not attr_spec.is_multi:
rsp[attr_spec['name']] = decoded
elif attr_spec.name in rsp:
Expand Down
39 changes: 39 additions & 0 deletions tools/net/ynl/ynl-gen-c.py
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,31 @@ def _setter_lines(self, ri, member, presence):
f'memcpy({member}, {self.c_name}, {presence}_len);']


class TypeBitfield32(Type):
def _complex_member_type(self, ri):
return "struct nla_bitfield32"

def _attr_typol(self):
return f'.type = YNL_PT_BITFIELD32, '

def _attr_policy(self, policy):
if not 'enum' in self.attr:
raise Exception('Enum required for bitfield32 attr')
enum = self.family.consts[self.attr['enum']]
mask = enum.get_mask(as_flags=True)
return f"NLA_POLICY_BITFIELD32({mask})"

def attr_put(self, ri, var):
line = f"mnl_attr_put(nlh, {self.enum_name}, sizeof(struct nla_bitfield32), &{var}->{self.c_name})"
self._attr_put_line(ri, var, line)

def _attr_get(self, ri, var):
return f"memcpy(&{var}->{self.c_name}, mnl_attr_get_payload(attr), sizeof(struct nla_bitfield32));", None, None

def _setter_lines(self, ri, member, presence):
return [f"memcpy(&{member}, {self.c_name}, sizeof(struct nla_bitfield32));"]


class TypeNest(Type):
def _complex_member_type(self, ri):
return self.nested_struct_type
Expand Down Expand Up @@ -786,6 +811,8 @@ def new_attr(self, elem, value):
t = TypeString(self.family, self, elem, value)
elif elem['type'] == 'binary':
t = TypeBinary(self.family, self, elem, value)
elif elem['type'] == 'bitfield32':
t = TypeBitfield32(self.family, self, elem, value)
elif elem['type'] == 'nest':
t = TypeNest(self.family, self, elem, value)
elif elem['type'] == 'array-nest':
Expand Down Expand Up @@ -2414,6 +2441,16 @@ def render_user_family(family, cw, prototype):
cw.block_end(line=';')


def family_contains_bitfield32(family):
for _, attr_set in family.attr_sets.items():
if attr_set.subset_of:
continue
for _, attr in attr_set.items():
if attr.type == "bitfield32":
return True
return False


def find_kernel_root(full_path):
sub_path = ''
while True:
Expand Down Expand Up @@ -2499,6 +2536,8 @@ def main():
cw.p('#include <string.h>')
if args.header:
cw.p('#include <linux/types.h>')
if family_contains_bitfield32(parsed):
cw.p('#include <linux/netlink.h>')
else:
cw.p(f'#include "{parsed.name}-user.h"')
cw.p('#include "ynl.h"')
Expand Down

0 comments on commit 4e2846f

Please sign in to comment.