Commit 196febcb authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'tools-net-ynl-add-support-for-nlctrl-netlink-family'

Donald Hunter says:

====================
tools/net/ynl: Add support for nlctrl netlink family

This series adds a new YNL spec for the nlctrl family, plus some fixes
and enhancements for ynl.

Patch 1 fixes an extack decoding bug
Patch 2 gives cleaner netlink error reporting
Patch 3 fixes an array-nest codegen bug
Patch 4 adds nest-type-value support to ynl
Patch 5 fixes the ynl schemas to allow empty enum-name attrs
Patch 6 contains the nlctrl spec
====================

Link: https://lore.kernel.org/r/20240306231046.97158-1-donald.hunter@gmail.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 62a1e416 768e044a
...@@ -126,8 +126,9 @@ properties: ...@@ -126,8 +126,9 @@ properties:
Prefix for the C enum name of the attributes. Default family[name]-set[name]-a- Prefix for the C enum name of the attributes. Default family[name]-set[name]-a-
type: string type: string
enum-name: enum-name:
description: Name for the enum type of the attribute. description: |
type: string Name for the enum type of the attribute, if empty no name will be used.
type: [ string, "null" ]
doc: doc:
description: Documentation of the space. description: Documentation of the space.
type: string type: string
...@@ -261,14 +262,16 @@ properties: ...@@ -261,14 +262,16 @@ properties:
the prefix with the upper case name of the command, with dashes replaced by underscores. the prefix with the upper case name of the command, with dashes replaced by underscores.
type: string type: string
enum-name: enum-name:
description: Name for the enum type with commands. description: |
type: string Name for the enum type with commands, if empty no name will be used.
type: [ string, "null" ]
async-prefix: async-prefix:
description: Same as name-prefix but used to render notifications and events to separate enum. description: Same as name-prefix but used to render notifications and events to separate enum.
type: string type: string
async-enum: async-enum:
description: Name for the enum type with notifications/events. description: |
type: string Name for the enum type with commands, if empty no name will be used.
type: [ string, "null" ]
list: list:
description: List of commands description: List of commands
type: array type: array
......
...@@ -168,8 +168,9 @@ properties: ...@@ -168,8 +168,9 @@ properties:
Prefix for the C enum name of the attributes. Default family[name]-set[name]-a- Prefix for the C enum name of the attributes. Default family[name]-set[name]-a-
type: string type: string
enum-name: enum-name:
description: Name for the enum type of the attribute. description: |
type: string Name for the enum type of the attribute, if empty no name will be used.
type: [ string, "null" ]
doc: doc:
description: Documentation of the space. description: Documentation of the space.
type: string type: string
...@@ -304,14 +305,16 @@ properties: ...@@ -304,14 +305,16 @@ properties:
the prefix with the upper case name of the command, with dashes replaced by underscores. the prefix with the upper case name of the command, with dashes replaced by underscores.
type: string type: string
enum-name: enum-name:
description: Name for the enum type with commands. description: |
type: string Name for the enum type with commands, if empty no name will be used.
type: [ string, "null" ]
async-prefix: async-prefix:
description: Same as name-prefix but used to render notifications and events to separate enum. description: Same as name-prefix but used to render notifications and events to separate enum.
type: string type: string
async-enum: async-enum:
description: Name for the enum type with notifications/events. description: |
type: string Name for the enum type with commands, if empty no name will be used.
type: [ string, "null" ]
# Start genetlink-legacy # Start genetlink-legacy
fixed-header: &fixed-header fixed-header: &fixed-header
description: | description: |
......
...@@ -189,8 +189,9 @@ properties: ...@@ -189,8 +189,9 @@ properties:
Prefix for the C enum name of the attributes. Default family[name]-set[name]-a- Prefix for the C enum name of the attributes. Default family[name]-set[name]-a-
type: string type: string
enum-name: enum-name:
description: Name for the enum type of the attribute. description: |
type: string Name for the enum type of the attribute, if empty no name will be used.
type: [ string, "null" ]
doc: doc:
description: Documentation of the space. description: Documentation of the space.
type: string type: string
...@@ -371,14 +372,16 @@ properties: ...@@ -371,14 +372,16 @@ properties:
the prefix with the upper case name of the command, with dashes replaced by underscores. the prefix with the upper case name of the command, with dashes replaced by underscores.
type: string type: string
enum-name: enum-name:
description: Name for the enum type with commands. description: |
type: string Name for the enum type with commands, if empty no name will be used.
type: [ string, "null" ]
async-prefix: async-prefix:
description: Same as name-prefix but used to render notifications and events to separate enum. description: Same as name-prefix but used to render notifications and events to separate enum.
type: string type: string
async-enum: async-enum:
description: Name for the enum type with notifications/events. description: |
type: string Name for the enum type with commands, if empty no name will be used.
type: [ string, "null" ]
# Start genetlink-legacy # Start genetlink-legacy
fixed-header: &fixed-header fixed-header: &fixed-header
description: | description: |
......
# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
name: nlctrl
protocol: genetlink-legacy
uapi-header: linux/genetlink.h
doc: |
genetlink meta-family that exposes information about all genetlink
families registered in the kernel (including itself).
definitions:
-
name: op-flags
type: flags
enum-name:
entries:
- admin-perm
- cmd-cap-do
- cmd-cap-dump
- cmd-cap-haspol
- uns-admin-perm
-
name: attr-type
enum-name: netlink-attribute-type
type: enum
entries:
- invalid
- flag
- u8
- u16
- u32
- u64
- s8
- s16
- s32
- s64
- binary
- string
- nul-string
- nested
- nested-array
- bitfield32
- sint
- uint
attribute-sets:
-
name: ctrl-attrs
name-prefix: ctrl-attr-
attributes:
-
name: family-id
type: u16
-
name: family-name
type: string
-
name: version
type: u32
-
name: hdrsize
type: u32
-
name: maxattr
type: u32
-
name: ops
type: array-nest
nested-attributes: op-attrs
-
name: mcast-groups
type: array-nest
nested-attributes: mcast-group-attrs
-
name: policy
type: nest-type-value
type-value: [ policy-id, attr-id ]
nested-attributes: policy-attrs
-
name: op-policy
type: nest-type-value
type-value: [ op-id ]
nested-attributes: op-policy-attrs
-
name: op
type: u32
-
name: mcast-group-attrs
name-prefix: ctrl-attr-mcast-grp-
enum-name:
attributes:
-
name: name
type: string
-
name: id
type: u32
-
name: op-attrs
name-prefix: ctrl-attr-op-
enum-name:
attributes:
-
name: id
type: u32
-
name: flags
type: u32
enum: op-flags
enum-as-flags: true
-
name: policy-attrs
name-prefix: nl-policy-type-attr-
enum-name:
attributes:
-
name: type
type: u32
enum: attr-type
-
name: min-value-s
type: s64
-
name: max-value-s
type: s64
-
name: min-value-u
type: u64
-
name: max-value-u
type: u64
-
name: min-length
type: u32
-
name: max-length
type: u32
-
name: policy-idx
type: u32
-
name: policy-maxtype
type: u32
-
name: bitfield32-mask
type: u32
-
name: mask
type: u64
-
name: pad
type: pad
-
name: op-policy-attrs
name-prefix: ctrl-attr-policy-
enum-name:
attributes:
-
name: do
type: u32
-
name: dump
type: u32
operations:
enum-model: directional
name-prefix: ctrl-cmd-
list:
-
name: getfamily
doc: Get / dump genetlink families
attribute-set: ctrl-attrs
do:
request:
value: 3
attributes:
- family-name
reply: &all-attrs
value: 1
attributes:
- family-id
- family-name
- hdrsize
- maxattr
- mcast-groups
- ops
- version
dump:
reply: *all-attrs
-
name: getpolicy
doc: Get / dump genetlink policies
attribute-set: ctrl-attrs
dump:
request:
value: 10
attributes:
- family-name
- family-id
- op
reply:
value: 10
attributes:
- family-id
- op-policy
- policy
...@@ -6,7 +6,7 @@ import json ...@@ -6,7 +6,7 @@ import json
import pprint import pprint
import time import time
from lib import YnlFamily, Netlink from lib import YnlFamily, Netlink, NlError
class YnlEncoder(json.JSONEncoder): class YnlEncoder(json.JSONEncoder):
...@@ -66,12 +66,16 @@ def main(): ...@@ -66,12 +66,16 @@ def main():
if args.sleep: if args.sleep:
time.sleep(args.sleep) time.sleep(args.sleep)
if args.do: try:
reply = ynl.do(args.do, attrs, args.flags) if args.do:
output(reply) reply = ynl.do(args.do, attrs, args.flags)
if args.dump: output(reply)
reply = ynl.dump(args.dump, attrs) if args.dump:
output(reply) reply = ynl.dump(args.dump, attrs)
output(reply)
except NlError as e:
print(e)
exit(1)
if args.ntf: if args.ntf:
ynl.check_ntf() ynl.check_ntf()
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
from .nlspec import SpecAttr, SpecAttrSet, SpecEnumEntry, SpecEnumSet, \ from .nlspec import SpecAttr, SpecAttrSet, SpecEnumEntry, SpecEnumSet, \
SpecFamily, SpecOperation SpecFamily, SpecOperation
from .ynl import YnlFamily, Netlink from .ynl import YnlFamily, Netlink, NlError
__all__ = ["SpecAttr", "SpecAttrSet", "SpecEnumEntry", "SpecEnumSet", __all__ = ["SpecAttr", "SpecAttrSet", "SpecEnumEntry", "SpecEnumSet",
"SpecFamily", "SpecOperation", "YnlFamily", "Netlink"] "SpecFamily", "SpecOperation", "YnlFamily", "Netlink", "NlError"]
...@@ -353,6 +353,9 @@ class NetlinkProtocol: ...@@ -353,6 +353,9 @@ class NetlinkProtocol:
raise Exception(f'Multicast group "{mcast_name}" not present in the spec') raise Exception(f'Multicast group "{mcast_name}" not present in the spec')
return mcast_groups[mcast_name].value return mcast_groups[mcast_name].value
def msghdr_size(self):
return 16
class GenlProtocol(NetlinkProtocol): class GenlProtocol(NetlinkProtocol):
def __init__(self, family_name): def __init__(self, family_name):
...@@ -378,6 +381,8 @@ class GenlProtocol(NetlinkProtocol): ...@@ -378,6 +381,8 @@ class GenlProtocol(NetlinkProtocol):
raise Exception(f'Multicast group "{mcast_name}" not present in the family') raise Exception(f'Multicast group "{mcast_name}" not present in the family')
return self.genl_family['mcast'][mcast_name] return self.genl_family['mcast'][mcast_name]
def msghdr_size(self):
return super().msghdr_size() + 4
class SpaceAttrs: class SpaceAttrs:
...@@ -590,6 +595,16 @@ class YnlFamily(SpecFamily): ...@@ -590,6 +595,16 @@ class YnlFamily(SpecFamily):
decoded.append({ item.type: subattrs }) decoded.append({ item.type: subattrs })
return decoded return decoded
def _decode_nest_type_value(self, attr, attr_spec):
decoded = {}
value = attr
for name in attr_spec['type-value']:
value = NlAttr(value.raw, 0)
decoded[name] = value.type
subattrs = self._decode(NlAttrs(value.raw), attr_spec['nested-attributes'])
decoded.update(subattrs)
return decoded
def _decode_unknown(self, attr): def _decode_unknown(self, attr):
if attr.is_nest: if attr.is_nest:
return self._decode(NlAttrs(attr.raw), None) return self._decode(NlAttrs(attr.raw), None)
...@@ -681,6 +696,8 @@ class YnlFamily(SpecFamily): ...@@ -681,6 +696,8 @@ class YnlFamily(SpecFamily):
decoded = {"value": value, "selector": selector} decoded = {"value": value, "selector": selector}
elif attr_spec["type"] == 'sub-message': elif attr_spec["type"] == 'sub-message':
decoded = self._decode_sub_msg(attr, attr_spec, search_attrs) decoded = self._decode_sub_msg(attr, attr_spec, search_attrs)
elif attr_spec["type"] == 'nest-type-value':
decoded = self._decode_nest_type_value(attr, attr_spec)
else: else:
if not self.process_unknown: if not self.process_unknown:
raise Exception(f'Unknown {attr_spec["type"]} with name {attr_spec["name"]}') raise Exception(f'Unknown {attr_spec["type"]} with name {attr_spec["name"]}')
...@@ -721,7 +738,7 @@ class YnlFamily(SpecFamily): ...@@ -721,7 +738,7 @@ class YnlFamily(SpecFamily):
return return
msg = self.nlproto.decode(self, NlMsg(request, 0, op.attr_set)) msg = self.nlproto.decode(self, NlMsg(request, 0, op.attr_set))
offset = 20 + self._struct_size(op.fixed_header) offset = self.nlproto.msghdr_size() + self._struct_size(op.fixed_header)
path = self._decode_extack_path(msg.raw_attrs, op.attr_set, offset, path = self._decode_extack_path(msg.raw_attrs, op.attr_set, offset,
extack['bad-attr-offs']) extack['bad-attr-offs'])
if path: if path:
......
...@@ -1667,7 +1667,7 @@ def _multi_parse(ri, struct, init_lines, local_vars): ...@@ -1667,7 +1667,7 @@ def _multi_parse(ri, struct, init_lines, local_vars):
aspec = struct[anest] aspec = struct[anest]
ri.cw.block_start(line=f"if (n_{aspec.c_name})") ri.cw.block_start(line=f"if (n_{aspec.c_name})")
ri.cw.p(f"dst->{aspec.c_name} = calloc({aspec.c_name}, sizeof(*dst->{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->n_{aspec.c_name} = n_{aspec.c_name};") ri.cw.p(f"dst->n_{aspec.c_name} = n_{aspec.c_name};")
ri.cw.p('i = 0;') ri.cw.p('i = 0;')
ri.cw.p(f"parg.rsp_policy = &{aspec.nested_render_name}_nest;") ri.cw.p(f"parg.rsp_policy = &{aspec.nested_render_name}_nest;")
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment