Merge branch 'tools-net-ynl-add-sub-message-support-to-ynl'
Donald Hunter says: ==================== tools/net/ynl: Add 'sub-message' support to ynl This patchset adds a 'sub-message' attribute type to the netlink-raw schema and implements it in ynl. This provides support for kind-specific options attributes as used in rt_link and tc raw netlink families. A description of the new 'sub-message' attribute type and the corresponding sub-message definitions is provided in patch 3. The patchset includes updates to the rt_link spec and a new tc spec that make use of the new 'sub-message' attribute type. As mentioned in patch 4, encode support is not yet implemented in ynl and support for sub-message selectors at a different nest level from the key attribute is not yet supported. I plan to work on these in follow-up patches. Patches 1 is code cleanup in ynl Patches 2-4 add sub-message support to the schema and ynl with documentation updates. Patch 5 adds binary and pad support to structs in netlink-raw. Patches 6-8 contain specs that use the sub-message attribute type. Patches 9-13 update ynl-gen-rst and its make target ==================== Link: https://lore.kernel.org/r/20231215093720.18774-1-donald.hunter@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
509afc7452
@ -106,10 +106,10 @@ YNL_RST_FILES_TMP := $(patsubst %.yaml,%.rst,$(wildcard $(YNL_YAML_DIR)/*.yaml))
|
||||
YNL_RST_FILES := $(patsubst $(YNL_YAML_DIR)%,$(YNL_RST_DIR)%, $(YNL_RST_FILES_TMP))
|
||||
|
||||
$(YNL_INDEX): $(YNL_RST_FILES)
|
||||
@$(YNL_TOOL) -o $@ -x
|
||||
$(Q)$(YNL_TOOL) -o $@ -x
|
||||
|
||||
$(YNL_RST_DIR)/%.rst: $(YNL_YAML_DIR)/%.yaml
|
||||
@$(YNL_TOOL) -i $< -o $@
|
||||
$(YNL_RST_DIR)/%.rst: $(YNL_YAML_DIR)/%.yaml $(YNL_TOOL)
|
||||
$(Q)$(YNL_TOOL) -i $< -o $@
|
||||
|
||||
htmldocs: $(YNL_INDEX)
|
||||
@$(srctree)/scripts/sphinx-pre-install --version-check
|
||||
|
@ -126,8 +126,10 @@ properties:
|
||||
name:
|
||||
type: string
|
||||
type:
|
||||
description: The netlink attribute type
|
||||
enum: [ u8, u16, u32, u64, s8, s16, s32, s64, string, binary ]
|
||||
description: |
|
||||
The netlink attribute type. Members of type 'binary' or 'pad'
|
||||
must also have the 'len' property set.
|
||||
enum: [ u8, u16, u32, u64, s8, s16, s32, s64, string, binary, pad ]
|
||||
len:
|
||||
$ref: '#/$defs/len-or-define'
|
||||
byte-order:
|
||||
@ -150,6 +152,14 @@ properties:
|
||||
the right formatting mechanism when displaying values of this
|
||||
type.
|
||||
enum: [ hex, mac, fddi, ipv4, ipv6, uuid ]
|
||||
if:
|
||||
properties:
|
||||
type:
|
||||
oneOf:
|
||||
- const: binary
|
||||
- const: pad
|
||||
then:
|
||||
required: [ len ]
|
||||
# End genetlink-legacy
|
||||
|
||||
attribute-sets:
|
||||
@ -202,7 +212,8 @@ properties:
|
||||
description: The netlink attribute type
|
||||
enum: [ unused, pad, flag, binary, bitfield32,
|
||||
u8, u16, u32, u64, s8, s16, s32, s64,
|
||||
string, nest, array-nest, nest-type-value ]
|
||||
string, nest, array-nest, nest-type-value,
|
||||
sub-message ]
|
||||
doc:
|
||||
description: Documentation of the attribute.
|
||||
type: string
|
||||
@ -261,6 +272,17 @@ properties:
|
||||
description: Name of the struct type used for the attribute.
|
||||
type: string
|
||||
# End genetlink-legacy
|
||||
# Start netlink-raw
|
||||
sub-message:
|
||||
description: |
|
||||
Name of the sub-message definition to use for the attribute.
|
||||
type: string
|
||||
selector:
|
||||
description: |
|
||||
Name of the attribute to use for dynamic selection of sub-message
|
||||
format specifier.
|
||||
type: string
|
||||
# End netlink-raw
|
||||
|
||||
# Make sure name-prefix does not appear in subsets (subsets inherit naming)
|
||||
dependencies:
|
||||
@ -283,6 +305,43 @@ properties:
|
||||
items:
|
||||
required: [ type ]
|
||||
|
||||
# Start netlink-raw
|
||||
sub-messages:
|
||||
description: Definition of sub message attributes
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
additionalProperties: False
|
||||
required: [ name, formats ]
|
||||
properties:
|
||||
name:
|
||||
description: Name of the sub-message definition
|
||||
type: string
|
||||
formats:
|
||||
description: Dynamically selected format specifiers
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
additionalProperties: False
|
||||
required: [ value ]
|
||||
properties:
|
||||
value:
|
||||
description: |
|
||||
Value to match for dynamic selection of sub-message format
|
||||
specifier.
|
||||
type: string
|
||||
fixed-header:
|
||||
description: |
|
||||
Name of the struct definition to use as the fixed header
|
||||
for the sub message.
|
||||
type: string
|
||||
attribute-set:
|
||||
description: |
|
||||
Name of the attribute space from which to resolve attributes
|
||||
in the sub message.
|
||||
type: string
|
||||
# End netlink-raw
|
||||
|
||||
operations:
|
||||
description: Operations supported by the protocol.
|
||||
type: object
|
||||
|
@ -66,8 +66,9 @@ definitions:
|
||||
name: ifi-family
|
||||
type: u8
|
||||
-
|
||||
name: padding
|
||||
type: u8
|
||||
name: pad
|
||||
type: pad
|
||||
len: 1
|
||||
-
|
||||
name: ifi-type
|
||||
type: u16
|
||||
@ -82,6 +83,18 @@ definitions:
|
||||
-
|
||||
name: ifi-change
|
||||
type: u32
|
||||
-
|
||||
name: ifla-bridge-id
|
||||
type: struct
|
||||
members:
|
||||
-
|
||||
name: prio
|
||||
type: u16
|
||||
-
|
||||
name: addr
|
||||
type: binary
|
||||
len: 6
|
||||
display-hint: mac
|
||||
-
|
||||
name: ifla-cacheinfo
|
||||
type: struct
|
||||
@ -707,11 +720,9 @@ definitions:
|
||||
name: family
|
||||
type: u8
|
||||
-
|
||||
name: pad1
|
||||
type: u8
|
||||
-
|
||||
name: pad2
|
||||
type: u16
|
||||
name: pad
|
||||
type: pad
|
||||
len: 3
|
||||
-
|
||||
name: ifindex
|
||||
type: u32
|
||||
@ -966,8 +977,9 @@ attribute-sets:
|
||||
type: string
|
||||
-
|
||||
name: data
|
||||
type: binary
|
||||
# kind specific nest, e.g. linkinfo-bridge-attrs
|
||||
type: sub-message
|
||||
sub-message: linkinfo-data-msg
|
||||
selector: kind
|
||||
-
|
||||
name: xstats
|
||||
type: binary
|
||||
@ -976,10 +988,12 @@ attribute-sets:
|
||||
type: string
|
||||
-
|
||||
name: slave-data
|
||||
type: binary
|
||||
# kind specific nest
|
||||
type: sub-message
|
||||
sub-message: linkinfo-member-data-msg
|
||||
selector: slave-kind
|
||||
-
|
||||
name: linkinfo-bridge-attrs
|
||||
name-prefix: ifla-br-
|
||||
attributes:
|
||||
-
|
||||
name: forward-delay
|
||||
@ -1011,9 +1025,11 @@ attribute-sets:
|
||||
-
|
||||
name: root-id
|
||||
type: binary
|
||||
struct: ifla-bridge-id
|
||||
-
|
||||
name: bridge-id
|
||||
type: binary
|
||||
struct: ifla-bridge-id
|
||||
-
|
||||
name: root-port
|
||||
type: u16
|
||||
@ -1041,6 +1057,7 @@ attribute-sets:
|
||||
-
|
||||
name: group-addr
|
||||
type: binary
|
||||
display-hint: mac
|
||||
-
|
||||
name: fdb-flush
|
||||
type: binary
|
||||
@ -1123,6 +1140,376 @@ attribute-sets:
|
||||
-
|
||||
name: mcast-querier-state
|
||||
type: binary
|
||||
-
|
||||
name: linkinfo-brport-attrs
|
||||
name-prefix: ifla-brport-
|
||||
attributes:
|
||||
-
|
||||
name: state
|
||||
type: u8
|
||||
-
|
||||
name: priority
|
||||
type: u16
|
||||
-
|
||||
name: cost
|
||||
type: u32
|
||||
-
|
||||
name: mode
|
||||
type: flag
|
||||
-
|
||||
name: guard
|
||||
type: flag
|
||||
-
|
||||
name: protect
|
||||
type: flag
|
||||
-
|
||||
name: fast-leave
|
||||
type: flag
|
||||
-
|
||||
name: learning
|
||||
type: flag
|
||||
-
|
||||
name: unicast-flood
|
||||
type: flag
|
||||
-
|
||||
name: proxyarp
|
||||
type: flag
|
||||
-
|
||||
name: learning-sync
|
||||
type: flag
|
||||
-
|
||||
name: proxyarp-wifi
|
||||
type: flag
|
||||
-
|
||||
name: root-id
|
||||
type: binary
|
||||
struct: ifla-bridge-id
|
||||
-
|
||||
name: bridge-id
|
||||
type: binary
|
||||
struct: ifla-bridge-id
|
||||
-
|
||||
name: designated-port
|
||||
type: u16
|
||||
-
|
||||
name: designated-cost
|
||||
type: u16
|
||||
-
|
||||
name: id
|
||||
type: u16
|
||||
-
|
||||
name: "no"
|
||||
type: u16
|
||||
-
|
||||
name: topology-change-ack
|
||||
type: u8
|
||||
-
|
||||
name: config-pending
|
||||
type: u8
|
||||
-
|
||||
name: message-age-timer
|
||||
type: u64
|
||||
-
|
||||
name: forward-delay-timer
|
||||
type: u64
|
||||
-
|
||||
name: hold-timer
|
||||
type: u64
|
||||
-
|
||||
name: flush
|
||||
type: flag
|
||||
-
|
||||
name: multicast-router
|
||||
type: u8
|
||||
-
|
||||
name: pad
|
||||
type: pad
|
||||
-
|
||||
name: mcast-flood
|
||||
type: flag
|
||||
-
|
||||
name: mcast-to-ucast
|
||||
type: flag
|
||||
-
|
||||
name: vlan-tunnel
|
||||
type: flag
|
||||
-
|
||||
name: bcast-flood
|
||||
type: flag
|
||||
-
|
||||
name: group-fwd-mask
|
||||
type: u16
|
||||
-
|
||||
name: neigh-suppress
|
||||
type: flag
|
||||
-
|
||||
name: isolated
|
||||
type: flag
|
||||
-
|
||||
name: backup-port
|
||||
type: u32
|
||||
-
|
||||
name: mrp-ring-open
|
||||
type: flag
|
||||
-
|
||||
name: mrp-in-open
|
||||
type: flag
|
||||
-
|
||||
name: mcast-eht-hosts-limit
|
||||
type: u32
|
||||
-
|
||||
name: mcast-eht-hosts-cnt
|
||||
type: u32
|
||||
-
|
||||
name: locked
|
||||
type: flag
|
||||
-
|
||||
name: mab
|
||||
type: flag
|
||||
-
|
||||
name: mcast-n-groups
|
||||
type: u32
|
||||
-
|
||||
name: mcast-max-groups
|
||||
type: u32
|
||||
-
|
||||
name: neigh-vlan-suppress
|
||||
type: flag
|
||||
-
|
||||
name: backup-nhid
|
||||
type: u32
|
||||
-
|
||||
name: linkinfo-gre-attrs
|
||||
name-prefix: ifla-gre-
|
||||
attributes:
|
||||
-
|
||||
name: link
|
||||
type: u32
|
||||
-
|
||||
name: iflags
|
||||
type: u16
|
||||
-
|
||||
name: oflags
|
||||
type: u16
|
||||
-
|
||||
name: ikey
|
||||
type: u32
|
||||
-
|
||||
name: okey
|
||||
type: u32
|
||||
-
|
||||
name: local
|
||||
type: binary
|
||||
display-hint: ipv4
|
||||
-
|
||||
name: remote
|
||||
type: binary
|
||||
display-hint: ipv4
|
||||
-
|
||||
name: ttl
|
||||
type: u8
|
||||
-
|
||||
name: tos
|
||||
type: u8
|
||||
-
|
||||
name: pmtudisc
|
||||
type: u8
|
||||
-
|
||||
name: encap-limit
|
||||
type: u32
|
||||
-
|
||||
name: flowinfo
|
||||
type: u32
|
||||
-
|
||||
name: flags
|
||||
type: u32
|
||||
-
|
||||
name: encap-type
|
||||
type: u16
|
||||
-
|
||||
name: encap-flags
|
||||
type: u16
|
||||
-
|
||||
name: encap-sport
|
||||
type: u16
|
||||
-
|
||||
name: encap-dport
|
||||
type: u16
|
||||
-
|
||||
name: collect-metadata
|
||||
type: flag
|
||||
-
|
||||
name: ignore-df
|
||||
type: u8
|
||||
-
|
||||
name: fwmark
|
||||
type: u32
|
||||
-
|
||||
name: erspan-index
|
||||
type: u32
|
||||
-
|
||||
name: erspan-ver
|
||||
type: u8
|
||||
-
|
||||
name: erspan-dir
|
||||
type: u8
|
||||
-
|
||||
name: erspan-hwid
|
||||
type: u16
|
||||
-
|
||||
name: linkinfo-geneve-attrs
|
||||
name-prefix: ifla-geneve-
|
||||
attributes:
|
||||
-
|
||||
name: id
|
||||
type: u32
|
||||
-
|
||||
name: remote
|
||||
type: binary
|
||||
display-hint: ipv4
|
||||
-
|
||||
name: ttl
|
||||
type: u8
|
||||
-
|
||||
name: tos
|
||||
type: u8
|
||||
-
|
||||
name: port
|
||||
type: u16
|
||||
-
|
||||
name: collect-metadata
|
||||
type: flag
|
||||
-
|
||||
name: remote6
|
||||
type: binary
|
||||
display-hint: ipv6
|
||||
-
|
||||
name: udp-csum
|
||||
type: u8
|
||||
-
|
||||
name: udp-zero-csum6-tx
|
||||
type: u8
|
||||
-
|
||||
name: udp-zero-csum6-rx
|
||||
type: u8
|
||||
-
|
||||
name: label
|
||||
type: u32
|
||||
-
|
||||
name: ttl-inherit
|
||||
type: u8
|
||||
-
|
||||
name: df
|
||||
type: u8
|
||||
-
|
||||
name: inner-proto-inherit
|
||||
type: flag
|
||||
-
|
||||
name: linkinfo-iptun-attrs
|
||||
name-prefix: ifla-iptun-
|
||||
attributes:
|
||||
-
|
||||
name: link
|
||||
type: u32
|
||||
-
|
||||
name: local
|
||||
type: binary
|
||||
display-hint: ipv4
|
||||
-
|
||||
name: remote
|
||||
type: binary
|
||||
display-hint: ipv4
|
||||
-
|
||||
name: ttl
|
||||
type: u8
|
||||
-
|
||||
name: tos
|
||||
type: u8
|
||||
-
|
||||
name: encap-limit
|
||||
type: u8
|
||||
-
|
||||
name: flowinfo
|
||||
type: u32
|
||||
-
|
||||
name: flags
|
||||
type: u16
|
||||
-
|
||||
name: proto
|
||||
type: u8
|
||||
-
|
||||
name: pmtudisc
|
||||
type: u8
|
||||
-
|
||||
name: 6rd-prefix
|
||||
type: binary
|
||||
display-hint: ipv6
|
||||
-
|
||||
name: 6rd-relay-prefix
|
||||
type: binary
|
||||
display-hint: ipv4
|
||||
-
|
||||
name: 6rd-prefixlen
|
||||
type: u16
|
||||
-
|
||||
name: 6rd-relay-prefixlen
|
||||
type: u16
|
||||
-
|
||||
name: encap-type
|
||||
type: u16
|
||||
-
|
||||
name: encap-flags
|
||||
type: u16
|
||||
-
|
||||
name: encap-sport
|
||||
type: u16
|
||||
-
|
||||
name: encap-dport
|
||||
type: u16
|
||||
-
|
||||
name: collect-metadata
|
||||
type: flag
|
||||
-
|
||||
name: fwmark
|
||||
type: u32
|
||||
-
|
||||
name: linkinfo-tun-attrs
|
||||
name-prefix: ifla-tun-
|
||||
attributes:
|
||||
-
|
||||
name: owner
|
||||
type: u32
|
||||
-
|
||||
name: group
|
||||
type: u32
|
||||
-
|
||||
name: type
|
||||
type: u8
|
||||
-
|
||||
name: pi
|
||||
type: u8
|
||||
-
|
||||
name: vnet-hdr
|
||||
type: u8
|
||||
-
|
||||
name: persist
|
||||
type: u8
|
||||
-
|
||||
name: multi-queue
|
||||
type: u8
|
||||
-
|
||||
name: num-queues
|
||||
type: u32
|
||||
-
|
||||
name: num-disabled-queues
|
||||
type: u32
|
||||
-
|
||||
name: linkinfo-vrf-attrs
|
||||
name-prefix: ifla-vrf-
|
||||
attributes:
|
||||
-
|
||||
name: table
|
||||
type: u32
|
||||
-
|
||||
name: xdp-attrs
|
||||
attributes:
|
||||
@ -1241,6 +1628,46 @@ attribute-sets:
|
||||
name: used
|
||||
type: u8
|
||||
|
||||
sub-messages:
|
||||
-
|
||||
name: linkinfo-data-msg
|
||||
formats:
|
||||
-
|
||||
value: bridge
|
||||
attribute-set: linkinfo-bridge-attrs
|
||||
-
|
||||
value: erspan
|
||||
attribute-set: linkinfo-gre-attrs
|
||||
-
|
||||
value: gre
|
||||
attribute-set: linkinfo-gre-attrs
|
||||
-
|
||||
value: gretap
|
||||
attribute-set: linkinfo-gre-attrs
|
||||
-
|
||||
value: geneve
|
||||
attribute-set: linkinfo-geneve-attrs
|
||||
-
|
||||
value: ipip
|
||||
attribute-set: linkinfo-iptun-attrs
|
||||
-
|
||||
value: sit
|
||||
attribute-set: linkinfo-iptun-attrs
|
||||
-
|
||||
value: tun
|
||||
attribute-set: linkinfo-tun-attrs
|
||||
-
|
||||
value: vrf
|
||||
attribute-set: linkinfo-vrf-attrs
|
||||
-
|
||||
name: linkinfo-member-data-msg
|
||||
formats:
|
||||
-
|
||||
value: bridge
|
||||
attribute-set: linkinfo-brport-attrs
|
||||
-
|
||||
value: bond
|
||||
|
||||
operations:
|
||||
enum-model: directional
|
||||
list:
|
||||
|
2031
Documentation/netlink/specs/tc.yaml
Normal file
2031
Documentation/netlink/specs/tc.yaml
Normal file
File diff suppressed because it is too large
Load Diff
@ -14,7 +14,8 @@ Specification
|
||||
The netlink-raw schema extends the :doc:`genetlink-legacy <genetlink-legacy>`
|
||||
schema with properties that are needed to specify the protocol numbers and
|
||||
multicast IDs used by raw netlink families. See :ref:`classic_netlink` for more
|
||||
information.
|
||||
information. The raw netlink families also make use of type-specific
|
||||
sub-messages.
|
||||
|
||||
Globals
|
||||
-------
|
||||
@ -56,3 +57,96 @@ group registration.
|
||||
-
|
||||
name: rtnlgrp-mctp-ifaddr
|
||||
value: 34
|
||||
|
||||
Sub-messages
|
||||
------------
|
||||
|
||||
Several raw netlink families such as
|
||||
:doc:`rt_link<../../networking/netlink_spec/rt_link>` and
|
||||
:doc:`tc<../../networking/netlink_spec/tc>` use attribute nesting as an
|
||||
abstraction to carry module specific information.
|
||||
|
||||
Conceptually it looks as follows::
|
||||
|
||||
[OUTER NEST OR MESSAGE LEVEL]
|
||||
[GENERIC ATTR 1]
|
||||
[GENERIC ATTR 2]
|
||||
[GENERIC ATTR 3]
|
||||
[GENERIC ATTR - wrapper]
|
||||
[MODULE SPECIFIC ATTR 1]
|
||||
[MODULE SPECIFIC ATTR 2]
|
||||
|
||||
The ``GENERIC ATTRs`` at the outer level are defined in the core (or rt_link or
|
||||
core TC), while specific drivers, TC classifiers, qdiscs etc. can carry their
|
||||
own information wrapped in the ``GENERIC ATTR - wrapper``. Even though the
|
||||
example above shows attributes nesting inside the wrapper, the modules generally
|
||||
have full freedom to define the format of the nest. In practice the payload of
|
||||
the wrapper attr has very similar characteristics to a netlink message. It may
|
||||
contain a fixed header / structure, netlink attributes, or both. Because of
|
||||
those shared characteristics we refer to the payload of the wrapper attribute as
|
||||
a sub-message.
|
||||
|
||||
A sub-message attribute uses the value of another attribute as a selector key to
|
||||
choose the right sub-message format. For example if the following attribute has
|
||||
already been decoded:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{ "kind": "gre" }
|
||||
|
||||
and we encounter the following attribute spec:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
-
|
||||
name: data
|
||||
type: sub-message
|
||||
sub-message: linkinfo-data-msg
|
||||
selector: kind
|
||||
|
||||
Then we look for a sub-message definition called ``linkinfo-data-msg`` and use
|
||||
the value of the ``kind`` attribute i.e. ``gre`` as the key to choose the
|
||||
correct format for the sub-message:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
sub-messages:
|
||||
name: linkinfo-data-msg
|
||||
formats:
|
||||
-
|
||||
value: bridge
|
||||
attribute-set: linkinfo-bridge-attrs
|
||||
-
|
||||
value: gre
|
||||
attribute-set: linkinfo-gre-attrs
|
||||
-
|
||||
value: geneve
|
||||
attribute-set: linkinfo-geneve-attrs
|
||||
|
||||
This would decode the attribute value as a sub-message with the attribute-set
|
||||
called ``linkinfo-gre-attrs`` as the attribute space.
|
||||
|
||||
A sub-message can have an optional ``fixed-header`` followed by zero or more
|
||||
attributes from an ``attribute-set``. For example the following
|
||||
``tc-options-msg`` sub-message defines message formats that use a mixture of
|
||||
``fixed-header``, ``attribute-set`` or both together:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
sub-messages:
|
||||
-
|
||||
name: tc-options-msg
|
||||
formats:
|
||||
-
|
||||
value: bfifo
|
||||
fixed-header: tc-fifo-qopt
|
||||
-
|
||||
value: cake
|
||||
attribute-set: tc-cake-attrs
|
||||
-
|
||||
value: netem
|
||||
fixed-header: tc-netem-qopt
|
||||
attribute-set: tc-netem-attrs
|
||||
|
||||
Note that a selector attribute must appear in a netlink message before any
|
||||
sub-message attributes that depend on it.
|
||||
|
@ -158,6 +158,9 @@ class SpecAttr(SpecElement):
|
||||
len integer, optional byte length of binary types
|
||||
display_hint string, hint to help choose format specifier
|
||||
when displaying the value
|
||||
sub_message string, name of sub message type
|
||||
selector string, name of attribute used to select
|
||||
sub-message type
|
||||
|
||||
is_auto_scalar bool, attr is a variable-size scalar
|
||||
"""
|
||||
@ -173,6 +176,8 @@ class SpecAttr(SpecElement):
|
||||
self.byte_order = yaml.get('byte-order')
|
||||
self.len = yaml.get('len')
|
||||
self.display_hint = yaml.get('display-hint')
|
||||
self.sub_message = yaml.get('sub-message')
|
||||
self.selector = yaml.get('selector')
|
||||
|
||||
self.is_auto_scalar = self.type == "sint" or self.type == "uint"
|
||||
|
||||
@ -278,6 +283,47 @@ class SpecStruct(SpecElement):
|
||||
return self.members.items()
|
||||
|
||||
|
||||
class SpecSubMessage(SpecElement):
|
||||
""" Netlink sub-message definition
|
||||
|
||||
Represents a set of sub-message formats for polymorphic nlattrs
|
||||
that contain type-specific sub messages.
|
||||
|
||||
Attributes:
|
||||
name string, name of sub-message definition
|
||||
formats dict of sub-message formats indexed by match value
|
||||
"""
|
||||
def __init__(self, family, yaml):
|
||||
super().__init__(family, yaml)
|
||||
|
||||
self.formats = collections.OrderedDict()
|
||||
for elem in self.yaml['formats']:
|
||||
format = self.new_format(family, elem)
|
||||
self.formats[format.value] = format
|
||||
|
||||
def new_format(self, family, format):
|
||||
return SpecSubMessageFormat(family, format)
|
||||
|
||||
|
||||
class SpecSubMessageFormat(SpecElement):
|
||||
""" Netlink sub-message definition
|
||||
|
||||
Represents a set of sub-message formats for polymorphic nlattrs
|
||||
that contain type-specific sub messages.
|
||||
|
||||
Attributes:
|
||||
value attribute value to match against type selector
|
||||
fixed_header string, name of fixed header, or None
|
||||
attr_set string, name of attribute set, or None
|
||||
"""
|
||||
def __init__(self, family, yaml):
|
||||
super().__init__(family, yaml)
|
||||
|
||||
self.value = yaml.get('value')
|
||||
self.fixed_header = yaml.get('fixed-header')
|
||||
self.attr_set = yaml.get('attribute-set')
|
||||
|
||||
|
||||
class SpecOperation(SpecElement):
|
||||
"""Netlink Operation
|
||||
|
||||
@ -365,6 +411,7 @@ class SpecFamily(SpecElement):
|
||||
|
||||
attr_sets dict of attribute sets
|
||||
msgs dict of all messages (index by name)
|
||||
sub_msgs dict of all sub messages (index by name)
|
||||
ops dict of all valid requests / responses
|
||||
ntfs dict of all async events
|
||||
consts dict of all constants/enums
|
||||
@ -405,6 +452,7 @@ class SpecFamily(SpecElement):
|
||||
jsonschema.validate(self.yaml, schema)
|
||||
|
||||
self.attr_sets = collections.OrderedDict()
|
||||
self.sub_msgs = collections.OrderedDict()
|
||||
self.msgs = collections.OrderedDict()
|
||||
self.req_by_value = collections.OrderedDict()
|
||||
self.rsp_by_value = collections.OrderedDict()
|
||||
@ -441,6 +489,9 @@ class SpecFamily(SpecElement):
|
||||
def new_struct(self, elem):
|
||||
return SpecStruct(self, elem)
|
||||
|
||||
def new_sub_message(self, elem):
|
||||
return SpecSubMessage(self, elem);
|
||||
|
||||
def new_operation(self, elem, req_val, rsp_val):
|
||||
return SpecOperation(self, elem, req_val, rsp_val)
|
||||
|
||||
@ -529,6 +580,10 @@ class SpecFamily(SpecElement):
|
||||
attr_set = self.new_attr_set(elem)
|
||||
self.attr_sets[elem['name']] = attr_set
|
||||
|
||||
for elem in self.yaml.get('sub-messages', []):
|
||||
sub_message = self.new_sub_message(elem)
|
||||
self.sub_msgs[sub_message.name] = sub_message
|
||||
|
||||
if self.msg_id_model == 'unified':
|
||||
self._dictify_ops_unified()
|
||||
elif self.msg_id_model == 'directional':
|
||||
|
@ -98,12 +98,12 @@ class NlAttr:
|
||||
}
|
||||
|
||||
def __init__(self, raw, offset):
|
||||
self._len, self._type = struct.unpack("HH", raw[offset:offset + 4])
|
||||
self._len, self._type = struct.unpack("HH", raw[offset : offset + 4])
|
||||
self.type = self._type & ~Netlink.NLA_TYPE_MASK
|
||||
self.is_nest = self._type & Netlink.NLA_F_NESTED
|
||||
self.payload_len = self._len
|
||||
self.full_len = (self.payload_len + 3) & ~3
|
||||
self.raw = raw[offset + 4:offset + self.payload_len]
|
||||
self.raw = raw[offset + 4 : offset + self.payload_len]
|
||||
|
||||
@classmethod
|
||||
def get_format(cls, attr_type, byte_order=None):
|
||||
@ -154,7 +154,7 @@ class NlAttr:
|
||||
for m in members:
|
||||
# TODO: handle non-scalar members
|
||||
if m.type == 'binary':
|
||||
decoded = self.raw[offset:offset+m['len']]
|
||||
decoded = self.raw[offset : offset + m['len']]
|
||||
offset += m['len']
|
||||
elif m.type in NlAttr.type_formats:
|
||||
format = self.get_format(m.type, m.byte_order)
|
||||
@ -170,10 +170,9 @@ class NlAttr:
|
||||
|
||||
|
||||
class NlAttrs:
|
||||
def __init__(self, msg):
|
||||
def __init__(self, msg, offset=0):
|
||||
self.attrs = []
|
||||
|
||||
offset = 0
|
||||
while offset < len(msg):
|
||||
attr = NlAttr(msg, offset)
|
||||
offset += attr.full_len
|
||||
@ -193,12 +192,12 @@ class NlAttrs:
|
||||
|
||||
class NlMsg:
|
||||
def __init__(self, msg, offset, attr_space=None):
|
||||
self.hdr = msg[offset:offset + 16]
|
||||
self.hdr = msg[offset : offset + 16]
|
||||
|
||||
self.nl_len, self.nl_type, self.nl_flags, self.nl_seq, self.nl_portid = \
|
||||
struct.unpack("IHHII", self.hdr)
|
||||
|
||||
self.raw = msg[offset + 16:offset + self.nl_len]
|
||||
self.raw = msg[offset + 16 : offset + self.nl_len]
|
||||
|
||||
self.error = 0
|
||||
self.done = 0
|
||||
@ -371,8 +370,8 @@ class NetlinkProtocol:
|
||||
fixed_header_size = 0
|
||||
if ynl:
|
||||
op = ynl.rsp_by_value[msg.cmd()]
|
||||
fixed_header_size = ynl._fixed_header_size(op)
|
||||
msg.raw_attrs = NlAttrs(msg.raw[fixed_header_size:])
|
||||
fixed_header_size = ynl._fixed_header_size(op.fixed_header)
|
||||
msg.raw_attrs = NlAttrs(msg.raw, fixed_header_size)
|
||||
return msg
|
||||
|
||||
def get_mcast_id(self, mcast_name, mcast_groups):
|
||||
@ -549,6 +548,37 @@ class YnlFamily(SpecFamily):
|
||||
else:
|
||||
rsp[name] = [decoded]
|
||||
|
||||
def _resolve_selector(self, attr_spec, vals):
|
||||
sub_msg = attr_spec.sub_message
|
||||
if sub_msg not in self.sub_msgs:
|
||||
raise Exception(f"No sub-message spec named {sub_msg} for {attr_spec.name}")
|
||||
sub_msg_spec = self.sub_msgs[sub_msg]
|
||||
|
||||
selector = attr_spec.selector
|
||||
if selector not in vals:
|
||||
raise Exception(f"There is no value for {selector} to resolve '{attr_spec.name}'")
|
||||
value = vals[selector]
|
||||
if value not in sub_msg_spec.formats:
|
||||
raise Exception(f"No message format for '{value}' in sub-message spec '{sub_msg}'")
|
||||
|
||||
spec = sub_msg_spec.formats[value]
|
||||
return spec
|
||||
|
||||
def _decode_sub_msg(self, attr, attr_spec, rsp):
|
||||
msg_format = self._resolve_selector(attr_spec, rsp)
|
||||
decoded = {}
|
||||
offset = 0
|
||||
if msg_format.fixed_header:
|
||||
decoded.update(self._decode_fixed_header(attr, msg_format.fixed_header));
|
||||
offset = self._fixed_header_size(msg_format.fixed_header)
|
||||
if msg_format.attr_set:
|
||||
if msg_format.attr_set in self.attr_sets:
|
||||
subdict = self._decode(NlAttrs(attr.raw, offset), msg_format.attr_set)
|
||||
decoded.update(subdict)
|
||||
else:
|
||||
raise Exception(f"Unknown attribute-set '{attr_space}' when decoding '{attr_spec.name}'")
|
||||
return decoded
|
||||
|
||||
def _decode(self, attrs, space):
|
||||
if space:
|
||||
attr_space = self.attr_sets[space]
|
||||
@ -586,6 +616,8 @@ class YnlFamily(SpecFamily):
|
||||
value = self._decode_enum(value, attr_spec)
|
||||
selector = self._decode_enum(selector, attr_spec)
|
||||
decoded = {"value": value, "selector": selector}
|
||||
elif attr_spec["type"] == 'sub-message':
|
||||
decoded = self._decode_sub_msg(attr, attr_spec, rsp)
|
||||
else:
|
||||
if not self.process_unknown:
|
||||
raise Exception(f'Unknown {attr_spec["type"]} with name {attr_spec["name"]}')
|
||||
@ -626,20 +658,23 @@ class YnlFamily(SpecFamily):
|
||||
return
|
||||
|
||||
msg = self.nlproto.decode(self, NlMsg(request, 0, op.attr_set))
|
||||
offset = 20 + self._fixed_header_size(op)
|
||||
offset = 20 + self._fixed_header_size(op.fixed_header)
|
||||
path = self._decode_extack_path(msg.raw_attrs, op.attr_set, offset,
|
||||
extack['bad-attr-offs'])
|
||||
if path:
|
||||
del extack['bad-attr-offs']
|
||||
extack['bad-attr'] = path
|
||||
|
||||
def _fixed_header_size(self, op):
|
||||
if op.fixed_header:
|
||||
fixed_header_members = self.consts[op.fixed_header].members
|
||||
def _fixed_header_size(self, name):
|
||||
if name:
|
||||
fixed_header_members = self.consts[name].members
|
||||
size = 0
|
||||
for m in fixed_header_members:
|
||||
format = NlAttr.get_format(m.type, m.byte_order)
|
||||
size += format.size
|
||||
if m.type in ['pad', 'binary']:
|
||||
size += m.len
|
||||
else:
|
||||
format = NlAttr.get_format(m.type, m.byte_order)
|
||||
size += format.size
|
||||
return size
|
||||
else:
|
||||
return 0
|
||||
@ -649,12 +684,20 @@ class YnlFamily(SpecFamily):
|
||||
fixed_header_attrs = dict()
|
||||
offset = 0
|
||||
for m in fixed_header_members:
|
||||
format = NlAttr.get_format(m.type, m.byte_order)
|
||||
[ value ] = format.unpack_from(msg.raw, offset)
|
||||
offset += format.size
|
||||
if m.enum:
|
||||
value = self._decode_enum(value, m)
|
||||
fixed_header_attrs[m.name] = value
|
||||
value = None
|
||||
if m.type == 'pad':
|
||||
offset += m.len
|
||||
elif m.type == 'binary':
|
||||
value = msg.raw[offset : offset + m.len]
|
||||
offset += m.len
|
||||
else:
|
||||
format = NlAttr.get_format(m.type, m.byte_order)
|
||||
[ value ] = format.unpack_from(msg.raw, offset)
|
||||
offset += format.size
|
||||
if value is not None:
|
||||
if m.enum:
|
||||
value = self._decode_enum(value, m)
|
||||
fixed_header_attrs[m.name] = value
|
||||
return fixed_header_attrs
|
||||
|
||||
def handle_ntf(self, decoded):
|
||||
@ -721,8 +764,13 @@ class YnlFamily(SpecFamily):
|
||||
fixed_header_members = self.consts[op.fixed_header].members
|
||||
for m in fixed_header_members:
|
||||
value = vals.pop(m.name) if m.name in vals else 0
|
||||
format = NlAttr.get_format(m.type, m.byte_order)
|
||||
msg += format.pack(value)
|
||||
if m.type == 'pad':
|
||||
msg += bytearray(m.len)
|
||||
elif m.type == 'binary':
|
||||
msg += bytes.fromhex(value)
|
||||
else:
|
||||
format = NlAttr.get_format(m.type, m.byte_order)
|
||||
msg += format.pack(value)
|
||||
for name, value in vals.items():
|
||||
msg += self._add_attr(op.attr_set.name, name, value)
|
||||
msg = _genl_msg_finalize(msg)
|
||||
|
@ -69,7 +69,7 @@ def rst_paragraph(paragraph: str, level: int = 0) -> str:
|
||||
|
||||
def rst_bullet(item: str, level: int = 0) -> str:
|
||||
"""Return a formatted a bullet"""
|
||||
return headroom(level) + f" - {item}"
|
||||
return headroom(level) + f"- {item}"
|
||||
|
||||
|
||||
def rst_subsection(title: str) -> str:
|
||||
@ -240,7 +240,7 @@ def parse_attr_sets(entries: List[Dict[str, Any]]) -> str:
|
||||
lines.append(rst_section(entry["name"]))
|
||||
for attr in entry["attributes"]:
|
||||
type_ = attr.get("type")
|
||||
attr_line = bold(attr["name"])
|
||||
attr_line = attr["name"]
|
||||
if type_:
|
||||
# Add the attribute type in the same line
|
||||
attr_line += f" ({inline(type_)})"
|
||||
@ -250,7 +250,25 @@ def parse_attr_sets(entries: List[Dict[str, Any]]) -> str:
|
||||
for k in attr.keys():
|
||||
if k in preprocessed + ignored:
|
||||
continue
|
||||
lines.append(rst_fields(k, sanitize(attr[k]), 2))
|
||||
lines.append(rst_fields(k, sanitize(attr[k]), 0))
|
||||
lines.append("\n")
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def parse_sub_messages(entries: List[Dict[str, Any]]) -> str:
|
||||
"""Parse sub-message definitions"""
|
||||
lines = []
|
||||
|
||||
for entry in entries:
|
||||
lines.append(rst_section(entry["name"]))
|
||||
for fmt in entry["formats"]:
|
||||
value = fmt["value"]
|
||||
|
||||
lines.append(rst_bullet(bold(value)))
|
||||
for attr in ['fixed-header', 'attribute-set']:
|
||||
if attr in fmt:
|
||||
lines.append(rst_fields(attr, fmt[attr], 1))
|
||||
lines.append("\n")
|
||||
|
||||
return "\n".join(lines)
|
||||
@ -292,6 +310,11 @@ def parse_yaml(obj: Dict[str, Any]) -> str:
|
||||
lines.append(rst_subtitle("Attribute sets"))
|
||||
lines.append(parse_attr_sets(obj["attribute-sets"]))
|
||||
|
||||
# Sub-messages
|
||||
if "sub-messages" in obj:
|
||||
lines.append(rst_subtitle("Sub-messages"))
|
||||
lines.append(parse_sub_messages(obj["sub-messages"]))
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
@ -360,7 +383,7 @@ def generate_main_index_rst(output: str) -> None:
|
||||
|
||||
index_dir = os.path.dirname(output)
|
||||
logging.debug("Looking for .rst files in %s", index_dir)
|
||||
for filename in os.listdir(index_dir):
|
||||
for filename in sorted(os.listdir(index_dir)):
|
||||
if not filename.endswith(".rst") or filename == "index.rst":
|
||||
continue
|
||||
lines.append(f" {filename.replace('.rst', '')}\n")
|
||||
|
Loading…
x
Reference in New Issue
Block a user