diff options
Diffstat (limited to 'tools/net')
224 files changed, 12272 insertions, 19882 deletions
diff --git a/tools/net/sunrpc/extract.sh b/tools/net/sunrpc/extract.sh new file mode 100755 index 000000000000..f944066f25bc --- /dev/null +++ b/tools/net/sunrpc/extract.sh @@ -0,0 +1,11 @@ +#! /bin/sh +# SPDX-License-Identifier: GPL-2.0 +# +# Extract an RPC protocol specification from an RFC document. +# The version of this script comes from RFC 8166. +# +# Usage: +# $ extract.sh < rfcNNNN.txt > protocol.x +# + +grep '^ *///' | sed 's?^ */// ??' | sed 's?^ *///$??' diff --git a/tools/net/sunrpc/xdrgen/.gitignore b/tools/net/sunrpc/xdrgen/.gitignore new file mode 100644 index 000000000000..d7366c2f9be8 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/.gitignore @@ -0,0 +1,2 @@ +__pycache__ +generators/__pycache__ diff --git a/tools/net/sunrpc/xdrgen/README b/tools/net/sunrpc/xdrgen/README new file mode 100644 index 000000000000..27218a78ab40 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/README @@ -0,0 +1,261 @@ +xdrgen - Linux Kernel XDR code generator + +Introduction +------------ + +SunRPC programs are typically specified using a language defined by +RFC 4506. In fact, all IETF-published NFS specifications provide a +description of the specified protocol using this language. + +Since the 1990's, user space consumers of SunRPC have had access to +a tool that could read such XDR specifications and then generate C +code that implements the RPC portions of that protocol. This tool is +called rpcgen. + +This RPC-level code is code that handles input directly from the +network, and thus a high degree of memory safety and sanity checking +is needed to help ensure proper levels of security. Bugs in this +code can have significant impact on security and performance. + +However, it is code that is repetitive and tedious to write by hand. + +The C code generated by rpcgen makes extensive use of the facilities +of the user space TI-RPC library and libc. Furthermore, the dialect +of the generated code is very traditional K&R C. + +The Linux kernel's implementation of SunRPC-based protocols hand-roll +their XDR implementation. There are two main reasons for this: + +1. libtirpc (and its predecessors) operate only in user space. The + kernel's RPC implementation and its API are significantly + different than libtirpc. + +2. rpcgen-generated code is believed to be less efficient than code + that is hand-written. + +These days, gcc and its kin are capable of optimizing code better +than human authors. There are only a few instances where writing +XDR code by hand will make a measurable performance different. + +In addition, the current hand-written code in the Linux kernel is +difficult to audit and prove that it implements exactly what is in +the protocol specification. + +In order to accrue the benefits of machine-generated XDR code in the +kernel, a tool is needed that will output C code that works against +the kernel's SunRPC implementation rather than libtirpc. + +Enter xdrgen. + + +Dependencies +------------ + +These dependencies are typically packaged by Linux distributions: + +- python3 +- python3-lark +- python3-jinja2 + +These dependencies are available via PyPi: + +- pip install 'lark[interegular]' + + +XDR Specifications +------------------ + +When adding a new protocol implementation to the kernel, the XDR +specification can be derived by feeding a .txt copy of the RFC to +the script located in tools/net/sunrpc/extract.sh. + + $ extract.sh < rfc0001.txt > new2.x + + +Operation +--------- + +Once a .x file is available, use xdrgen to generate source and +header files containing an implementation of XDR encoding and +decoding functions for the specified protocol. + + $ ./xdrgen definitions new2.x > include/linux/sunrpc/xdrgen/new2.h + $ ./xdrgen declarations new2.x > new2xdr_gen.h + +and + + $ ./xdrgen source new2.x > new2xdr_gen.c + +The files are ready to use for a server-side protocol implementation, +or may be used as a guide for implementing these routines by hand. + +By default, the only comments added to this code are kdoc comments +that appear directly in front of the public per-procedure APIs. For +deeper introspection, specifying the "--annotate" flag will insert +additional comments in the generated code to help readers match the +generated code to specific parts of the XDR specification. + +Because the generated code is targeted for the Linux kernel, it +is tagged with a GPLv2-only license. + +The xdrgen tool can also provide lexical and syntax checking of +an XDR specification: + + $ ./xdrgen lint xdr/new.x + + +How It Works +------------ + +xdrgen does not use machine learning to generate source code. The +translation is entirely deterministic. + +RFC 4506 Section 6 contains a BNF grammar of the XDR specification +language. The grammar has been adapted for use by the Python Lark +module. + +The xdr.ebnf file in this directory contains the grammar used to +parse XDR specifications. xdrgen configures Lark using the grammar +in xdr.ebnf. Lark parses the target XDR specification using this +grammar, creating a parse tree. + +xdrgen then transforms the parse tree into an abstract syntax tree. +This tree is passed to a series of code generators. + +The generators are implemented as Python classes residing in the +generators/ directory. Each generator emits code created from Jinja2 +templates stored in the templates/ directory. + +The source code is generated in the same order in which they appear +in the specification to ensure the generated code compiles. This +conforms with the behavior of rpcgen. + +xdrgen assumes that the generated source code is further compiled by +a compiler that can optimize in a number of ways, including: + + - Unused functions are discarded (ie, not added to the executable) + + - Aggressive function inlining removes unnecessary stack frames + + - Single-arm switch statements are replaced by a single conditional + branch + +And so on. + + +Pragmas +------- + +Pragma directives specify exceptions to the normal generation of +encoding and decoding functions. Currently one directive is +implemented: "public". + +Pragma big_endian +------ ---------- + + pragma big_endian <enum> ; + +For variables that might contain only a small number values, it +is more efficient to avoid the byte-swap when encoding or decoding +on little-endian machines. Such is often the case with error status +codes. For example: + + pragma big_endian nfsstat3; + +In this case, when generating an XDR struct or union containing a +field of type "nfsstat3", xdrgen will make the type of that field +"__be32" instead of "enum nfsstat3". XDR unions then switch on the +non-byte-swapped value of that field. + +Pragma exclude +------ ------- + + pragma exclude <RPC procedure> ; + +In some cases, a procedure encoder or decoder function might need +special processing that cannot be automatically generated. The +automatically-generated functions might conflict or interfere with +the hand-rolled function. To avoid editing the generated source code +by hand, a pragma can specify that the procedure's encoder and +decoder functions are not included in the generated header and +source. + +For example: + + pragma exclude NFSPROC3_READDIRPLUS; + +Excludes the decoder function for the READDIRPLUS argument and the +encoder function for the READDIRPLUS result. + +Note that because data item encoder and decoder functions are +defined "static __maybe_unused", subsequent compilation +automatically excludes data item encoder and decoder functions that +are used only by excluded procedure. + +Pragma header +------ ------ + + pragma header <string> ; + +Provide a name to use for the header file. For example: + + pragma header nlm4; + +Adds + + #include "nlm4xdr_gen.h" + +to the generated source file. + +Pragma public +------ ------ + + pragma public <XDR data item> ; + +Normally XDR encoder and decoder functions are "static". In case an +implementer wants to call these functions from other source code, +s/he can add a public pragma in the input .x file to indicate a set +of functions that should get a prototype in the generated header, +and the function definitions will not be declared static. + +For example: + + pragma public nfsstat3; + +Adds these prototypes in the generated header: + + bool xdrgen_decode_nfsstat3(struct xdr_stream *xdr, enum nfsstat3 *ptr); + bool xdrgen_encode_nfsstat3(struct xdr_stream *xdr, enum nfsstat3 value); + +And, in the generated source code, both of these functions appear +without the "static __maybe_unused" modifiers. + + +Future Work +----------- + +Finish implementing XDR pointer and list types. + +Generate client-side procedure functions + +Expand the README into a user guide similar to rpcgen(1) + +Add more pragma directives: + + * @pages -- use xdr_read/write_pages() for the specified opaque + field + * @skip -- do not decode, but rather skip, the specified argument + field + +Enable something like a #include to dynamically insert the content +of other specification files + +Properly support line-by-line pass-through via the "%" decorator + +Build a unit test suite for verifying translation of XDR language +into compilable code + +Add a command-line option to insert trace_printk call sites in the +generated source code, for improved (temporary) observability + +Generate kernel Rust code as well as C code diff --git a/tools/net/sunrpc/xdrgen/__init__.py b/tools/net/sunrpc/xdrgen/__init__.py new file mode 100644 index 000000000000..c940e9275252 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/__init__.py @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +# Just to make sphinx-apidoc document this directory diff --git a/tools/net/sunrpc/xdrgen/generators/__init__.py b/tools/net/sunrpc/xdrgen/generators/__init__.py new file mode 100644 index 000000000000..e22632cf38fb --- /dev/null +++ b/tools/net/sunrpc/xdrgen/generators/__init__.py @@ -0,0 +1,118 @@ +# SPDX-License-Identifier: GPL-2.0 + +"""Define a base code generator class""" + +from pathlib import Path +from jinja2 import Environment, FileSystemLoader, Template + +from xdr_ast import _XdrAst, Specification, _RpcProgram, _XdrTypeSpecifier +from xdr_ast import public_apis, pass_by_reference, get_header_name +from xdr_parse import get_xdr_annotate + + +def create_jinja2_environment(language: str, xdr_type: str) -> Environment: + """Open a set of templates based on output language""" + match language: + case "C": + templates_dir = ( + Path(__file__).parent.parent / "templates" / language / xdr_type + ) + environment = Environment( + loader=FileSystemLoader(templates_dir), + trim_blocks=True, + lstrip_blocks=True, + ) + environment.globals["annotate"] = get_xdr_annotate() + environment.globals["public_apis"] = public_apis + environment.globals["pass_by_reference"] = pass_by_reference + return environment + case _: + raise NotImplementedError("Language not supported") + + +def get_jinja2_template( + environment: Environment, template_type: str, template_name: str +) -> Template: + """Retrieve a Jinja2 template for emitting source code""" + return environment.get_template(template_type + "/" + template_name + ".j2") + + +def find_xdr_program_name(root: Specification) -> str: + """Retrieve the RPC program name from an abstract syntax tree""" + raw_name = get_header_name() + if raw_name != "none": + return raw_name.lower() + for definition in root.definitions: + if isinstance(definition.value, _RpcProgram): + raw_name = definition.value.name + return raw_name.lower().removesuffix("_program").removesuffix("_prog") + return "noprog" + + +def header_guard_infix(filename: str) -> str: + """Extract the header guard infix from the specification filename""" + return Path(filename).stem.upper() + + +def kernel_c_type(spec: _XdrTypeSpecifier) -> str: + """Return name of C type""" + builtin_native_c_type = { + "bool": "bool", + "int": "s32", + "unsigned_int": "u32", + "long": "s32", + "unsigned_long": "u32", + "hyper": "s64", + "unsigned_hyper": "u64", + } + if spec.type_name in builtin_native_c_type: + return builtin_native_c_type[spec.type_name] + return spec.type_name + + +class Boilerplate: + """Base class to generate boilerplate for source files""" + + def __init__(self, language: str, peer: str): + """Initialize an instance of this class""" + raise NotImplementedError("No language support defined") + + def emit_declaration(self, filename: str, root: Specification) -> None: + """Emit declaration header boilerplate""" + raise NotImplementedError("Header boilerplate generation not supported") + + def emit_definition(self, filename: str, root: Specification) -> None: + """Emit definition header boilerplate""" + raise NotImplementedError("Header boilerplate generation not supported") + + def emit_source(self, filename: str, root: Specification) -> None: + """Emit generic source code for this XDR type""" + raise NotImplementedError("Source boilerplate generation not supported") + + +class SourceGenerator: + """Base class to generate header and source code for XDR types""" + + def __init__(self, language: str, peer: str): + """Initialize an instance of this class""" + raise NotImplementedError("No language support defined") + + def emit_declaration(self, node: _XdrAst) -> None: + """Emit one function declaration for this XDR type""" + raise NotImplementedError("Declaration generation not supported") + + def emit_decoder(self, node: _XdrAst) -> None: + """Emit one decoder function for this XDR type""" + raise NotImplementedError("Decoder generation not supported") + + def emit_definition(self, node: _XdrAst) -> None: + """Emit one definition for this XDR type""" + raise NotImplementedError("Definition generation not supported") + + def emit_encoder(self, node: _XdrAst) -> None: + """Emit one encoder function for this XDR type""" + raise NotImplementedError("Encoder generation not supported") + + def emit_maxsize(self, node: _XdrAst) -> None: + """Emit one maxsize macro for this XDR type""" + raise NotImplementedError("Maxsize macro generation not supported") diff --git a/tools/net/sunrpc/xdrgen/generators/constant.py b/tools/net/sunrpc/xdrgen/generators/constant.py new file mode 100644 index 000000000000..f2339caf0953 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/generators/constant.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python3 +# ex: set filetype=python: + +"""Generate code to handle XDR constants""" + +from generators import SourceGenerator, create_jinja2_environment +from xdr_ast import _XdrConstant + +class XdrConstantGenerator(SourceGenerator): + """Generate source code for XDR constants""" + + def __init__(self, language: str, peer: str): + """Initialize an instance of this class""" + self.environment = create_jinja2_environment(language, "constants") + self.peer = peer + + def emit_definition(self, node: _XdrConstant) -> None: + """Emit one definition for a constant""" + template = self.environment.get_template("definition.j2") + print(template.render(name=node.name, value=node.value)) diff --git a/tools/net/sunrpc/xdrgen/generators/enum.py b/tools/net/sunrpc/xdrgen/generators/enum.py new file mode 100644 index 000000000000..e62f715d3996 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/generators/enum.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 +# ex: set filetype=python: + +"""Generate code to handle XDR enum types""" + +from generators import SourceGenerator, create_jinja2_environment +from xdr_ast import _XdrEnum, public_apis, big_endian, get_header_name + + +class XdrEnumGenerator(SourceGenerator): + """Generate source code for XDR enum types""" + + def __init__(self, language: str, peer: str): + """Initialize an instance of this class""" + self.environment = create_jinja2_environment(language, "enum") + self.peer = peer + + def emit_declaration(self, node: _XdrEnum) -> None: + """Emit one declaration pair for an XDR enum type""" + if node.name in public_apis: + template = self.environment.get_template("declaration/enum.j2") + print(template.render(name=node.name)) + + def emit_definition(self, node: _XdrEnum) -> None: + """Emit one definition for an XDR enum type""" + template = self.environment.get_template("definition/open.j2") + print(template.render(name=node.name)) + + template = self.environment.get_template("definition/enumerator.j2") + for enumerator in node.enumerators: + print(template.render(name=enumerator.name, value=enumerator.value)) + + if node.name in big_endian: + template = self.environment.get_template("definition/close_be.j2") + else: + template = self.environment.get_template("definition/close.j2") + print(template.render(name=node.name)) + + def emit_decoder(self, node: _XdrEnum) -> None: + """Emit one decoder function for an XDR enum type""" + if node.name in big_endian: + template = self.environment.get_template("decoder/enum_be.j2") + else: + template = self.environment.get_template("decoder/enum.j2") + print(template.render(name=node.name)) + + def emit_encoder(self, node: _XdrEnum) -> None: + """Emit one encoder function for an XDR enum type""" + if node.name in big_endian: + template = self.environment.get_template("encoder/enum_be.j2") + else: + template = self.environment.get_template("encoder/enum.j2") + print(template.render(name=node.name)) + + def emit_maxsize(self, node: _XdrEnum) -> None: + """Emit one maxsize macro for an XDR enum type""" + macro_name = get_header_name().upper() + "_" + node.name + "_sz" + template = self.environment.get_template("maxsize/enum.j2") + print( + template.render( + macro=macro_name, + width=" + ".join(node.symbolic_width()), + ) + ) diff --git a/tools/net/sunrpc/xdrgen/generators/header_bottom.py b/tools/net/sunrpc/xdrgen/generators/header_bottom.py new file mode 100644 index 000000000000..4b55b282dfc0 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/generators/header_bottom.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 +# ex: set filetype=python: + +"""Generate header bottom boilerplate""" + +import os.path +import time + +from generators import Boilerplate, header_guard_infix +from generators import create_jinja2_environment, get_jinja2_template +from xdr_ast import Specification + + +class XdrHeaderBottomGenerator(Boilerplate): + """Generate header boilerplate""" + + def __init__(self, language: str, peer: str): + """Initialize an instance of this class""" + self.environment = create_jinja2_environment(language, "header_bottom") + self.peer = peer + + def emit_declaration(self, filename: str, root: Specification) -> None: + """Emit the bottom header guard""" + template = get_jinja2_template(self.environment, "declaration", "header") + print(template.render(infix=header_guard_infix(filename))) + + def emit_definition(self, filename: str, root: Specification) -> None: + """Emit the bottom header guard""" + template = get_jinja2_template(self.environment, "definition", "header") + print(template.render(infix=header_guard_infix(filename))) + + def emit_source(self, filename: str, root: Specification) -> None: + pass diff --git a/tools/net/sunrpc/xdrgen/generators/header_top.py b/tools/net/sunrpc/xdrgen/generators/header_top.py new file mode 100644 index 000000000000..c6bc21c71f19 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/generators/header_top.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python3 +# ex: set filetype=python: + +"""Generate header top boilerplate""" + +import os.path +import time + +from generators import Boilerplate, header_guard_infix +from generators import create_jinja2_environment, get_jinja2_template +from xdr_ast import Specification + + +class XdrHeaderTopGenerator(Boilerplate): + """Generate header boilerplate""" + + def __init__(self, language: str, peer: str): + """Initialize an instance of this class""" + self.environment = create_jinja2_environment(language, "header_top") + self.peer = peer + + def emit_declaration(self, filename: str, root: Specification) -> None: + """Emit the top header guard""" + template = get_jinja2_template(self.environment, "declaration", "header") + print( + template.render( + infix=header_guard_infix(filename), + filename=filename, + mtime=time.ctime(os.path.getmtime(filename)), + ) + ) + + def emit_definition(self, filename: str, root: Specification) -> None: + """Emit the top header guard""" + template = get_jinja2_template(self.environment, "definition", "header") + print( + template.render( + infix=header_guard_infix(filename), + filename=filename, + mtime=time.ctime(os.path.getmtime(filename)), + ) + ) + + def emit_source(self, filename: str, root: Specification) -> None: + pass diff --git a/tools/net/sunrpc/xdrgen/generators/pointer.py b/tools/net/sunrpc/xdrgen/generators/pointer.py new file mode 100644 index 000000000000..6dbda60ad2db --- /dev/null +++ b/tools/net/sunrpc/xdrgen/generators/pointer.py @@ -0,0 +1,288 @@ +#!/usr/bin/env python3 +# ex: set filetype=python: + +"""Generate code to handle XDR pointer types""" + +from jinja2 import Environment + +from generators import SourceGenerator, kernel_c_type +from generators import create_jinja2_environment, get_jinja2_template + +from xdr_ast import _XdrBasic, _XdrString +from xdr_ast import _XdrFixedLengthOpaque, _XdrVariableLengthOpaque +from xdr_ast import _XdrFixedLengthArray, _XdrVariableLengthArray +from xdr_ast import _XdrOptionalData, _XdrPointer, _XdrDeclaration +from xdr_ast import public_apis, get_header_name + + +def emit_pointer_declaration(environment: Environment, node: _XdrPointer) -> None: + """Emit a declaration pair for an XDR pointer type""" + if node.name in public_apis: + template = get_jinja2_template(environment, "declaration", "close") + print(template.render(name=node.name)) + + +def emit_pointer_member_definition( + environment: Environment, field: _XdrDeclaration +) -> None: + """Emit a definition for one field in an XDR struct""" + if isinstance(field, _XdrBasic): + template = get_jinja2_template(environment, "definition", field.template) + print( + template.render( + name=field.name, + type=kernel_c_type(field.spec), + classifier=field.spec.c_classifier, + ) + ) + elif isinstance(field, _XdrFixedLengthOpaque): + template = get_jinja2_template(environment, "definition", field.template) + print( + template.render( + name=field.name, + size=field.size, + ) + ) + elif isinstance(field, _XdrVariableLengthOpaque): + template = get_jinja2_template(environment, "definition", field.template) + print(template.render(name=field.name)) + elif isinstance(field, _XdrString): + template = get_jinja2_template(environment, "definition", field.template) + print(template.render(name=field.name)) + elif isinstance(field, _XdrFixedLengthArray): + template = get_jinja2_template(environment, "definition", field.template) + print( + template.render( + name=field.name, + type=kernel_c_type(field.spec), + size=field.size, + ) + ) + elif isinstance(field, _XdrVariableLengthArray): + template = get_jinja2_template(environment, "definition", field.template) + print( + template.render( + name=field.name, + type=kernel_c_type(field.spec), + classifier=field.spec.c_classifier, + ) + ) + elif isinstance(field, _XdrOptionalData): + template = get_jinja2_template(environment, "definition", field.template) + print( + template.render( + name=field.name, + type=kernel_c_type(field.spec), + classifier=field.spec.c_classifier, + ) + ) + + +def emit_pointer_definition(environment: Environment, node: _XdrPointer) -> None: + """Emit a definition for an XDR pointer type""" + template = get_jinja2_template(environment, "definition", "open") + print(template.render(name=node.name)) + + for field in node.fields[0:-1]: + emit_pointer_member_definition(environment, field) + + template = get_jinja2_template(environment, "definition", "close") + print(template.render(name=node.name)) + + +def emit_pointer_member_decoder( + environment: Environment, field: _XdrDeclaration +) -> None: + """Emit a decoder for one field in an XDR pointer""" + if isinstance(field, _XdrBasic): + template = get_jinja2_template(environment, "decoder", field.template) + print( + template.render( + name=field.name, + type=field.spec.type_name, + classifier=field.spec.c_classifier, + ) + ) + elif isinstance(field, _XdrFixedLengthOpaque): + template = get_jinja2_template(environment, "decoder", field.template) + print( + template.render( + name=field.name, + size=field.size, + ) + ) + elif isinstance(field, _XdrVariableLengthOpaque): + template = get_jinja2_template(environment, "decoder", field.template) + print( + template.render( + name=field.name, + maxsize=field.maxsize, + ) + ) + elif isinstance(field, _XdrString): + template = get_jinja2_template(environment, "decoder", field.template) + print( + template.render( + name=field.name, + maxsize=field.maxsize, + ) + ) + elif isinstance(field, _XdrFixedLengthArray): + template = get_jinja2_template(environment, "decoder", field.template) + print( + template.render( + name=field.name, + type=field.spec.type_name, + size=field.size, + classifier=field.spec.c_classifier, + ) + ) + elif isinstance(field, _XdrVariableLengthArray): + template = get_jinja2_template(environment, "decoder", field.template) + print( + template.render( + name=field.name, + type=field.spec.type_name, + maxsize=field.maxsize, + classifier=field.spec.c_classifier, + ) + ) + elif isinstance(field, _XdrOptionalData): + template = get_jinja2_template(environment, "decoder", field.template) + print( + template.render( + name=field.name, + type=field.spec.type_name, + classifier=field.spec.c_classifier, + ) + ) + + +def emit_pointer_decoder(environment: Environment, node: _XdrPointer) -> None: + """Emit one decoder function for an XDR pointer type""" + template = get_jinja2_template(environment, "decoder", "open") + print(template.render(name=node.name)) + + for field in node.fields[0:-1]: + emit_pointer_member_decoder(environment, field) + + template = get_jinja2_template(environment, "decoder", "close") + print(template.render()) + + +def emit_pointer_member_encoder( + environment: Environment, field: _XdrDeclaration +) -> None: + """Emit an encoder for one field in a XDR pointer""" + if isinstance(field, _XdrBasic): + template = get_jinja2_template(environment, "encoder", field.template) + print( + template.render( + name=field.name, + type=field.spec.type_name, + ) + ) + elif isinstance(field, _XdrFixedLengthOpaque): + template = get_jinja2_template(environment, "encoder", field.template) + print( + template.render( + name=field.name, + size=field.size, + ) + ) + elif isinstance(field, _XdrVariableLengthOpaque): + template = get_jinja2_template(environment, "encoder", field.template) + print( + template.render( + name=field.name, + maxsize=field.maxsize, + ) + ) + elif isinstance(field, _XdrString): + template = get_jinja2_template(environment, "encoder", field.template) + print( + template.render( + name=field.name, + maxsize=field.maxsize, + ) + ) + elif isinstance(field, _XdrFixedLengthArray): + template = get_jinja2_template(environment, "encoder", field.template) + print( + template.render( + name=field.name, + type=field.spec.type_name, + size=field.size, + ) + ) + elif isinstance(field, _XdrVariableLengthArray): + template = get_jinja2_template(environment, "encoder", field.template) + print( + template.render( + name=field.name, + type=field.spec.type_name, + maxsize=field.maxsize, + ) + ) + elif isinstance(field, _XdrOptionalData): + template = get_jinja2_template(environment, "encoder", field.template) + print( + template.render( + name=field.name, + type=field.spec.type_name, + classifier=field.spec.c_classifier, + ) + ) + + +def emit_pointer_encoder(environment: Environment, node: _XdrPointer) -> None: + """Emit one encoder function for an XDR pointer type""" + template = get_jinja2_template(environment, "encoder", "open") + print(template.render(name=node.name)) + + for field in node.fields[0:-1]: + emit_pointer_member_encoder(environment, field) + + template = get_jinja2_template(environment, "encoder", "close") + print(template.render()) + + +def emit_pointer_maxsize(environment: Environment, node: _XdrPointer) -> None: + """Emit one maxsize macro for an XDR pointer type""" + macro_name = get_header_name().upper() + "_" + node.name + "_sz" + template = get_jinja2_template(environment, "maxsize", "pointer") + print( + template.render( + macro=macro_name, + width=" + ".join(node.symbolic_width()), + ) + ) + + +class XdrPointerGenerator(SourceGenerator): + """Generate source code for XDR pointer""" + + def __init__(self, language: str, peer: str): + """Initialize an instance of this class""" + self.environment = create_jinja2_environment(language, "pointer") + self.peer = peer + + def emit_declaration(self, node: _XdrPointer) -> None: + """Emit one declaration pair for an XDR pointer type""" + emit_pointer_declaration(self.environment, node) + + def emit_definition(self, node: _XdrPointer) -> None: + """Emit one declaration for an XDR pointer type""" + emit_pointer_definition(self.environment, node) + + def emit_decoder(self, node: _XdrPointer) -> None: + """Emit one decoder function for an XDR pointer type""" + emit_pointer_decoder(self.environment, node) + + def emit_encoder(self, node: _XdrPointer) -> None: + """Emit one encoder function for an XDR pointer type""" + emit_pointer_encoder(self.environment, node) + + def emit_maxsize(self, node: _XdrPointer) -> None: + """Emit one maxsize macro for an XDR pointer type""" + emit_pointer_maxsize(self.environment, node) diff --git a/tools/net/sunrpc/xdrgen/generators/program.py b/tools/net/sunrpc/xdrgen/generators/program.py new file mode 100644 index 000000000000..ac3cf1694b68 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/generators/program.py @@ -0,0 +1,168 @@ +#!/usr/bin/env python3 +# ex: set filetype=python: + +"""Generate code for an RPC program's procedures""" + +from jinja2 import Environment + +from generators import SourceGenerator, create_jinja2_environment +from xdr_ast import _RpcProgram, _RpcVersion, excluded_apis + + +def emit_version_definitions( + environment: Environment, program: str, version: _RpcVersion +) -> None: + """Emit procedure numbers for each RPC version's procedures""" + template = environment.get_template("definition/open.j2") + print(template.render(program=program.upper())) + + template = environment.get_template("definition/procedure.j2") + for procedure in version.procedures: + if procedure.name not in excluded_apis: + print( + template.render( + name=procedure.name, + value=procedure.number, + ) + ) + + template = environment.get_template("definition/close.j2") + print(template.render()) + + +def emit_version_declarations( + environment: Environment, program: str, version: _RpcVersion +) -> None: + """Emit declarations for each RPC version's procedures""" + arguments = dict.fromkeys([]) + for procedure in version.procedures: + if procedure.name not in excluded_apis: + arguments[procedure.argument.type_name] = None + if len(arguments) > 0: + print("") + template = environment.get_template("declaration/argument.j2") + for argument in arguments: + print(template.render(program=program, argument=argument)) + + results = dict.fromkeys([]) + for procedure in version.procedures: + if procedure.name not in excluded_apis: + results[procedure.result.type_name] = None + if len(results) > 0: + print("") + template = environment.get_template("declaration/result.j2") + for result in results: + print(template.render(program=program, result=result)) + + +def emit_version_argument_decoders( + environment: Environment, program: str, version: _RpcVersion +) -> None: + """Emit server argument decoders for each RPC version's procedures""" + arguments = dict.fromkeys([]) + for procedure in version.procedures: + if procedure.name not in excluded_apis: + arguments[procedure.argument.type_name] = None + + template = environment.get_template("decoder/argument.j2") + for argument in arguments: + print(template.render(program=program, argument=argument)) + + +def emit_version_result_decoders( + environment: Environment, program: str, version: _RpcVersion +) -> None: + """Emit client result decoders for each RPC version's procedures""" + results = dict.fromkeys([]) + for procedure in version.procedures: + if procedure.name not in excluded_apis: + results[procedure.result.type_name] = None + + template = environment.get_template("decoder/result.j2") + for result in results: + print(template.render(program=program, result=result)) + + +def emit_version_argument_encoders( + environment: Environment, program: str, version: _RpcVersion +) -> None: + """Emit client argument encoders for each RPC version's procedures""" + arguments = dict.fromkeys([]) + for procedure in version.procedures: + if procedure.name not in excluded_apis: + arguments[procedure.argument.type_name] = None + + template = environment.get_template("encoder/argument.j2") + for argument in arguments: + print(template.render(program=program, argument=argument)) + + +def emit_version_result_encoders( + environment: Environment, program: str, version: _RpcVersion +) -> None: + """Emit server result encoders for each RPC version's procedures""" + results = dict.fromkeys([]) + for procedure in version.procedures: + if procedure.name not in excluded_apis: + results[procedure.result.type_name] = None + + template = environment.get_template("encoder/result.j2") + for result in results: + print(template.render(program=program, result=result)) + + +class XdrProgramGenerator(SourceGenerator): + """Generate source code for an RPC program's procedures""" + + def __init__(self, language: str, peer: str): + """Initialize an instance of this class""" + self.environment = create_jinja2_environment(language, "program") + self.peer = peer + + def emit_definition(self, node: _RpcProgram) -> None: + """Emit procedure numbers for each of an RPC programs's procedures""" + raw_name = node.name + program = raw_name.lower().removesuffix("_program").removesuffix("_prog") + + for version in node.versions: + emit_version_definitions(self.environment, program, version) + + def emit_declaration(self, node: _RpcProgram) -> None: + """Emit a declaration pair for each of an RPC programs's procedures""" + raw_name = node.name + program = raw_name.lower().removesuffix("_program").removesuffix("_prog") + + for version in node.versions: + emit_version_declarations(self.environment, program, version) + + def emit_decoder(self, node: _RpcProgram) -> None: + """Emit all decoder functions for an RPC program's procedures""" + raw_name = node.name + program = raw_name.lower().removesuffix("_program").removesuffix("_prog") + match self.peer: + case "server": + for version in node.versions: + emit_version_argument_decoders( + self.environment, program, version, + ) + case "client": + for version in node.versions: + emit_version_result_decoders( + self.environment, program, version, + ) + + def emit_encoder(self, node: _RpcProgram) -> None: + """Emit all encoder functions for an RPC program's procedures""" + raw_name = node.name + program = raw_name.lower().removesuffix("_program").removesuffix("_prog") + match self.peer: + case "server": + for version in node.versions: + emit_version_result_encoders( + self.environment, program, version, + ) + case "client": + for version in node.versions: + emit_version_argument_encoders( + self.environment, program, version, + ) diff --git a/tools/net/sunrpc/xdrgen/generators/source_top.py b/tools/net/sunrpc/xdrgen/generators/source_top.py new file mode 100644 index 000000000000..bcf47d93d6f1 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/generators/source_top.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python3 +# ex: set filetype=python: + +"""Generate source code boilerplate""" + +import os.path +import time + +from generators import Boilerplate +from generators import find_xdr_program_name, create_jinja2_environment +from xdr_ast import _RpcProgram, Specification, get_header_name + + +class XdrSourceTopGenerator(Boilerplate): + """Generate source code boilerplate""" + + def __init__(self, language: str, peer: str): + """Initialize an instance of this class""" + self.environment = create_jinja2_environment(language, "source_top") + self.peer = peer + + def emit_source(self, filename: str, root: Specification) -> None: + """Emit the top source boilerplate""" + name = find_xdr_program_name(root) + template = self.environment.get_template(self.peer + ".j2") + print( + template.render( + program=name, + filename=filename, + mtime=time.ctime(os.path.getmtime(filename)), + ) + ) diff --git a/tools/net/sunrpc/xdrgen/generators/struct.py b/tools/net/sunrpc/xdrgen/generators/struct.py new file mode 100644 index 000000000000..64911de46f62 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/generators/struct.py @@ -0,0 +1,288 @@ +#!/usr/bin/env python3 +# ex: set filetype=python: + +"""Generate code to handle XDR struct types""" + +from jinja2 import Environment + +from generators import SourceGenerator, kernel_c_type +from generators import create_jinja2_environment, get_jinja2_template + +from xdr_ast import _XdrBasic, _XdrString +from xdr_ast import _XdrFixedLengthOpaque, _XdrVariableLengthOpaque +from xdr_ast import _XdrFixedLengthArray, _XdrVariableLengthArray +from xdr_ast import _XdrOptionalData, _XdrStruct, _XdrDeclaration +from xdr_ast import public_apis, get_header_name + + +def emit_struct_declaration(environment: Environment, node: _XdrStruct) -> None: + """Emit one declaration pair for an XDR struct type""" + if node.name in public_apis: + template = get_jinja2_template(environment, "declaration", "close") + print(template.render(name=node.name)) + + +def emit_struct_member_definition( + environment: Environment, field: _XdrDeclaration +) -> None: + """Emit a definition for one field in an XDR struct""" + if isinstance(field, _XdrBasic): + template = get_jinja2_template(environment, "definition", field.template) + print( + template.render( + name=field.name, + type=kernel_c_type(field.spec), + classifier=field.spec.c_classifier, + ) + ) + elif isinstance(field, _XdrFixedLengthOpaque): + template = get_jinja2_template(environment, "definition", field.template) + print( + template.render( + name=field.name, + size=field.size, + ) + ) + elif isinstance(field, _XdrVariableLengthOpaque): + template = get_jinja2_template(environment, "definition", field.template) + print(template.render(name=field.name)) + elif isinstance(field, _XdrString): + template = get_jinja2_template(environment, "definition", field.template) + print(template.render(name=field.name)) + elif isinstance(field, _XdrFixedLengthArray): + template = get_jinja2_template(environment, "definition", field.template) + print( + template.render( + name=field.name, + type=kernel_c_type(field.spec), + size=field.size, + ) + ) + elif isinstance(field, _XdrVariableLengthArray): + template = get_jinja2_template(environment, "definition", field.template) + print( + template.render( + name=field.name, + type=kernel_c_type(field.spec), + classifier=field.spec.c_classifier, + ) + ) + elif isinstance(field, _XdrOptionalData): + template = get_jinja2_template(environment, "definition", field.template) + print( + template.render( + name=field.name, + type=kernel_c_type(field.spec), + classifier=field.spec.c_classifier, + ) + ) + + +def emit_struct_definition(environment: Environment, node: _XdrStruct) -> None: + """Emit one definition for an XDR struct type""" + template = get_jinja2_template(environment, "definition", "open") + print(template.render(name=node.name)) + + for field in node.fields: + emit_struct_member_definition(environment, field) + + template = get_jinja2_template(environment, "definition", "close") + print(template.render(name=node.name)) + + +def emit_struct_member_decoder( + environment: Environment, field: _XdrDeclaration +) -> None: + """Emit a decoder for one field in an XDR struct""" + if isinstance(field, _XdrBasic): + template = get_jinja2_template(environment, "decoder", field.template) + print( + template.render( + name=field.name, + type=field.spec.type_name, + classifier=field.spec.c_classifier, + ) + ) + elif isinstance(field, _XdrFixedLengthOpaque): + template = get_jinja2_template(environment, "decoder", field.template) + print( + template.render( + name=field.name, + size=field.size, + ) + ) + elif isinstance(field, _XdrVariableLengthOpaque): + template = get_jinja2_template(environment, "decoder", field.template) + print( + template.render( + name=field.name, + maxsize=field.maxsize, + ) + ) + elif isinstance(field, _XdrString): + template = get_jinja2_template(environment, "decoder", field.template) + print( + template.render( + name=field.name, + maxsize=field.maxsize, + ) + ) + elif isinstance(field, _XdrFixedLengthArray): + template = get_jinja2_template(environment, "decoder", field.template) + print( + template.render( + name=field.name, + type=field.spec.type_name, + size=field.size, + classifier=field.spec.c_classifier, + ) + ) + elif isinstance(field, _XdrVariableLengthArray): + template = get_jinja2_template(environment, "decoder", field.template) + print( + template.render( + name=field.name, + type=field.spec.type_name, + maxsize=field.maxsize, + classifier=field.spec.c_classifier, + ) + ) + elif isinstance(field, _XdrOptionalData): + template = get_jinja2_template(environment, "decoder", field.template) + print( + template.render( + name=field.name, + type=field.spec.type_name, + classifier=field.spec.c_classifier, + ) + ) + + +def emit_struct_decoder(environment: Environment, node: _XdrStruct) -> None: + """Emit one decoder function for an XDR struct type""" + template = get_jinja2_template(environment, "decoder", "open") + print(template.render(name=node.name)) + + for field in node.fields: + emit_struct_member_decoder(environment, field) + + template = get_jinja2_template(environment, "decoder", "close") + print(template.render()) + + +def emit_struct_member_encoder( + environment: Environment, field: _XdrDeclaration +) -> None: + """Emit an encoder for one field in an XDR struct""" + if isinstance(field, _XdrBasic): + template = get_jinja2_template(environment, "encoder", field.template) + print( + template.render( + name=field.name, + type=field.spec.type_name, + ) + ) + elif isinstance(field, _XdrFixedLengthOpaque): + template = get_jinja2_template(environment, "encoder", field.template) + print( + template.render( + name=field.name, + size=field.size, + ) + ) + elif isinstance(field, _XdrVariableLengthOpaque): + template = get_jinja2_template(environment, "encoder", field.template) + print( + template.render( + name=field.name, + maxsize=field.maxsize, + ) + ) + elif isinstance(field, _XdrString): + template = get_jinja2_template(environment, "encoder", field.template) + print( + template.render( + name=field.name, + maxsize=field.maxsize, + ) + ) + elif isinstance(field, _XdrFixedLengthArray): + template = get_jinja2_template(environment, "encoder", field.template) + print( + template.render( + name=field.name, + type=field.spec.type_name, + size=field.size, + ) + ) + elif isinstance(field, _XdrVariableLengthArray): + template = get_jinja2_template(environment, "encoder", field.template) + print( + template.render( + name=field.name, + type=field.spec.type_name, + maxsize=field.maxsize, + ) + ) + elif isinstance(field, _XdrOptionalData): + template = get_jinja2_template(environment, "encoder", field.template) + print( + template.render( + name=field.name, + type=field.spec.type_name, + classifier=field.spec.c_classifier, + ) + ) + + +def emit_struct_encoder(environment: Environment, node: _XdrStruct) -> None: + """Emit one encoder function for an XDR struct type""" + template = get_jinja2_template(environment, "encoder", "open") + print(template.render(name=node.name)) + + for field in node.fields: + emit_struct_member_encoder(environment, field) + + template = get_jinja2_template(environment, "encoder", "close") + print(template.render()) + + +def emit_struct_maxsize(environment: Environment, node: _XdrStruct) -> None: + """Emit one maxsize macro for an XDR struct type""" + macro_name = get_header_name().upper() + "_" + node.name + "_sz" + template = get_jinja2_template(environment, "maxsize", "struct") + print( + template.render( + macro=macro_name, + width=" + ".join(node.symbolic_width()), + ) + ) + + +class XdrStructGenerator(SourceGenerator): + """Generate source code for XDR structs""" + + def __init__(self, language: str, peer: str): + """Initialize an instance of this class""" + self.environment = create_jinja2_environment(language, "struct") + self.peer = peer + + def emit_declaration(self, node: _XdrStruct) -> None: + """Emit one declaration pair for an XDR struct type""" + emit_struct_declaration(self.environment, node) + + def emit_definition(self, node: _XdrStruct) -> None: + """Emit one definition for an XDR struct type""" + emit_struct_definition(self.environment, node) + + def emit_decoder(self, node: _XdrStruct) -> None: + """Emit one decoder function for an XDR struct type""" + emit_struct_decoder(self.environment, node) + + def emit_encoder(self, node: _XdrStruct) -> None: + """Emit one encoder function for an XDR struct type""" + emit_struct_encoder(self.environment, node) + + def emit_maxsize(self, node: _XdrStruct) -> None: + """Emit one maxsize macro for an XDR struct type""" + emit_struct_maxsize(self.environment, node) diff --git a/tools/net/sunrpc/xdrgen/generators/typedef.py b/tools/net/sunrpc/xdrgen/generators/typedef.py new file mode 100644 index 000000000000..fab72e9d6915 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/generators/typedef.py @@ -0,0 +1,271 @@ +#!/usr/bin/env python3 +# ex: set filetype=python: + +"""Generate code to handle XDR typedefs""" + +from jinja2 import Environment + +from generators import SourceGenerator, kernel_c_type +from generators import create_jinja2_environment, get_jinja2_template + +from xdr_ast import _XdrBasic, _XdrTypedef, _XdrString +from xdr_ast import _XdrFixedLengthOpaque, _XdrVariableLengthOpaque +from xdr_ast import _XdrFixedLengthArray, _XdrVariableLengthArray +from xdr_ast import _XdrOptionalData, _XdrVoid, _XdrDeclaration +from xdr_ast import public_apis, get_header_name + + +def emit_typedef_declaration(environment: Environment, node: _XdrDeclaration) -> None: + """Emit a declaration pair for one XDR typedef""" + if node.name not in public_apis: + return + if isinstance(node, _XdrBasic): + template = get_jinja2_template(environment, "declaration", node.template) + print( + template.render( + name=node.name, + type=kernel_c_type(node.spec), + classifier=node.spec.c_classifier, + ) + ) + elif isinstance(node, _XdrString): + template = get_jinja2_template(environment, "declaration", node.template) + print(template.render(name=node.name)) + elif isinstance(node, _XdrFixedLengthOpaque): + template = get_jinja2_template(environment, "declaration", node.template) + print(template.render(name=node.name, size=node.size)) + elif isinstance(node, _XdrVariableLengthOpaque): + template = get_jinja2_template(environment, "declaration", node.template) + print(template.render(name=node.name)) + elif isinstance(node, _XdrFixedLengthArray): + template = get_jinja2_template(environment, "declaration", node.template) + print( + template.render( + name=node.name, + type=node.spec.type_name, + size=node.size, + ) + ) + elif isinstance(node, _XdrVariableLengthArray): + template = get_jinja2_template(environment, "declaration", node.template) + print( + template.render( + name=node.name, + type=node.spec.type_name, + classifier=node.spec.c_classifier, + ) + ) + elif isinstance(node, _XdrOptionalData): + raise NotImplementedError("<optional_data> typedef not yet implemented") + elif isinstance(node, _XdrVoid): + raise NotImplementedError("<void> typedef not yet implemented") + else: + raise NotImplementedError("typedef: type not recognized") + + +def emit_type_definition(environment: Environment, node: _XdrDeclaration) -> None: + """Emit a definition for one XDR typedef""" + if isinstance(node, _XdrBasic): + template = get_jinja2_template(environment, "definition", node.template) + print( + template.render( + name=node.name, + type=kernel_c_type(node.spec), + classifier=node.spec.c_classifier, + ) + ) + elif isinstance(node, _XdrString): + template = get_jinja2_template(environment, "definition", node.template) + print(template.render(name=node.name)) + elif isinstance(node, _XdrFixedLengthOpaque): + template = get_jinja2_template(environment, "definition", node.template) + print(template.render(name=node.name, size=node.size)) + elif isinstance(node, _XdrVariableLengthOpaque): + template = get_jinja2_template(environment, "definition", node.template) + print(template.render(name=node.name)) + elif isinstance(node, _XdrFixedLengthArray): + template = get_jinja2_template(environment, "definition", node.template) + print( + template.render( + name=node.name, + type=node.spec.type_name, + size=node.size, + ) + ) + elif isinstance(node, _XdrVariableLengthArray): + template = get_jinja2_template(environment, "definition", node.template) + print( + template.render( + name=node.name, + type=node.spec.type_name, + classifier=node.spec.c_classifier, + ) + ) + elif isinstance(node, _XdrOptionalData): + raise NotImplementedError("<optional_data> typedef not yet implemented") + elif isinstance(node, _XdrVoid): + raise NotImplementedError("<void> typedef not yet implemented") + else: + raise NotImplementedError("typedef: type not recognized") + + +def emit_typedef_decoder(environment: Environment, node: _XdrDeclaration) -> None: + """Emit a decoder function for one XDR typedef""" + if isinstance(node, _XdrBasic): + template = get_jinja2_template(environment, "decoder", node.template) + print( + template.render( + name=node.name, + type=node.spec.type_name, + ) + ) + elif isinstance(node, _XdrString): + template = get_jinja2_template(environment, "decoder", node.template) + print( + template.render( + name=node.name, + maxsize=node.maxsize, + ) + ) + elif isinstance(node, _XdrFixedLengthOpaque): + template = get_jinja2_template(environment, "decoder", node.template) + print( + template.render( + name=node.name, + size=node.size, + ) + ) + elif isinstance(node, _XdrVariableLengthOpaque): + template = get_jinja2_template(environment, "decoder", node.template) + print( + template.render( + name=node.name, + maxsize=node.maxsize, + ) + ) + elif isinstance(node, _XdrFixedLengthArray): + template = get_jinja2_template(environment, "decoder", node.template) + print( + template.render( + name=node.name, + type=node.spec.type_name, + size=node.size, + classifier=node.spec.c_classifier, + ) + ) + elif isinstance(node, _XdrVariableLengthArray): + template = get_jinja2_template(environment, "decoder", node.template) + print( + template.render( + name=node.name, + type=node.spec.type_name, + maxsize=node.maxsize, + ) + ) + elif isinstance(node, _XdrOptionalData): + raise NotImplementedError("<optional_data> typedef not yet implemented") + elif isinstance(node, _XdrVoid): + raise NotImplementedError("<void> typedef not yet implemented") + else: + raise NotImplementedError("typedef: type not recognized") + + +def emit_typedef_encoder(environment: Environment, node: _XdrDeclaration) -> None: + """Emit an encoder function for one XDR typedef""" + if isinstance(node, _XdrBasic): + template = get_jinja2_template(environment, "encoder", node.template) + print( + template.render( + name=node.name, + type=node.spec.type_name, + ) + ) + elif isinstance(node, _XdrString): + template = get_jinja2_template(environment, "encoder", node.template) + print( + template.render( + name=node.name, + maxsize=node.maxsize, + ) + ) + elif isinstance(node, _XdrFixedLengthOpaque): + template = get_jinja2_template(environment, "encoder", node.template) + print( + template.render( + name=node.name, + size=node.size, + ) + ) + elif isinstance(node, _XdrVariableLengthOpaque): + template = get_jinja2_template(environment, "encoder", node.template) + print( + template.render( + name=node.name, + maxsize=node.maxsize, + ) + ) + elif isinstance(node, _XdrFixedLengthArray): + template = get_jinja2_template(environment, "encoder", node.template) + print( + template.render( + name=node.name, + type=node.spec.type_name, + size=node.size, + ) + ) + elif isinstance(node, _XdrVariableLengthArray): + template = get_jinja2_template(environment, "encoder", node.template) + print( + template.render( + name=node.name, + type=node.spec.type_name, + maxsize=node.maxsize, + ) + ) + elif isinstance(node, _XdrOptionalData): + raise NotImplementedError("<optional_data> typedef not yet implemented") + elif isinstance(node, _XdrVoid): + raise NotImplementedError("<void> typedef not yet implemented") + else: + raise NotImplementedError("typedef: type not recognized") + + +def emit_typedef_maxsize(environment: Environment, node: _XdrDeclaration) -> None: + """Emit a maxsize macro for an XDR typedef""" + macro_name = get_header_name().upper() + "_" + node.name + "_sz" + template = get_jinja2_template(environment, "maxsize", node.template) + print( + template.render( + macro=macro_name, + width=" + ".join(node.symbolic_width()), + ) + ) + + +class XdrTypedefGenerator(SourceGenerator): + """Generate source code for XDR typedefs""" + + def __init__(self, language: str, peer: str): + """Initialize an instance of this class""" + self.environment = create_jinja2_environment(language, "typedef") + self.peer = peer + + def emit_declaration(self, node: _XdrTypedef) -> None: + """Emit one declaration pair for an XDR enum type""" + emit_typedef_declaration(self.environment, node.declaration) + + def emit_definition(self, node: _XdrTypedef) -> None: + """Emit one definition for an XDR typedef""" + emit_type_definition(self.environment, node.declaration) + + def emit_decoder(self, node: _XdrTypedef) -> None: + """Emit one decoder function for an XDR typedef""" + emit_typedef_decoder(self.environment, node.declaration) + + def emit_encoder(self, node: _XdrTypedef) -> None: + """Emit one encoder function for an XDR typedef""" + emit_typedef_encoder(self.environment, node.declaration) + + def emit_maxsize(self, node: _XdrTypedef) -> None: + """Emit one maxsize macro for an XDR typedef""" + emit_typedef_maxsize(self.environment, node.declaration) diff --git a/tools/net/sunrpc/xdrgen/generators/union.py b/tools/net/sunrpc/xdrgen/generators/union.py new file mode 100644 index 000000000000..ad1f214ef22a --- /dev/null +++ b/tools/net/sunrpc/xdrgen/generators/union.py @@ -0,0 +1,291 @@ +#!/usr/bin/env python3 +# ex: set filetype=python: + +"""Generate code to handle XDR unions""" + +from jinja2 import Environment + +from generators import SourceGenerator +from generators import create_jinja2_environment, get_jinja2_template + +from xdr_ast import _XdrBasic, _XdrUnion, _XdrVoid, _XdrString, get_header_name +from xdr_ast import _XdrDeclaration, _XdrCaseSpec, public_apis, big_endian + + +def emit_union_declaration(environment: Environment, node: _XdrUnion) -> None: + """Emit one declaration pair for an XDR union type""" + if node.name in public_apis: + template = get_jinja2_template(environment, "declaration", "close") + print(template.render(name=node.name)) + + +def emit_union_switch_spec_definition( + environment: Environment, node: _XdrDeclaration +) -> None: + """Emit a definition for an XDR union's discriminant""" + assert isinstance(node, _XdrBasic) + template = get_jinja2_template(environment, "definition", "switch_spec") + print( + template.render( + name=node.name, + type=node.spec.type_name, + classifier=node.spec.c_classifier, + ) + ) + + +def emit_union_case_spec_definition( + environment: Environment, node: _XdrDeclaration +) -> None: + """Emit a definition for an XDR union's case arm""" + if isinstance(node.arm, _XdrVoid): + return + if isinstance(node.arm, _XdrString): + type_name = "char *" + classifier = "" + else: + type_name = node.arm.spec.type_name + classifier = node.arm.spec.c_classifier + + assert isinstance(node.arm, (_XdrBasic, _XdrString)) + template = get_jinja2_template(environment, "definition", "case_spec") + print( + template.render( + name=node.arm.name, + type=type_name, + classifier=classifier, + ) + ) + + +def emit_union_definition(environment: Environment, node: _XdrUnion) -> None: + """Emit one XDR union definition""" + template = get_jinja2_template(environment, "definition", "open") + print(template.render(name=node.name)) + + emit_union_switch_spec_definition(environment, node.discriminant) + + for case in node.cases: + emit_union_case_spec_definition(environment, case) + + if node.default is not None: + emit_union_case_spec_definition(environment, node.default) + + template = get_jinja2_template(environment, "definition", "close") + print(template.render(name=node.name)) + + +def emit_union_switch_spec_decoder( + environment: Environment, node: _XdrDeclaration +) -> None: + """Emit a decoder for an XDR union's discriminant""" + assert isinstance(node, _XdrBasic) + template = get_jinja2_template(environment, "decoder", "switch_spec") + print(template.render(name=node.name, type=node.spec.type_name)) + + +def emit_union_case_spec_decoder( + environment: Environment, node: _XdrCaseSpec, big_endian_discriminant: bool +) -> None: + """Emit decoder functions for an XDR union's case arm""" + + if isinstance(node.arm, _XdrVoid): + return + if isinstance(node.arm, _XdrString): + type_name = "char *" + classifier = "" + else: + type_name = node.arm.spec.type_name + classifier = node.arm.spec.c_classifier + + if big_endian_discriminant: + template = get_jinja2_template(environment, "decoder", "case_spec_be") + else: + template = get_jinja2_template(environment, "decoder", "case_spec") + for case in node.values: + print(template.render(case=case)) + + assert isinstance(node.arm, (_XdrBasic, _XdrString)) + template = get_jinja2_template(environment, "decoder", node.arm.template) + print( + template.render( + name=node.arm.name, + type=type_name, + classifier=classifier, + ) + ) + + template = get_jinja2_template(environment, "decoder", "break") + print(template.render()) + + +def emit_union_default_spec_decoder(environment: Environment, node: _XdrUnion) -> None: + """Emit a decoder function for an XDR union's default arm""" + default_case = node.default + + # Avoid a gcc warning about a default case with boolean discriminant + if default_case is None and node.discriminant.spec.type_name == "bool": + return + + template = get_jinja2_template(environment, "decoder", "default_spec") + print(template.render()) + + if default_case is None or isinstance(default_case.arm, _XdrVoid): + template = get_jinja2_template(environment, "decoder", "break") + print(template.render()) + return + + assert isinstance(default_case.arm, _XdrBasic) + template = get_jinja2_template(environment, "decoder", default_case.arm.template) + print( + template.render( + name=default_case.arm.name, + type=default_case.arm.spec.type_name, + classifier=default_case.arm.spec.c_classifier, + ) + ) + + +def emit_union_decoder(environment: Environment, node: _XdrUnion) -> None: + """Emit one XDR union decoder""" + template = get_jinja2_template(environment, "decoder", "open") + print(template.render(name=node.name)) + + emit_union_switch_spec_decoder(environment, node.discriminant) + + for case in node.cases: + emit_union_case_spec_decoder( + environment, + case, + node.discriminant.spec.type_name in big_endian, + ) + + emit_union_default_spec_decoder(environment, node) + + template = get_jinja2_template(environment, "decoder", "close") + print(template.render()) + + +def emit_union_switch_spec_encoder( + environment: Environment, node: _XdrDeclaration +) -> None: + """Emit an encoder for an XDR union's discriminant""" + assert isinstance(node, _XdrBasic) + template = get_jinja2_template(environment, "encoder", "switch_spec") + print(template.render(name=node.name, type=node.spec.type_name)) + + +def emit_union_case_spec_encoder( + environment: Environment, node: _XdrCaseSpec, big_endian_discriminant: bool +) -> None: + """Emit encoder functions for an XDR union's case arm""" + + if isinstance(node.arm, _XdrVoid): + return + if isinstance(node.arm, _XdrString): + type_name = "char *" + else: + type_name = node.arm.spec.type_name + if big_endian_discriminant: + template = get_jinja2_template(environment, "encoder", "case_spec_be") + else: + template = get_jinja2_template(environment, "encoder", "case_spec") + for case in node.values: + print(template.render(case=case)) + + template = get_jinja2_template(environment, "encoder", node.arm.template) + print( + template.render( + name=node.arm.name, + type=type_name, + ) + ) + + template = get_jinja2_template(environment, "encoder", "break") + print(template.render()) + + +def emit_union_default_spec_encoder(environment: Environment, node: _XdrUnion) -> None: + """Emit an encoder function for an XDR union's default arm""" + default_case = node.default + + # Avoid a gcc warning about a default case with boolean discriminant + if default_case is None and node.discriminant.spec.type_name == "bool": + return + + template = get_jinja2_template(environment, "encoder", "default_spec") + print(template.render()) + + if default_case is None or isinstance(default_case.arm, _XdrVoid): + template = get_jinja2_template(environment, "encoder", "break") + print(template.render()) + return + + template = get_jinja2_template(environment, "encoder", default_case.arm.template) + print( + template.render( + name=default_case.arm.name, + type=default_case.arm.spec.type_name, + ) + ) + + +def emit_union_encoder(environment, node: _XdrUnion) -> None: + """Emit one XDR union encoder""" + template = get_jinja2_template(environment, "encoder", "open") + print(template.render(name=node.name)) + + emit_union_switch_spec_encoder(environment, node.discriminant) + + for case in node.cases: + emit_union_case_spec_encoder( + environment, + case, + node.discriminant.spec.type_name in big_endian, + ) + + emit_union_default_spec_encoder(environment, node) + + template = get_jinja2_template(environment, "encoder", "close") + print(template.render()) + + +def emit_union_maxsize(environment: Environment, node: _XdrUnion) -> None: + """Emit one maxsize macro for an XDR union type""" + macro_name = get_header_name().upper() + "_" + node.name + "_sz" + template = get_jinja2_template(environment, "maxsize", "union") + print( + template.render( + macro=macro_name, + width=" + ".join(node.symbolic_width()), + ) + ) + + +class XdrUnionGenerator(SourceGenerator): + """Generate source code for XDR unions""" + + def __init__(self, language: str, peer: str): + """Initialize an instance of this class""" + self.environment = create_jinja2_environment(language, "union") + self.peer = peer + + def emit_declaration(self, node: _XdrUnion) -> None: + """Emit one declaration pair for an XDR union""" + emit_union_declaration(self.environment, node) + + def emit_definition(self, node: _XdrUnion) -> None: + """Emit one definition for an XDR union""" + emit_union_definition(self.environment, node) + + def emit_decoder(self, node: _XdrUnion) -> None: + """Emit one decoder function for an XDR union""" + emit_union_decoder(self.environment, node) + + def emit_encoder(self, node: _XdrUnion) -> None: + """Emit one encoder function for an XDR union""" + emit_union_encoder(self.environment, node) + + def emit_maxsize(self, node: _XdrUnion) -> None: + """Emit one maxsize macro for an XDR union""" + emit_union_maxsize(self.environment, node) diff --git a/tools/net/sunrpc/xdrgen/grammars/xdr.lark b/tools/net/sunrpc/xdrgen/grammars/xdr.lark new file mode 100644 index 000000000000..7c2c1b8c86d1 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/grammars/xdr.lark @@ -0,0 +1,121 @@ +// A Lark grammar for the XDR specification language based on +// https://tools.ietf.org/html/rfc4506 Section 6.3 + +declaration : "opaque" identifier "[" value "]" -> fixed_length_opaque + | "opaque" identifier "<" [ value ] ">" -> variable_length_opaque + | "string" identifier "<" [ value ] ">" -> string + | type_specifier identifier "[" value "]" -> fixed_length_array + | type_specifier identifier "<" [ value ] ">" -> variable_length_array + | type_specifier "*" identifier -> optional_data + | type_specifier identifier -> basic + | "void" -> void + +value : decimal_constant + | hexadecimal_constant + | octal_constant + | identifier + +constant : decimal_constant | hexadecimal_constant | octal_constant + +type_specifier : unsigned_hyper + | unsigned_long + | unsigned_int + | hyper + | long + | int + | float + | double + | quadruple + | bool + | enum_type_spec + | struct_type_spec + | union_type_spec + | identifier + +unsigned_hyper : "unsigned" "hyper" +unsigned_long : "unsigned" "long" +unsigned_int : "unsigned" "int" +hyper : "hyper" +long : "long" +int : "int" +float : "float" +double : "double" +quadruple : "quadruple" +bool : "bool" + +enum_type_spec : "enum" enum_body + +enum_body : "{" ( identifier "=" value ) ( "," identifier "=" value )* "}" + +struct_type_spec : "struct" struct_body + +struct_body : "{" ( declaration ";" )+ "}" + +union_type_spec : "union" union_body + +union_body : switch_spec "{" case_spec+ [ default_spec ] "}" + +switch_spec : "switch" "(" declaration ")" + +case_spec : ( "case" value ":" )+ declaration ";" + +default_spec : "default" ":" declaration ";" + +constant_def : "const" identifier "=" value ";" + +type_def : "typedef" declaration ";" -> typedef + | "enum" identifier enum_body ";" -> enum + | "struct" identifier struct_body ";" -> struct + | "union" identifier union_body ";" -> union + +specification : definition* + +definition : constant_def + | type_def + | program_def + | pragma_def + +// +// RPC program definitions not specified in RFC 4506 +// + +program_def : "program" identifier "{" version_def+ "}" "=" constant ";" + +version_def : "version" identifier "{" procedure_def+ "}" "=" constant ";" + +procedure_def : type_specifier identifier "(" type_specifier ")" "=" constant ";" + +pragma_def : "pragma" directive identifier [ identifier ] ";" + +directive : big_endian_directive + | exclude_directive + | header_directive + | pages_directive + | public_directive + | skip_directive + +big_endian_directive : "big_endian" +exclude_directive : "exclude" +header_directive : "header" +pages_directive : "pages" +public_directive : "public" +skip_directive : "skip" + +// +// XDR language primitives +// + +identifier : /([a-z]|[A-Z])(_|[a-z]|[A-Z]|[0-9])*/ + +decimal_constant : /[\+-]?(0|[1-9][0-9]*)/ +hexadecimal_constant : /0x([a-f]|[A-F]|[0-9])+/ +octal_constant : /0[0-7]+/ + +PASSTHRU : "%" | "%" /.+/ +%ignore PASSTHRU + +%import common.C_COMMENT +%ignore C_COMMENT + +%import common.WS +%ignore WS diff --git a/tools/net/sunrpc/xdrgen/subcmds/__init__.py b/tools/net/sunrpc/xdrgen/subcmds/__init__.py new file mode 100644 index 000000000000..c940e9275252 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/subcmds/__init__.py @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +# Just to make sphinx-apidoc document this directory diff --git a/tools/net/sunrpc/xdrgen/subcmds/declarations.py b/tools/net/sunrpc/xdrgen/subcmds/declarations.py new file mode 100644 index 000000000000..c5e8d79986ef --- /dev/null +++ b/tools/net/sunrpc/xdrgen/subcmds/declarations.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python3 +# ex: set filetype=python: + +"""Translate an XDR specification into executable code that +can be compiled for the Linux kernel.""" + +import logging + +from argparse import Namespace +from lark import logger +from lark.exceptions import UnexpectedInput + +from generators.constant import XdrConstantGenerator +from generators.enum import XdrEnumGenerator +from generators.header_bottom import XdrHeaderBottomGenerator +from generators.header_top import XdrHeaderTopGenerator +from generators.pointer import XdrPointerGenerator +from generators.program import XdrProgramGenerator +from generators.typedef import XdrTypedefGenerator +from generators.struct import XdrStructGenerator +from generators.union import XdrUnionGenerator + +from xdr_ast import transform_parse_tree, _RpcProgram, Specification +from xdr_ast import _XdrConstant, _XdrEnum, _XdrPointer +from xdr_ast import _XdrTypedef, _XdrStruct, _XdrUnion +from xdr_parse import xdr_parser, set_xdr_annotate + +logger.setLevel(logging.INFO) + + +def emit_header_declarations( + root: Specification, language: str, peer: str +) -> None: + """Emit header declarations""" + for definition in root.definitions: + if isinstance(definition.value, _XdrEnum): + gen = XdrEnumGenerator(language, peer) + elif isinstance(definition.value, _XdrPointer): + gen = XdrPointerGenerator(language, peer) + elif isinstance(definition.value, _XdrTypedef): + gen = XdrTypedefGenerator(language, peer) + elif isinstance(definition.value, _XdrStruct): + gen = XdrStructGenerator(language, peer) + elif isinstance(definition.value, _XdrUnion): + gen = XdrUnionGenerator(language, peer) + elif isinstance(definition.value, _RpcProgram): + gen = XdrProgramGenerator(language, peer) + else: + continue + gen.emit_declaration(definition.value) + + +def handle_parse_error(e: UnexpectedInput) -> bool: + """Simple parse error reporting, no recovery attempted""" + print(e) + return True + + +def subcmd(args: Namespace) -> int: + """Generate definitions and declarations""" + + set_xdr_annotate(args.annotate) + parser = xdr_parser() + with open(args.filename, encoding="utf-8") as f: + parse_tree = parser.parse(f.read(), on_error=handle_parse_error) + ast = transform_parse_tree(parse_tree) + + gen = XdrHeaderTopGenerator(args.language, args.peer) + gen.emit_declaration(args.filename, ast) + + emit_header_declarations(ast, args.language, args.peer) + + gen = XdrHeaderBottomGenerator(args.language, args.peer) + gen.emit_declaration(args.filename, ast) + + return 0 diff --git a/tools/net/sunrpc/xdrgen/subcmds/definitions.py b/tools/net/sunrpc/xdrgen/subcmds/definitions.py new file mode 100644 index 000000000000..c956e27f37c0 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/subcmds/definitions.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python3 +# ex: set filetype=python: + +"""Translate an XDR specification into executable code that +can be compiled for the Linux kernel.""" + +import logging + +from argparse import Namespace +from lark import logger +from lark.exceptions import UnexpectedInput + +from generators.constant import XdrConstantGenerator +from generators.enum import XdrEnumGenerator +from generators.header_bottom import XdrHeaderBottomGenerator +from generators.header_top import XdrHeaderTopGenerator +from generators.pointer import XdrPointerGenerator +from generators.program import XdrProgramGenerator +from generators.typedef import XdrTypedefGenerator +from generators.struct import XdrStructGenerator +from generators.union import XdrUnionGenerator + +from xdr_ast import transform_parse_tree, Specification +from xdr_ast import _RpcProgram, _XdrConstant, _XdrEnum, _XdrPointer +from xdr_ast import _XdrTypedef, _XdrStruct, _XdrUnion +from xdr_parse import xdr_parser, set_xdr_annotate + +logger.setLevel(logging.INFO) + + +def emit_header_definitions(root: Specification, language: str, peer: str) -> None: + """Emit header definitions""" + for definition in root.definitions: + if isinstance(definition.value, _XdrConstant): + gen = XdrConstantGenerator(language, peer) + elif isinstance(definition.value, _XdrEnum): + gen = XdrEnumGenerator(language, peer) + elif isinstance(definition.value, _XdrPointer): + gen = XdrPointerGenerator(language, peer) + elif isinstance(definition.value, _RpcProgram): + gen = XdrProgramGenerator(language, peer) + elif isinstance(definition.value, _XdrTypedef): + gen = XdrTypedefGenerator(language, peer) + elif isinstance(definition.value, _XdrStruct): + gen = XdrStructGenerator(language, peer) + elif isinstance(definition.value, _XdrUnion): + gen = XdrUnionGenerator(language, peer) + else: + continue + gen.emit_definition(definition.value) + + +def emit_header_maxsize(root: Specification, language: str, peer: str) -> None: + """Emit header maxsize macros""" + print("") + for definition in root.definitions: + if isinstance(definition.value, _XdrEnum): + gen = XdrEnumGenerator(language, peer) + elif isinstance(definition.value, _XdrPointer): + gen = XdrPointerGenerator(language, peer) + elif isinstance(definition.value, _XdrTypedef): + gen = XdrTypedefGenerator(language, peer) + elif isinstance(definition.value, _XdrStruct): + gen = XdrStructGenerator(language, peer) + elif isinstance(definition.value, _XdrUnion): + gen = XdrUnionGenerator(language, peer) + else: + continue + gen.emit_maxsize(definition.value) + + +def handle_parse_error(e: UnexpectedInput) -> bool: + """Simple parse error reporting, no recovery attempted""" + print(e) + return True + + +def subcmd(args: Namespace) -> int: + """Generate definitions""" + + set_xdr_annotate(args.annotate) + parser = xdr_parser() + with open(args.filename, encoding="utf-8") as f: + parse_tree = parser.parse(f.read(), on_error=handle_parse_error) + ast = transform_parse_tree(parse_tree) + + gen = XdrHeaderTopGenerator(args.language, args.peer) + gen.emit_definition(args.filename, ast) + + emit_header_definitions(ast, args.language, args.peer) + emit_header_maxsize(ast, args.language, args.peer) + + gen = XdrHeaderBottomGenerator(args.language, args.peer) + gen.emit_definition(args.filename, ast) + + return 0 diff --git a/tools/net/sunrpc/xdrgen/subcmds/lint.py b/tools/net/sunrpc/xdrgen/subcmds/lint.py new file mode 100644 index 000000000000..36cc43717d30 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/subcmds/lint.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 +# ex: set filetype=python: + +"""Translate an XDR specification into executable code that +can be compiled for the Linux kernel.""" + +import logging + +from argparse import Namespace +from lark import logger +from lark.exceptions import UnexpectedInput + +from xdr_parse import xdr_parser +from xdr_ast import transform_parse_tree + +logger.setLevel(logging.DEBUG) + + +def handle_parse_error(e: UnexpectedInput) -> bool: + """Simple parse error reporting, no recovery attempted""" + print(e) + return True + + +def subcmd(args: Namespace) -> int: + """Lexical and syntax check of an XDR specification""" + + parser = xdr_parser() + with open(args.filename, encoding="utf-8") as f: + parse_tree = parser.parse(f.read(), on_error=handle_parse_error) + transform_parse_tree(parse_tree) + + return 0 diff --git a/tools/net/sunrpc/xdrgen/subcmds/source.py b/tools/net/sunrpc/xdrgen/subcmds/source.py new file mode 100644 index 000000000000..2024954748f0 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/subcmds/source.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python3 +# ex: set filetype=python: + +"""Translate an XDR specification into executable code that +can be compiled for the Linux kernel.""" + +import logging + +from argparse import Namespace +from lark import logger +from lark.exceptions import UnexpectedInput + +from generators.source_top import XdrSourceTopGenerator +from generators.enum import XdrEnumGenerator +from generators.pointer import XdrPointerGenerator +from generators.program import XdrProgramGenerator +from generators.typedef import XdrTypedefGenerator +from generators.struct import XdrStructGenerator +from generators.union import XdrUnionGenerator + +from xdr_ast import transform_parse_tree, _RpcProgram, Specification +from xdr_ast import _XdrAst, _XdrEnum, _XdrPointer +from xdr_ast import _XdrStruct, _XdrTypedef, _XdrUnion + +from xdr_parse import xdr_parser, set_xdr_annotate + +logger.setLevel(logging.INFO) + + +def emit_source_decoder(node: _XdrAst, language: str, peer: str) -> None: + """Emit one XDR decoder function for a source file""" + if isinstance(node, _XdrEnum): + gen = XdrEnumGenerator(language, peer) + elif isinstance(node, _XdrPointer): + gen = XdrPointerGenerator(language, peer) + elif isinstance(node, _XdrTypedef): + gen = XdrTypedefGenerator(language, peer) + elif isinstance(node, _XdrStruct): + gen = XdrStructGenerator(language, peer) + elif isinstance(node, _XdrUnion): + gen = XdrUnionGenerator(language, peer) + elif isinstance(node, _RpcProgram): + gen = XdrProgramGenerator(language, peer) + else: + return + gen.emit_decoder(node) + + +def emit_source_encoder(node: _XdrAst, language: str, peer: str) -> None: + """Emit one XDR encoder function for a source file""" + if isinstance(node, _XdrEnum): + gen = XdrEnumGenerator(language, peer) + elif isinstance(node, _XdrPointer): + gen = XdrPointerGenerator(language, peer) + elif isinstance(node, _XdrTypedef): + gen = XdrTypedefGenerator(language, peer) + elif isinstance(node, _XdrStruct): + gen = XdrStructGenerator(language, peer) + elif isinstance(node, _XdrUnion): + gen = XdrUnionGenerator(language, peer) + elif isinstance(node, _RpcProgram): + gen = XdrProgramGenerator(language, peer) + else: + return + gen.emit_encoder(node) + + +def generate_server_source(filename: str, root: Specification, language: str) -> None: + """Generate server-side source code""" + + gen = XdrSourceTopGenerator(language, "server") + gen.emit_source(filename, root) + + for definition in root.definitions: + emit_source_decoder(definition.value, language, "server") + for definition in root.definitions: + emit_source_encoder(definition.value, language, "server") + + +def generate_client_source(filename: str, root: Specification, language: str) -> None: + """Generate server-side source code""" + + gen = XdrSourceTopGenerator(language, "client") + gen.emit_source(filename, root) + + print("") + for definition in root.definitions: + emit_source_encoder(definition.value, language, "client") + for definition in root.definitions: + emit_source_decoder(definition.value, language, "client") + + # cel: todo: client needs PROC macros + + +def handle_parse_error(e: UnexpectedInput) -> bool: + """Simple parse error reporting, no recovery attempted""" + print(e) + return True + + +def subcmd(args: Namespace) -> int: + """Generate encoder and decoder functions""" + + set_xdr_annotate(args.annotate) + parser = xdr_parser() + with open(args.filename, encoding="utf-8") as f: + parse_tree = parser.parse(f.read(), on_error=handle_parse_error) + ast = transform_parse_tree(parse_tree) + match args.peer: + case "server": + generate_server_source(args.filename, ast, args.language) + case "client": + generate_client_source(args.filename, ast, args.language) + case _: + print("Code generation for", args.peer, "is not yet supported") + + return 0 diff --git a/tools/net/sunrpc/xdrgen/templates/C/constants/definition.j2 b/tools/net/sunrpc/xdrgen/templates/C/constants/definition.j2 new file mode 100644 index 000000000000..d648ca4193f8 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/constants/definition.j2 @@ -0,0 +1,3 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +enum { {{ name }} = {{ value }} }; diff --git a/tools/net/sunrpc/xdrgen/templates/C/enum/declaration/enum.j2 b/tools/net/sunrpc/xdrgen/templates/C/enum/declaration/enum.j2 new file mode 100644 index 000000000000..d1405c7c5354 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/enum/declaration/enum.j2 @@ -0,0 +1,4 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +bool xdrgen_decode_{{ name }}(struct xdr_stream *xdr, {{ name }} *ptr); +bool xdrgen_encode_{{ name }}(struct xdr_stream *xdr, {{ name }} value); diff --git a/tools/net/sunrpc/xdrgen/templates/C/enum/decoder/enum.j2 b/tools/net/sunrpc/xdrgen/templates/C/enum/decoder/enum.j2 new file mode 100644 index 000000000000..6482984f1cb7 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/enum/decoder/enum.j2 @@ -0,0 +1,19 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +{% if annotate %} +/* enum {{ name }} */ +{% endif %} +{% if name in public_apis %} +bool +{% else %} +static bool __maybe_unused +{% endif %} +xdrgen_decode_{{ name }}(struct xdr_stream *xdr, {{ name }} *ptr) +{ + u32 val; + + if (xdr_stream_decode_u32(xdr, &val) < 0) + return false; + *ptr = val; + return true; +} diff --git a/tools/net/sunrpc/xdrgen/templates/C/enum/decoder/enum_be.j2 b/tools/net/sunrpc/xdrgen/templates/C/enum/decoder/enum_be.j2 new file mode 100644 index 000000000000..44c391c10b42 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/enum/decoder/enum_be.j2 @@ -0,0 +1,14 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +{% if annotate %} +/* enum {{ name }} (big-endian) */ +{% endif %} +{% if name in public_apis %} +bool +{% else %} +static bool __maybe_unused +{% endif %} +xdrgen_decode_{{ name }}(struct xdr_stream *xdr, {{ name }} *ptr) +{ + return xdr_stream_decode_be32(xdr, ptr) == 0; +} diff --git a/tools/net/sunrpc/xdrgen/templates/C/enum/definition/close.j2 b/tools/net/sunrpc/xdrgen/templates/C/enum/definition/close.j2 new file mode 100644 index 000000000000..a07586cbee17 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/enum/definition/close.j2 @@ -0,0 +1,3 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +}; +typedef enum {{ name }} {{ name }}; diff --git a/tools/net/sunrpc/xdrgen/templates/C/enum/definition/close_be.j2 b/tools/net/sunrpc/xdrgen/templates/C/enum/definition/close_be.j2 new file mode 100644 index 000000000000..2c18948bddf7 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/enum/definition/close_be.j2 @@ -0,0 +1,3 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +}; +typedef __be32 {{ name }}; diff --git a/tools/net/sunrpc/xdrgen/templates/C/enum/definition/enumerator.j2 b/tools/net/sunrpc/xdrgen/templates/C/enum/definition/enumerator.j2 new file mode 100644 index 000000000000..ff0b893b8b14 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/enum/definition/enumerator.j2 @@ -0,0 +1,2 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + {{ name }} = {{ value }}, diff --git a/tools/net/sunrpc/xdrgen/templates/C/enum/definition/open.j2 b/tools/net/sunrpc/xdrgen/templates/C/enum/definition/open.j2 new file mode 100644 index 000000000000..b25335221d48 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/enum/definition/open.j2 @@ -0,0 +1,3 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +enum {{ name }} { diff --git a/tools/net/sunrpc/xdrgen/templates/C/enum/encoder/enum.j2 b/tools/net/sunrpc/xdrgen/templates/C/enum/encoder/enum.j2 new file mode 100644 index 000000000000..67245b9a914d --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/enum/encoder/enum.j2 @@ -0,0 +1,14 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +{% if annotate %} +/* enum {{ name }} */ +{% endif %} +{% if name in public_apis %} +bool +{% else %} +static bool __maybe_unused +{% endif %} +xdrgen_encode_{{ name }}(struct xdr_stream *xdr, {{ name }} value) +{ + return xdr_stream_encode_u32(xdr, value) == XDR_UNIT; +} diff --git a/tools/net/sunrpc/xdrgen/templates/C/enum/encoder/enum_be.j2 b/tools/net/sunrpc/xdrgen/templates/C/enum/encoder/enum_be.j2 new file mode 100644 index 000000000000..fbbcc45948d6 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/enum/encoder/enum_be.j2 @@ -0,0 +1,14 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +{% if annotate %} +/* enum {{ name }} (big-endian) */ +{% endif %} +{% if name in public_apis %} +bool +{% else %} +static bool __maybe_unused +{% endif %} +xdrgen_encode_{{ name }}(struct xdr_stream *xdr, {{ name }} value) +{ + return xdr_stream_encode_be32(xdr, value) == XDR_UNIT; +} diff --git a/tools/net/sunrpc/xdrgen/templates/C/enum/maxsize/enum.j2 b/tools/net/sunrpc/xdrgen/templates/C/enum/maxsize/enum.j2 new file mode 100644 index 000000000000..45c1d4c21b22 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/enum/maxsize/enum.j2 @@ -0,0 +1,2 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +#define {{ '{:<31}'.format(macro) }} ({{ width }}) diff --git a/tools/net/sunrpc/xdrgen/templates/C/header_bottom/declaration/header.j2 b/tools/net/sunrpc/xdrgen/templates/C/header_bottom/declaration/header.j2 new file mode 100644 index 000000000000..0bb8c6fc0c20 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/header_bottom/declaration/header.j2 @@ -0,0 +1,3 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +#endif /* _LINUX_XDRGEN_{{ infix }}_DECL_H */ diff --git a/tools/net/sunrpc/xdrgen/templates/C/header_bottom/definition/header.j2 b/tools/net/sunrpc/xdrgen/templates/C/header_bottom/definition/header.j2 new file mode 100644 index 000000000000..69069d08dc91 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/header_bottom/definition/header.j2 @@ -0,0 +1,3 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +#endif /* _LINUX_XDRGEN_{{ infix }}_DEF_H */ diff --git a/tools/net/sunrpc/xdrgen/templates/C/header_top/declaration/header.j2 b/tools/net/sunrpc/xdrgen/templates/C/header_top/declaration/header.j2 new file mode 100644 index 000000000000..ebb4e1d32f85 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/header_top/declaration/header.j2 @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Generated by xdrgen. Manual edits will be lost. */ +/* XDR specification file: {{ filename }} */ +/* XDR specification modification time: {{ mtime }} */ + +#ifndef _LINUX_XDRGEN_{{ infix }}_DECL_H +#define _LINUX_XDRGEN_{{ infix }}_DECL_H + +#include <linux/types.h> + +#include <linux/sunrpc/xdr.h> +#include <linux/sunrpc/xdrgen/_defs.h> +#include <linux/sunrpc/xdrgen/_builtins.h> +#include <linux/sunrpc/xdrgen/{{ infix.lower() }}.h> diff --git a/tools/net/sunrpc/xdrgen/templates/C/header_top/definition/header.j2 b/tools/net/sunrpc/xdrgen/templates/C/header_top/definition/header.j2 new file mode 100644 index 000000000000..92f1fd4ba024 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/header_top/definition/header.j2 @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Generated by xdrgen. Manual edits will be lost. */ +/* XDR specification file: {{ filename }} */ +/* XDR specification modification time: {{ mtime }} */ + +#ifndef _LINUX_XDRGEN_{{ infix }}_DEF_H +#define _LINUX_XDRGEN_{{ infix }}_DEF_H + +#include <linux/types.h> +#include <linux/sunrpc/xdrgen/_defs.h> diff --git a/tools/net/sunrpc/xdrgen/templates/C/pointer/declaration/close.j2 b/tools/net/sunrpc/xdrgen/templates/C/pointer/declaration/close.j2 new file mode 100644 index 000000000000..816291184e8c --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/pointer/declaration/close.j2 @@ -0,0 +1,4 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +bool xdrgen_decode_{{ name }}(struct xdr_stream *xdr, struct {{ name }} *ptr); +bool xdrgen_encode_{{ name }}(struct xdr_stream *xdr, const struct {{ name }} *value); diff --git a/tools/net/sunrpc/xdrgen/templates/C/pointer/decoder/basic.j2 b/tools/net/sunrpc/xdrgen/templates/C/pointer/decoder/basic.j2 new file mode 100644 index 000000000000..cde4ab53f4be --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/pointer/decoder/basic.j2 @@ -0,0 +1,6 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* member {{ name }} (basic) */ +{% endif %} + if (!xdrgen_decode_{{ type }}(xdr, &ptr->{{ name }})) + return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/pointer/decoder/close.j2 b/tools/net/sunrpc/xdrgen/templates/C/pointer/decoder/close.j2 new file mode 100644 index 000000000000..3dbd724d7f17 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/pointer/decoder/close.j2 @@ -0,0 +1,3 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + return true; +} diff --git a/tools/net/sunrpc/xdrgen/templates/C/pointer/decoder/fixed_length_array.j2 b/tools/net/sunrpc/xdrgen/templates/C/pointer/decoder/fixed_length_array.j2 new file mode 100644 index 000000000000..cfd64217ad82 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/pointer/decoder/fixed_length_array.j2 @@ -0,0 +1,8 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* member {{ name }} (fixed-length array) */ +{% endif %} + for (u32 i = 0; i < {{ size }}; i++) { + if (xdrgen_decode_{{ type }}(xdr, &ptr->{{ name }}.items[i]) < 0) + return false; + } diff --git a/tools/net/sunrpc/xdrgen/templates/C/pointer/decoder/fixed_length_opaque.j2 b/tools/net/sunrpc/xdrgen/templates/C/pointer/decoder/fixed_length_opaque.j2 new file mode 100644 index 000000000000..b4695ece1884 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/pointer/decoder/fixed_length_opaque.j2 @@ -0,0 +1,6 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* member {{ name }} (fixed-length opaque) */ +{% endif %} + if (xdr_stream_decode_opaque_fixed(xdr, ptr->{{ name }}, {{ size }}) < 0) + return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/pointer/decoder/open.j2 b/tools/net/sunrpc/xdrgen/templates/C/pointer/decoder/open.j2 new file mode 100644 index 000000000000..c093d9e3c9ad --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/pointer/decoder/open.j2 @@ -0,0 +1,22 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +{% if annotate %} +/* pointer {{ name }} */ +{% endif %} +{% if name in public_apis %} +bool +{% else %} +static bool __maybe_unused +{% endif %} +xdrgen_decode_{{ name }}(struct xdr_stream *xdr, struct {{ name }} *ptr) +{ + bool opted; + +{% if annotate %} + /* opted */ +{% endif %} + if (!xdrgen_decode_bool(xdr, &opted)) + return false; + if (!opted) + return true; + diff --git a/tools/net/sunrpc/xdrgen/templates/C/pointer/decoder/optional_data.j2 b/tools/net/sunrpc/xdrgen/templates/C/pointer/decoder/optional_data.j2 new file mode 100644 index 000000000000..b6834299a04b --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/pointer/decoder/optional_data.j2 @@ -0,0 +1,6 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* member {{ name }} (optional data) */ +{% endif %} + if (!xdrgen_decode_{{ type }}(xdr, ptr->{{ name }})) + return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/pointer/decoder/string.j2 b/tools/net/sunrpc/xdrgen/templates/C/pointer/decoder/string.j2 new file mode 100644 index 000000000000..12d20b143b43 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/pointer/decoder/string.j2 @@ -0,0 +1,6 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* member {{ name }} (variable-length string) */ +{% endif %} + if (!xdrgen_decode_string(xdr, (string *)ptr, {{ maxsize }})) + return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/pointer/decoder/variable_length_array.j2 b/tools/net/sunrpc/xdrgen/templates/C/pointer/decoder/variable_length_array.j2 new file mode 100644 index 000000000000..2f943909cdf7 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/pointer/decoder/variable_length_array.j2 @@ -0,0 +1,13 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* member {{ name }} (variable-length array) */ +{% endif %} + if (xdr_stream_decode_u32(xdr, &ptr->{{ name }}.count) < 0) + return false; +{% if maxsize != "0" %} + if (ptr->{{ name }}.count > {{ maxsize }}) + return false; +{% endif %} + for (u32 i = 0; i < ptr->{{ name }}.count; i++) + if (!xdrgen_decode_{{ type }}(xdr, &ptr->{{ name }}.element[i])) + return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/pointer/decoder/variable_length_opaque.j2 b/tools/net/sunrpc/xdrgen/templates/C/pointer/decoder/variable_length_opaque.j2 new file mode 100644 index 000000000000..9a814de54ae8 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/pointer/decoder/variable_length_opaque.j2 @@ -0,0 +1,6 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* member {{ name }} (variable-length opaque) */ +{% endif %} + if (!xdrgen_decode_opaque(xdr, (opaque *)ptr, {{ maxsize }})) + return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/pointer/definition/basic.j2 b/tools/net/sunrpc/xdrgen/templates/C/pointer/definition/basic.j2 new file mode 100644 index 000000000000..b3430895f311 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/pointer/definition/basic.j2 @@ -0,0 +1,5 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* (basic) */ +{% endif %} + {{ classifier }}{{ type }} {{ name }}; diff --git a/tools/net/sunrpc/xdrgen/templates/C/pointer/definition/close.j2 b/tools/net/sunrpc/xdrgen/templates/C/pointer/definition/close.j2 new file mode 100644 index 000000000000..9e62344a976a --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/pointer/definition/close.j2 @@ -0,0 +1,2 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +}; diff --git a/tools/net/sunrpc/xdrgen/templates/C/pointer/definition/fixed_length_array.j2 b/tools/net/sunrpc/xdrgen/templates/C/pointer/definition/fixed_length_array.j2 new file mode 100644 index 000000000000..66be836826a0 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/pointer/definition/fixed_length_array.j2 @@ -0,0 +1,5 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* (fixed-length array) */ +{% endif %} + {{ type }} {{ name }}[{{ size }}]; diff --git a/tools/net/sunrpc/xdrgen/templates/C/pointer/definition/fixed_length_opaque.j2 b/tools/net/sunrpc/xdrgen/templates/C/pointer/definition/fixed_length_opaque.j2 new file mode 100644 index 000000000000..0daba19aa0f0 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/pointer/definition/fixed_length_opaque.j2 @@ -0,0 +1,5 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* (fixed-length opaque) */ +{% endif %} + u8 {{ name }}[{{ size }}]; diff --git a/tools/net/sunrpc/xdrgen/templates/C/pointer/definition/open.j2 b/tools/net/sunrpc/xdrgen/templates/C/pointer/definition/open.j2 new file mode 100644 index 000000000000..bc886b818d85 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/pointer/definition/open.j2 @@ -0,0 +1,6 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +{% if annotate %} +/* pointer {{ name }} */ +{% endif %} +struct {{ name }} { diff --git a/tools/net/sunrpc/xdrgen/templates/C/pointer/definition/optional_data.j2 b/tools/net/sunrpc/xdrgen/templates/C/pointer/definition/optional_data.j2 new file mode 100644 index 000000000000..a33341f45e8f --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/pointer/definition/optional_data.j2 @@ -0,0 +1,5 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* (optional data) */ +{% endif %} + {{ classifier }}{{ type }} *{{ name }}; diff --git a/tools/net/sunrpc/xdrgen/templates/C/pointer/definition/string.j2 b/tools/net/sunrpc/xdrgen/templates/C/pointer/definition/string.j2 new file mode 100644 index 000000000000..2de2feec77db --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/pointer/definition/string.j2 @@ -0,0 +1,5 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* (variable-length string) */ +{% endif %} + string {{ name }}; diff --git a/tools/net/sunrpc/xdrgen/templates/C/pointer/definition/variable_length_array.j2 b/tools/net/sunrpc/xdrgen/templates/C/pointer/definition/variable_length_array.j2 new file mode 100644 index 000000000000..5d767f9b3674 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/pointer/definition/variable_length_array.j2 @@ -0,0 +1,8 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* (variable-length array) */ +{% endif %} + struct { + u32 count; + {{ classifier }}{{ type }} *element; + } {{ name }}; diff --git a/tools/net/sunrpc/xdrgen/templates/C/pointer/definition/variable_length_opaque.j2 b/tools/net/sunrpc/xdrgen/templates/C/pointer/definition/variable_length_opaque.j2 new file mode 100644 index 000000000000..4d0cd84be3db --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/pointer/definition/variable_length_opaque.j2 @@ -0,0 +1,5 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* (variable-length opaque) */ +{% endif %} + opaque {{ name }}; diff --git a/tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/basic.j2 b/tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/basic.j2 new file mode 100644 index 000000000000..a7d3695c5a6a --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/basic.j2 @@ -0,0 +1,10 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* member {{ name }} (basic) */ +{% endif %} +{% if type in pass_by_reference %} + if (!xdrgen_encode_{{ type }}(xdr, &value->{{ name }})) +{% else %} + if (!xdrgen_encode_{{ type }}(xdr, value->{{ name }})) +{% endif %} + return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/close.j2 b/tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/close.j2 new file mode 100644 index 000000000000..3dbd724d7f17 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/close.j2 @@ -0,0 +1,3 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + return true; +} diff --git a/tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/fixed_length_array.j2 b/tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/fixed_length_array.j2 new file mode 100644 index 000000000000..b01833a2c7a1 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/fixed_length_array.j2 @@ -0,0 +1,12 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* member {{ name }} (fixed-length array) */ +{% endif %} + for (u32 i = 0; i < {{ size }}; i++) { +{% if type in pass_by_reference %} + if (xdrgen_encode_{{ type }}(xdr, &value->items[i]) < 0) +{% else %} + if (xdrgen_encode_{{ type }}(xdr, value->items[i]) < 0) +{% endif %} + return false; + } diff --git a/tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/fixed_length_opaque.j2 b/tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/fixed_length_opaque.j2 new file mode 100644 index 000000000000..07bc91919898 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/fixed_length_opaque.j2 @@ -0,0 +1,6 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* member {{ name }} (fixed-length opaque) */ +{% endif %} + if (xdr_stream_encode_opaque_fixed(xdr, value->{{ name }}, {{ size }}) < 0) + return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/open.j2 b/tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/open.j2 new file mode 100644 index 000000000000..d67fae200261 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/open.j2 @@ -0,0 +1,20 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +{% if annotate %} +/* pointer {{ name }} */ +{% endif %} +{% if name in public_apis %} +bool +{% else %} +static bool __maybe_unused +{% endif %} +xdrgen_encode_{{ name }}(struct xdr_stream *xdr, const struct {{ name }} *value) +{ +{% if annotate %} + /* opted */ +{% endif %} + if (!xdrgen_encode_bool(xdr, value != NULL)) + return false; + if (!value) + return true; + diff --git a/tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/optional_data.j2 b/tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/optional_data.j2 new file mode 100644 index 000000000000..16fb3e09bba1 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/optional_data.j2 @@ -0,0 +1,6 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* member {{ name }} (optional data) */ +{% endif %} + if (!xdrgen_encode_{{ type }}(xdr, value->{{ name }})) + return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/string.j2 b/tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/string.j2 new file mode 100644 index 000000000000..cf65b71eaef3 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/string.j2 @@ -0,0 +1,8 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* member {{ name }} (variable-length string) */ +{% endif %} + if (value->{{ name }}.len > {{ maxsize }}) + return false; + if (xdr_stream_encode_opaque(xdr, value->{{ name }}.data, value->{{ name }}.len) < 0) + return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/variable_length_array.j2 b/tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/variable_length_array.j2 new file mode 100644 index 000000000000..b21476629679 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/variable_length_array.j2 @@ -0,0 +1,17 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* member {{ name }} (variable-length array) */ +{% endif %} +{% if maxsize != "0" %} + if (value->{{ name }}.count > {{ maxsize }}) + return false; +{% endif %} + if (xdr_stream_encode_u32(xdr, value->{{ name }}.count) != XDR_UNIT) + return false; + for (u32 i = 0; i < value->{{ name }}.count; i++) +{% if type in pass_by_reference %} + if (!xdrgen_encode_{{ type }}(xdr, &value->{{ name }}.element[i])) +{% else %} + if (!xdrgen_encode_{{ type }}(xdr, value->{{ name }}.element[i])) +{% endif %} + return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/variable_length_opaque.j2 b/tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/variable_length_opaque.j2 new file mode 100644 index 000000000000..1d477c2d197a --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/variable_length_opaque.j2 @@ -0,0 +1,8 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* member {{ name }} (variable-length opaque) */ +{% endif %} + if (value->{{ name }}.len > {{ maxsize }}) + return false; + if (xdr_stream_encode_opaque(xdr, value->{{ name }}.data, value->{{ name }}.len) < 0) + return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/pointer/maxsize/pointer.j2 b/tools/net/sunrpc/xdrgen/templates/C/pointer/maxsize/pointer.j2 new file mode 100644 index 000000000000..9f3bfb47d2f4 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/pointer/maxsize/pointer.j2 @@ -0,0 +1,3 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +#define {{ '{:<31}'.format(macro) }} \ + ({{ width }}) diff --git a/tools/net/sunrpc/xdrgen/templates/C/program/declaration/argument.j2 b/tools/net/sunrpc/xdrgen/templates/C/program/declaration/argument.j2 new file mode 100644 index 000000000000..4364fed19162 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/program/declaration/argument.j2 @@ -0,0 +1,2 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +bool {{ program }}_svc_decode_{{ argument }}(struct svc_rqst *rqstp, struct xdr_stream *xdr); diff --git a/tools/net/sunrpc/xdrgen/templates/C/program/declaration/result.j2 b/tools/net/sunrpc/xdrgen/templates/C/program/declaration/result.j2 new file mode 100644 index 000000000000..e0ea1e849910 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/program/declaration/result.j2 @@ -0,0 +1,2 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +bool {{ program }}_svc_encode_{{ result }}(struct svc_rqst *rqstp, struct xdr_stream *xdr); diff --git a/tools/net/sunrpc/xdrgen/templates/C/program/decoder/argument.j2 b/tools/net/sunrpc/xdrgen/templates/C/program/decoder/argument.j2 new file mode 100644 index 000000000000..0b1709cca0d4 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/program/decoder/argument.j2 @@ -0,0 +1,21 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +/** + * {{ program }}_svc_decode_{{ argument }} - Decode a {{ argument }} argument + * @rqstp: RPC transaction context + * @xdr: source XDR data stream + * + * Return values: + * %true: procedure arguments decoded successfully + * %false: decode failed + */ +bool {{ program }}_svc_decode_{{ argument }}(struct svc_rqst *rqstp, struct xdr_stream *xdr) +{ +{% if argument == 'void' %} + return xdrgen_decode_void(xdr); +{% else %} + struct {{ argument }} *argp = rqstp->rq_argp; + + return xdrgen_decode_{{ argument }}(xdr, argp); +{% endif %} +} diff --git a/tools/net/sunrpc/xdrgen/templates/C/program/decoder/result.j2 b/tools/net/sunrpc/xdrgen/templates/C/program/decoder/result.j2 new file mode 100644 index 000000000000..aa9940e322db --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/program/decoder/result.j2 @@ -0,0 +1,18 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +{% if annotate %} +/* Decode {{ result }} results */ +{% endif %} +static int {{ program }}_xdr_dec_{{ result }}(struct rpc_rqst *req, + struct xdr_stream *xdr, void *data) +{ +{% if result == 'void' %} + xdrgen_decode_void(xdr); +{% else %} + struct {{ result }} *result = data; + + if (!xdrgen_decode_{{ result }}(xdr, result)) + return -EIO; +{% endif %} + return 0; +} diff --git a/tools/net/sunrpc/xdrgen/templates/C/program/definition/close.j2 b/tools/net/sunrpc/xdrgen/templates/C/program/definition/close.j2 new file mode 100644 index 000000000000..9e62344a976a --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/program/definition/close.j2 @@ -0,0 +1,2 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +}; diff --git a/tools/net/sunrpc/xdrgen/templates/C/program/definition/open.j2 b/tools/net/sunrpc/xdrgen/templates/C/program/definition/open.j2 new file mode 100644 index 000000000000..f9a6d439f156 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/program/definition/open.j2 @@ -0,0 +1,6 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +{% if annotate %} +/* procedure numbers for {{ program }} */ +{% endif %} +enum { diff --git a/tools/net/sunrpc/xdrgen/templates/C/program/definition/procedure.j2 b/tools/net/sunrpc/xdrgen/templates/C/program/definition/procedure.j2 new file mode 100644 index 000000000000..ff0b893b8b14 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/program/definition/procedure.j2 @@ -0,0 +1,2 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + {{ name }} = {{ value }}, diff --git a/tools/net/sunrpc/xdrgen/templates/C/program/encoder/argument.j2 b/tools/net/sunrpc/xdrgen/templates/C/program/encoder/argument.j2 new file mode 100644 index 000000000000..2fbb5bd13aec --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/program/encoder/argument.j2 @@ -0,0 +1,16 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +{%if annotate %} +/* Encode {{ argument }} arguments */ +{% endif %} +static void {{ program }}_xdr_enc_{{ argument }}(struct rpc_rqst *req, + struct xdr_stream *xdr, const void *data) +{ +{% if argument == 'void' %} + xdrgen_encode_void(xdr); +{% else %} + const struct {{ argument }} *args = data; + + xdrgen_encode_{{ argument }}(xdr, args); +{% endif %} +} diff --git a/tools/net/sunrpc/xdrgen/templates/C/program/encoder/result.j2 b/tools/net/sunrpc/xdrgen/templates/C/program/encoder/result.j2 new file mode 100644 index 000000000000..6fc61a5d47b7 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/program/encoder/result.j2 @@ -0,0 +1,21 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +/** + * {{ program }}_svc_encode_{{ result }} - Encode a {{ result }} result + * @rqstp: RPC transaction context + * @xdr: target XDR data stream + * + * Return values: + * %true: procedure results encoded successfully + * %false: encode failed + */ +bool {{ program }}_svc_encode_{{ result }}(struct svc_rqst *rqstp, struct xdr_stream *xdr) +{ +{% if result == 'void' %} + return xdrgen_encode_void(xdr); +{% else %} + struct {{ result }} *resp = rqstp->rq_resp; + + return xdrgen_encode_{{ result }}(xdr, resp); +{% endif %} +} diff --git a/tools/net/sunrpc/xdrgen/templates/C/source_top/client.j2 b/tools/net/sunrpc/xdrgen/templates/C/source_top/client.j2 new file mode 100644 index 000000000000..c5518c519854 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/source_top/client.j2 @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0 +// Generated by xdrgen. Manual edits will be lost. +// XDR specification file: {{ filename }} +// XDR specification modification time: {{ mtime }} + +#include <linux/types.h> + +#include <linux/sunrpc/xdr.h> +#include <linux/sunrpc/xdrgen/_defs.h> +#include <linux/sunrpc/xdrgen/_builtins.h> +#include <linux/sunrpc/xdrgen/nlm4.h> + +#include <linux/sunrpc/clnt.h> diff --git a/tools/net/sunrpc/xdrgen/templates/C/source_top/server.j2 b/tools/net/sunrpc/xdrgen/templates/C/source_top/server.j2 new file mode 100644 index 000000000000..974e1d971e5d --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/source_top/server.j2 @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 +// Generated by xdrgen. Manual edits will be lost. +// XDR specification file: {{ filename }} +// XDR specification modification time: {{ mtime }} + +#include <linux/sunrpc/svc.h> + +#include "{{ program }}xdr_gen.h" diff --git a/tools/net/sunrpc/xdrgen/templates/C/struct/declaration/close.j2 b/tools/net/sunrpc/xdrgen/templates/C/struct/declaration/close.j2 new file mode 100644 index 000000000000..816291184e8c --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/struct/declaration/close.j2 @@ -0,0 +1,4 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +bool xdrgen_decode_{{ name }}(struct xdr_stream *xdr, struct {{ name }} *ptr); +bool xdrgen_encode_{{ name }}(struct xdr_stream *xdr, const struct {{ name }} *value); diff --git a/tools/net/sunrpc/xdrgen/templates/C/struct/decoder/basic.j2 b/tools/net/sunrpc/xdrgen/templates/C/struct/decoder/basic.j2 new file mode 100644 index 000000000000..cde4ab53f4be --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/struct/decoder/basic.j2 @@ -0,0 +1,6 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* member {{ name }} (basic) */ +{% endif %} + if (!xdrgen_decode_{{ type }}(xdr, &ptr->{{ name }})) + return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/struct/decoder/close.j2 b/tools/net/sunrpc/xdrgen/templates/C/struct/decoder/close.j2 new file mode 100644 index 000000000000..3dbd724d7f17 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/struct/decoder/close.j2 @@ -0,0 +1,3 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + return true; +} diff --git a/tools/net/sunrpc/xdrgen/templates/C/struct/decoder/fixed_length_array.j2 b/tools/net/sunrpc/xdrgen/templates/C/struct/decoder/fixed_length_array.j2 new file mode 100644 index 000000000000..cfd64217ad82 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/struct/decoder/fixed_length_array.j2 @@ -0,0 +1,8 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* member {{ name }} (fixed-length array) */ +{% endif %} + for (u32 i = 0; i < {{ size }}; i++) { + if (xdrgen_decode_{{ type }}(xdr, &ptr->{{ name }}.items[i]) < 0) + return false; + } diff --git a/tools/net/sunrpc/xdrgen/templates/C/struct/decoder/fixed_length_opaque.j2 b/tools/net/sunrpc/xdrgen/templates/C/struct/decoder/fixed_length_opaque.j2 new file mode 100644 index 000000000000..b4695ece1884 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/struct/decoder/fixed_length_opaque.j2 @@ -0,0 +1,6 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* member {{ name }} (fixed-length opaque) */ +{% endif %} + if (xdr_stream_decode_opaque_fixed(xdr, ptr->{{ name }}, {{ size }}) < 0) + return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/struct/decoder/open.j2 b/tools/net/sunrpc/xdrgen/templates/C/struct/decoder/open.j2 new file mode 100644 index 000000000000..289e67259f55 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/struct/decoder/open.j2 @@ -0,0 +1,12 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +{% if annotate %} +/* struct {{ name }} */ +{% endif %} +{% if name in public_apis %} +bool +{% else %} +static bool __maybe_unused +{% endif %} +xdrgen_decode_{{ name }}(struct xdr_stream *xdr, struct {{ name }} *ptr) +{ diff --git a/tools/net/sunrpc/xdrgen/templates/C/struct/decoder/optional_data.j2 b/tools/net/sunrpc/xdrgen/templates/C/struct/decoder/optional_data.j2 new file mode 100644 index 000000000000..b6834299a04b --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/struct/decoder/optional_data.j2 @@ -0,0 +1,6 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* member {{ name }} (optional data) */ +{% endif %} + if (!xdrgen_decode_{{ type }}(xdr, ptr->{{ name }})) + return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/struct/decoder/string.j2 b/tools/net/sunrpc/xdrgen/templates/C/struct/decoder/string.j2 new file mode 100644 index 000000000000..12d20b143b43 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/struct/decoder/string.j2 @@ -0,0 +1,6 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* member {{ name }} (variable-length string) */ +{% endif %} + if (!xdrgen_decode_string(xdr, (string *)ptr, {{ maxsize }})) + return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/struct/decoder/variable_length_array.j2 b/tools/net/sunrpc/xdrgen/templates/C/struct/decoder/variable_length_array.j2 new file mode 100644 index 000000000000..2f943909cdf7 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/struct/decoder/variable_length_array.j2 @@ -0,0 +1,13 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* member {{ name }} (variable-length array) */ +{% endif %} + if (xdr_stream_decode_u32(xdr, &ptr->{{ name }}.count) < 0) + return false; +{% if maxsize != "0" %} + if (ptr->{{ name }}.count > {{ maxsize }}) + return false; +{% endif %} + for (u32 i = 0; i < ptr->{{ name }}.count; i++) + if (!xdrgen_decode_{{ type }}(xdr, &ptr->{{ name }}.element[i])) + return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/struct/decoder/variable_length_opaque.j2 b/tools/net/sunrpc/xdrgen/templates/C/struct/decoder/variable_length_opaque.j2 new file mode 100644 index 000000000000..65698e20d8cd --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/struct/decoder/variable_length_opaque.j2 @@ -0,0 +1,6 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* member {{ name }} (variable-length opaque) */ +{% endif %} + if (!xdrgen_decode_opaque(xdr, &ptr->{{ name }}, {{ maxsize }})) + return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/struct/definition/basic.j2 b/tools/net/sunrpc/xdrgen/templates/C/struct/definition/basic.j2 new file mode 100644 index 000000000000..b3430895f311 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/struct/definition/basic.j2 @@ -0,0 +1,5 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* (basic) */ +{% endif %} + {{ classifier }}{{ type }} {{ name }}; diff --git a/tools/net/sunrpc/xdrgen/templates/C/struct/definition/close.j2 b/tools/net/sunrpc/xdrgen/templates/C/struct/definition/close.j2 new file mode 100644 index 000000000000..9e62344a976a --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/struct/definition/close.j2 @@ -0,0 +1,2 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +}; diff --git a/tools/net/sunrpc/xdrgen/templates/C/struct/definition/fixed_length_array.j2 b/tools/net/sunrpc/xdrgen/templates/C/struct/definition/fixed_length_array.j2 new file mode 100644 index 000000000000..66be836826a0 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/struct/definition/fixed_length_array.j2 @@ -0,0 +1,5 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* (fixed-length array) */ +{% endif %} + {{ type }} {{ name }}[{{ size }}]; diff --git a/tools/net/sunrpc/xdrgen/templates/C/struct/definition/fixed_length_opaque.j2 b/tools/net/sunrpc/xdrgen/templates/C/struct/definition/fixed_length_opaque.j2 new file mode 100644 index 000000000000..0daba19aa0f0 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/struct/definition/fixed_length_opaque.j2 @@ -0,0 +1,5 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* (fixed-length opaque) */ +{% endif %} + u8 {{ name }}[{{ size }}]; diff --git a/tools/net/sunrpc/xdrgen/templates/C/struct/definition/open.j2 b/tools/net/sunrpc/xdrgen/templates/C/struct/definition/open.j2 new file mode 100644 index 000000000000..07cbf5424546 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/struct/definition/open.j2 @@ -0,0 +1,6 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +{% if annotate %} +/* struct {{ name }} */ +{% endif %} +struct {{ name }} { diff --git a/tools/net/sunrpc/xdrgen/templates/C/struct/definition/optional_data.j2 b/tools/net/sunrpc/xdrgen/templates/C/struct/definition/optional_data.j2 new file mode 100644 index 000000000000..a33341f45e8f --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/struct/definition/optional_data.j2 @@ -0,0 +1,5 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* (optional data) */ +{% endif %} + {{ classifier }}{{ type }} *{{ name }}; diff --git a/tools/net/sunrpc/xdrgen/templates/C/struct/definition/string.j2 b/tools/net/sunrpc/xdrgen/templates/C/struct/definition/string.j2 new file mode 100644 index 000000000000..2de2feec77db --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/struct/definition/string.j2 @@ -0,0 +1,5 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* (variable-length string) */ +{% endif %} + string {{ name }}; diff --git a/tools/net/sunrpc/xdrgen/templates/C/struct/definition/variable_length_array.j2 b/tools/net/sunrpc/xdrgen/templates/C/struct/definition/variable_length_array.j2 new file mode 100644 index 000000000000..5d767f9b3674 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/struct/definition/variable_length_array.j2 @@ -0,0 +1,8 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* (variable-length array) */ +{% endif %} + struct { + u32 count; + {{ classifier }}{{ type }} *element; + } {{ name }}; diff --git a/tools/net/sunrpc/xdrgen/templates/C/struct/definition/variable_length_opaque.j2 b/tools/net/sunrpc/xdrgen/templates/C/struct/definition/variable_length_opaque.j2 new file mode 100644 index 000000000000..4d0cd84be3db --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/struct/definition/variable_length_opaque.j2 @@ -0,0 +1,5 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* (variable-length opaque) */ +{% endif %} + opaque {{ name }}; diff --git a/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/basic.j2 b/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/basic.j2 new file mode 100644 index 000000000000..a7d3695c5a6a --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/basic.j2 @@ -0,0 +1,10 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* member {{ name }} (basic) */ +{% endif %} +{% if type in pass_by_reference %} + if (!xdrgen_encode_{{ type }}(xdr, &value->{{ name }})) +{% else %} + if (!xdrgen_encode_{{ type }}(xdr, value->{{ name }})) +{% endif %} + return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/close.j2 b/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/close.j2 new file mode 100644 index 000000000000..3dbd724d7f17 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/close.j2 @@ -0,0 +1,3 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + return true; +} diff --git a/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/fixed_length_array.j2 b/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/fixed_length_array.j2 new file mode 100644 index 000000000000..b01833a2c7a1 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/fixed_length_array.j2 @@ -0,0 +1,12 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* member {{ name }} (fixed-length array) */ +{% endif %} + for (u32 i = 0; i < {{ size }}; i++) { +{% if type in pass_by_reference %} + if (xdrgen_encode_{{ type }}(xdr, &value->items[i]) < 0) +{% else %} + if (xdrgen_encode_{{ type }}(xdr, value->items[i]) < 0) +{% endif %} + return false; + } diff --git a/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/fixed_length_opaque.j2 b/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/fixed_length_opaque.j2 new file mode 100644 index 000000000000..07bc91919898 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/fixed_length_opaque.j2 @@ -0,0 +1,6 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* member {{ name }} (fixed-length opaque) */ +{% endif %} + if (xdr_stream_encode_opaque_fixed(xdr, value->{{ name }}, {{ size }}) < 0) + return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/open.j2 b/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/open.j2 new file mode 100644 index 000000000000..2286a3adf82a --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/open.j2 @@ -0,0 +1,12 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +{% if annotate %} +/* struct {{ name }} */ +{% endif %} +{% if name in public_apis %} +bool +{% else %} +static bool __maybe_unused +{% endif %} +xdrgen_encode_{{ name }}(struct xdr_stream *xdr, const struct {{ name }} *value) +{ diff --git a/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/optional_data.j2 b/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/optional_data.j2 new file mode 100644 index 000000000000..16fb3e09bba1 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/optional_data.j2 @@ -0,0 +1,6 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* member {{ name }} (optional data) */ +{% endif %} + if (!xdrgen_encode_{{ type }}(xdr, value->{{ name }})) + return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/string.j2 b/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/string.j2 new file mode 100644 index 000000000000..cf65b71eaef3 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/string.j2 @@ -0,0 +1,8 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* member {{ name }} (variable-length string) */ +{% endif %} + if (value->{{ name }}.len > {{ maxsize }}) + return false; + if (xdr_stream_encode_opaque(xdr, value->{{ name }}.data, value->{{ name }}.len) < 0) + return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/variable_length_array.j2 b/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/variable_length_array.j2 new file mode 100644 index 000000000000..b21476629679 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/variable_length_array.j2 @@ -0,0 +1,17 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* member {{ name }} (variable-length array) */ +{% endif %} +{% if maxsize != "0" %} + if (value->{{ name }}.count > {{ maxsize }}) + return false; +{% endif %} + if (xdr_stream_encode_u32(xdr, value->{{ name }}.count) != XDR_UNIT) + return false; + for (u32 i = 0; i < value->{{ name }}.count; i++) +{% if type in pass_by_reference %} + if (!xdrgen_encode_{{ type }}(xdr, &value->{{ name }}.element[i])) +{% else %} + if (!xdrgen_encode_{{ type }}(xdr, value->{{ name }}.element[i])) +{% endif %} + return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/variable_length_opaque.j2 b/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/variable_length_opaque.j2 new file mode 100644 index 000000000000..1d477c2d197a --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/variable_length_opaque.j2 @@ -0,0 +1,8 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* member {{ name }} (variable-length opaque) */ +{% endif %} + if (value->{{ name }}.len > {{ maxsize }}) + return false; + if (xdr_stream_encode_opaque(xdr, value->{{ name }}.data, value->{{ name }}.len) < 0) + return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/struct/maxsize/struct.j2 b/tools/net/sunrpc/xdrgen/templates/C/struct/maxsize/struct.j2 new file mode 100644 index 000000000000..9f3bfb47d2f4 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/struct/maxsize/struct.j2 @@ -0,0 +1,3 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +#define {{ '{:<31}'.format(macro) }} \ + ({{ width }}) diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/declaration/basic.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/declaration/basic.j2 new file mode 100644 index 000000000000..455b10bd90ec --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/typedef/declaration/basic.j2 @@ -0,0 +1,8 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +bool xdrgen_decode_{{ name }}(struct xdr_stream *xdr, {{ name }} *ptr); +{% if name in pass_by_reference %} +bool xdrgen_encode_{{ name }}(struct xdr_stream *xdr, const {{ name }} *value); +{%- else -%} +bool xdrgen_encode_{{ name }}(struct xdr_stream *xdr, const {{ name }} value); +{% endif %} diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/declaration/fixed_length_array.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/declaration/fixed_length_array.j2 new file mode 100644 index 000000000000..3fe3ddd9f359 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/typedef/declaration/fixed_length_array.j2 @@ -0,0 +1,4 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +bool xdrgen_decode_{{ name }}(struct xdr_stream *xdr, {{ classifier }}{{ name }} *ptr); +bool xdrgen_encode_{{ name }}(struct xdr_stream *xdr, const {{ classifier }}{{ name }} value); diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/declaration/fixed_length_opaque.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/declaration/fixed_length_opaque.j2 new file mode 100644 index 000000000000..3fe3ddd9f359 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/typedef/declaration/fixed_length_opaque.j2 @@ -0,0 +1,4 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +bool xdrgen_decode_{{ name }}(struct xdr_stream *xdr, {{ classifier }}{{ name }} *ptr); +bool xdrgen_encode_{{ name }}(struct xdr_stream *xdr, const {{ classifier }}{{ name }} value); diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/declaration/string.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/declaration/string.j2 new file mode 100644 index 000000000000..3fe3ddd9f359 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/typedef/declaration/string.j2 @@ -0,0 +1,4 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +bool xdrgen_decode_{{ name }}(struct xdr_stream *xdr, {{ classifier }}{{ name }} *ptr); +bool xdrgen_encode_{{ name }}(struct xdr_stream *xdr, const {{ classifier }}{{ name }} value); diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/declaration/variable_length_array.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/declaration/variable_length_array.j2 new file mode 100644 index 000000000000..3fe3ddd9f359 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/typedef/declaration/variable_length_array.j2 @@ -0,0 +1,4 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +bool xdrgen_decode_{{ name }}(struct xdr_stream *xdr, {{ classifier }}{{ name }} *ptr); +bool xdrgen_encode_{{ name }}(struct xdr_stream *xdr, const {{ classifier }}{{ name }} value); diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/declaration/variable_length_opaque.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/declaration/variable_length_opaque.j2 new file mode 100644 index 000000000000..3fe3ddd9f359 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/typedef/declaration/variable_length_opaque.j2 @@ -0,0 +1,4 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +bool xdrgen_decode_{{ name }}(struct xdr_stream *xdr, {{ classifier }}{{ name }} *ptr); +bool xdrgen_encode_{{ name }}(struct xdr_stream *xdr, const {{ classifier }}{{ name }} value); diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/decoder/basic.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/decoder/basic.j2 new file mode 100644 index 000000000000..b215e157dfa7 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/typedef/decoder/basic.j2 @@ -0,0 +1,17 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +{% if annotate %} +/* typedef {{ name }} */ +{% endif %} +{% if name in public_apis %} +bool +{% else %} +static bool __maybe_unused +{% endif %} +xdrgen_decode_{{ name }}(struct xdr_stream *xdr, {{ name }} *ptr) +{ +{% if annotate %} + /* (basic) */ +{% endif %} + return xdrgen_decode_{{ type }}(xdr, ptr); +} diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/decoder/fixed_length_array.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/decoder/fixed_length_array.j2 new file mode 100644 index 000000000000..c8953719e626 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/typedef/decoder/fixed_length_array.j2 @@ -0,0 +1,25 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +{% if annotate %} +/* typedef {{ name }} */ +{% endif %} +{% if name in public_apis %} +bool +{% else %} +static bool __maybe_unused +{% endif %} +xdrgen_decode_{{ name }}(struct xdr_stream *xdr, {{ classifier }}{{ name }} *ptr) +{ +{% if annotate %} + /* (fixed-length array) */ +{% endif %} + for (u32 i = 0; i < {{ size }}; i++) { +{%- if classifier == '' %} + if (xdrgen_decode_{{ type }}(xdr, ptr->items[i]) < 0) +{% else %} + if (xdrgen_decode_{{ type }}(xdr, &ptr->items[i]) < 0) +{% endif %} + return false; + } + return true; +} diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/decoder/fixed_length_opaque.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/decoder/fixed_length_opaque.j2 new file mode 100644 index 000000000000..c854fc8c74e3 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/typedef/decoder/fixed_length_opaque.j2 @@ -0,0 +1,17 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +{% if annotate %} +/* typedef {{ name }} */ +{% endif %} +{% if name in public_apis %} +bool +{% else %} +static bool __maybe_unused +{% endif %} +xdrgen_decode_{{ name }}(struct xdr_stream *xdr, {{ classifier }}{{ name }} *ptr) +{ +{% if annotate %} + /* (fixed-length opaque) */ +{% endif %} + return xdr_stream_decode_opaque_fixed(xdr, ptr, {{ size }}) == 0; +} diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/decoder/string.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/decoder/string.j2 new file mode 100644 index 000000000000..bcbc1758aae9 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/typedef/decoder/string.j2 @@ -0,0 +1,17 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +{% if annotate %} +/* typedef {{ name }} */ +{% endif %} +{% if name in public_apis %} +bool +{% else %} +static bool __maybe_unused +{% endif %} +xdrgen_decode_{{ name }}(struct xdr_stream *xdr, {{ classifier }}{{ name }} *ptr) +{ +{% if annotate %} + /* (variable-length string) */ +{% endif %} + return xdrgen_decode_string(xdr, ptr, {{ maxsize }}); +} diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/decoder/variable_length_array.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/decoder/variable_length_array.j2 new file mode 100644 index 000000000000..a59cc1f38eed --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/typedef/decoder/variable_length_array.j2 @@ -0,0 +1,26 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +{% if annotate %} +/* typedef {{ name }} */ +{% endif %} +{% if name in public_apis %} +bool +{% else %} +static bool __maybe_unused +{% endif %} +xdrgen_decode_{{ name }}(struct xdr_stream *xdr, {{ classifier }}{{ name }} *ptr) +{ +{% if annotate %} + /* (variable-length array) */ +{% endif %} + if (xdr_stream_decode_u32(xdr, &ptr->count) < 0) + return false; +{% if maxsize != "0" %} + if (ptr->count > {{ maxsize }}) + return false; +{% endif %} + for (u32 i = 0; i < ptr->count; i++) + if (!xdrgen_decode_{{ type }}(xdr, &ptr->element[i])) + return false; + return true; +} diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/decoder/variable_length_opaque.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/decoder/variable_length_opaque.j2 new file mode 100644 index 000000000000..eb05f53e1041 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/typedef/decoder/variable_length_opaque.j2 @@ -0,0 +1,17 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +{% if annotate %} +/* typedef {{ name }} */ +{% endif %} +{% if name in public_apis %} +bool +{% else %} +static bool __maybe_unused +{% endif %} +xdrgen_decode_{{ name }}(struct xdr_stream *xdr, {{ classifier }}{{ name }} *ptr) +{ +{% if annotate %} + /* (variable-length opaque) */ +{% endif %} + return xdrgen_decode_opaque(xdr, ptr, {{ maxsize }}); +} diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/definition/basic.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/definition/basic.j2 new file mode 100644 index 000000000000..1c5f28135eec --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/typedef/definition/basic.j2 @@ -0,0 +1,6 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +{% if annotate %} +/* typedef {{ name }} (basic) */ +{% endif %} +typedef {{ classifier }}{{ type }} {{ name }}; diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/definition/fixed_length_array.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/definition/fixed_length_array.j2 new file mode 100644 index 000000000000..c3a67c952e77 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/typedef/definition/fixed_length_array.j2 @@ -0,0 +1,6 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +{% if annotate %} +/* typedef {{ name }} (fixed-length array) */ +{% endif %} +typedef {{ type }}{{ name }}[{{ size }}]; diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/definition/fixed_length_opaque.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/definition/fixed_length_opaque.j2 new file mode 100644 index 000000000000..8788b02fe4f5 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/typedef/definition/fixed_length_opaque.j2 @@ -0,0 +1,6 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +{% if annotate %} +/* typedef {{ name }} (fixed-length opaque) */ +{% endif %} +typedef u8 {{ name }}[{{ size }}]; diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/definition/string.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/definition/string.j2 new file mode 100644 index 000000000000..c03c2df8e625 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/typedef/definition/string.j2 @@ -0,0 +1,6 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +{% if annotate %} +/* typedef {{ name }} (variable-length string) */ +{% endif %} +typedef string {{ name }}; diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/definition/variable_length_array.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/definition/variable_length_array.j2 new file mode 100644 index 000000000000..f03393760545 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/typedef/definition/variable_length_array.j2 @@ -0,0 +1,9 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +{% if annotate %} +/* typedef {{ name }} (variable-length array) */ +{% endif %} +typedef struct { + u32 count; + {{ classifier }}{{ type }} *element; +} {{ name }}; diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/definition/variable_length_opaque.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/definition/variable_length_opaque.j2 new file mode 100644 index 000000000000..162f2610af34 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/typedef/definition/variable_length_opaque.j2 @@ -0,0 +1,6 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +{% if annotate %} +/* typedef {{ name }} (variable-length opaque) */ +{% endif %} +typedef opaque {{ name }}; diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/encoder/basic.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/encoder/basic.j2 new file mode 100644 index 000000000000..0d21dd0b723a --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/typedef/encoder/basic.j2 @@ -0,0 +1,21 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +{% if annotate %} +/* typedef {{ name }} */ +{% endif %} +{% if name in public_apis %} +bool +{% else %} +static bool __maybe_unused +{% endif %} +{% if name in pass_by_reference %} +xdrgen_encode_{{ name }}(struct xdr_stream *xdr, const {{ classifier }}{{ name }} *value) +{% else %} +xdrgen_encode_{{ name }}(struct xdr_stream *xdr, const {{ classifier }}{{ name }} value) +{% endif %} +{ +{% if annotate %} + /* (basic) */ +{% endif %} + return xdrgen_encode_{{ type }}(xdr, value); +} diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/encoder/fixed_length_array.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/encoder/fixed_length_array.j2 new file mode 100644 index 000000000000..ec8cd6509514 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/typedef/encoder/fixed_length_array.j2 @@ -0,0 +1,25 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +{% if annotate %} +/* typedef {{ name }} */ +{% endif %} +{% if name in public_apis %} +bool +{% else %} +static bool __maybe_unused +{% endif %} +xdrgen_encode_{{ name }}(struct xdr_stream *xdr, const {{ classifier }}{{ name }} value) +{ +{% if annotate %} + /* (fixed-length array) */ +{% endif %} + for (u32 i = 0; i < {{ size }}; i++) { +{% if type in pass_by_reference %} + if (xdrgen_encode_{{ type }}(xdr, &value->items[i]) < 0) +{% else %} + if (xdrgen_encode_{{ type }}(xdr, value->items[i]) < 0) +{% endif %} + return false; + } + return true; +} diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/encoder/fixed_length_opaque.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/encoder/fixed_length_opaque.j2 new file mode 100644 index 000000000000..b53fa87e1858 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/typedef/encoder/fixed_length_opaque.j2 @@ -0,0 +1,17 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +{% if annotate %} +/* typedef {{ name }} */ +{% endif %} +{% if name in public_apis %} +bool +{% else %} +static bool __maybe_unused +{% endif %} +xdrgen_encode_{{ name }}(struct xdr_stream *xdr, const {{ classifier }}{{ name }} value) +{ +{% if annotate %} + /* (fixed-length opaque) */ +{% endif %} + return xdr_stream_encode_opaque_fixed(xdr, value, {{ size }}) >= 0; +} diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/encoder/string.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/encoder/string.j2 new file mode 100644 index 000000000000..28b81f1d0bd6 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/typedef/encoder/string.j2 @@ -0,0 +1,17 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +{% if annotate %} +/* typedef {{ name }} */ +{% endif %} +{% if name in public_apis %} +bool +{% else %} +static bool __maybe_unused +{% endif %} +xdrgen_encode_{{ name }}(struct xdr_stream *xdr, const {{ classifier }}{{ name }} value) +{ +{% if annotate %} + /* (variable-length string) */ +{% endif %} + return xdr_stream_encode_opaque(xdr, value.data, value.len) >= 0; +} diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/encoder/variable_length_array.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/encoder/variable_length_array.j2 new file mode 100644 index 000000000000..ff093c281d51 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/typedef/encoder/variable_length_array.j2 @@ -0,0 +1,30 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +{% if annotate %} +/* typedef {{ name }} */ +{% endif %} +{% if name in public_apis %} +bool +{% else %} +static bool __maybe_unused +{% endif %} +xdrgen_encode_{{ name }}(struct xdr_stream *xdr, const {{ classifier }}{{ name }} value) +{ +{% if annotate %} + /* (variable-length array) */ +{% endif %} +{% if maxsize != "0" %} + if (unlikely(value.count > {{ maxsize }})) + return false; +{% endif %} + if (xdr_stream_encode_u32(xdr, value.count) != XDR_UNIT) + return false; + for (u32 i = 0; i < value.count; i++) +{% if type in pass_by_reference %} + if (!xdrgen_encode_{{ type }}(xdr, &value.element[i])) +{% else %} + if (!xdrgen_encode_{{ type }}(xdr, value.element[i])) +{% endif %} + return false; + return true; +} diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/encoder/variable_length_opaque.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/encoder/variable_length_opaque.j2 new file mode 100644 index 000000000000..2e89592fa702 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/typedef/encoder/variable_length_opaque.j2 @@ -0,0 +1,17 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +{% if annotate %} +/* typedef {{ name }} */ +{% endif %} +{% if name in public_apis %} +bool +{% else %} +static bool __maybe_unused +{% endif %} +xdrgen_encode_{{ name }}(struct xdr_stream *xdr, const {{ classifier }}{{ name }} value) +{ +{% if annotate %} + /* (variable-length opaque) */ +{% endif %} + return xdr_stream_encode_opaque(xdr, value.data, value.len) >= 0; +} diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/maxsize/basic.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/maxsize/basic.j2 new file mode 100644 index 000000000000..9f3bfb47d2f4 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/typedef/maxsize/basic.j2 @@ -0,0 +1,3 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +#define {{ '{:<31}'.format(macro) }} \ + ({{ width }}) diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/maxsize/fixed_length_opaque.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/maxsize/fixed_length_opaque.j2 new file mode 100644 index 000000000000..45c1d4c21b22 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/typedef/maxsize/fixed_length_opaque.j2 @@ -0,0 +1,2 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +#define {{ '{:<31}'.format(macro) }} ({{ width }}) diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/maxsize/string.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/maxsize/string.j2 new file mode 100644 index 000000000000..45c1d4c21b22 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/typedef/maxsize/string.j2 @@ -0,0 +1,2 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +#define {{ '{:<31}'.format(macro) }} ({{ width }}) diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/maxsize/variable_length_array.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/maxsize/variable_length_array.j2 new file mode 100644 index 000000000000..45c1d4c21b22 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/typedef/maxsize/variable_length_array.j2 @@ -0,0 +1,2 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +#define {{ '{:<31}'.format(macro) }} ({{ width }}) diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/maxsize/variable_length_opaque.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/maxsize/variable_length_opaque.j2 new file mode 100644 index 000000000000..45c1d4c21b22 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/typedef/maxsize/variable_length_opaque.j2 @@ -0,0 +1,2 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +#define {{ '{:<31}'.format(macro) }} ({{ width }}) diff --git a/tools/net/sunrpc/xdrgen/templates/C/union/declaration/close.j2 b/tools/net/sunrpc/xdrgen/templates/C/union/declaration/close.j2 new file mode 100644 index 000000000000..816291184e8c --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/union/declaration/close.j2 @@ -0,0 +1,4 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +bool xdrgen_decode_{{ name }}(struct xdr_stream *xdr, struct {{ name }} *ptr); +bool xdrgen_encode_{{ name }}(struct xdr_stream *xdr, const struct {{ name }} *value); diff --git a/tools/net/sunrpc/xdrgen/templates/C/union/decoder/basic.j2 b/tools/net/sunrpc/xdrgen/templates/C/union/decoder/basic.j2 new file mode 100644 index 000000000000..4d97cc5395eb --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/union/decoder/basic.j2 @@ -0,0 +1,6 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* member {{ name }} (basic) */ +{% endif %} + if (!xdrgen_decode_{{ type }}(xdr, &ptr->u.{{ name }})) + return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/union/decoder/break.j2 b/tools/net/sunrpc/xdrgen/templates/C/union/decoder/break.j2 new file mode 100644 index 000000000000..b286d1407029 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/union/decoder/break.j2 @@ -0,0 +1,2 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + break; diff --git a/tools/net/sunrpc/xdrgen/templates/C/union/decoder/case_spec.j2 b/tools/net/sunrpc/xdrgen/templates/C/union/decoder/case_spec.j2 new file mode 100644 index 000000000000..5fa2163f0a74 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/union/decoder/case_spec.j2 @@ -0,0 +1,2 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + case {{ case }}: diff --git a/tools/net/sunrpc/xdrgen/templates/C/union/decoder/case_spec_be.j2 b/tools/net/sunrpc/xdrgen/templates/C/union/decoder/case_spec_be.j2 new file mode 100644 index 000000000000..917f3a1c4588 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/union/decoder/case_spec_be.j2 @@ -0,0 +1,2 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + case __constant_cpu_to_be32({{ case }}): diff --git a/tools/net/sunrpc/xdrgen/templates/C/union/decoder/close.j2 b/tools/net/sunrpc/xdrgen/templates/C/union/decoder/close.j2 new file mode 100644 index 000000000000..39d8d6c5094d --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/union/decoder/close.j2 @@ -0,0 +1,4 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + } + return true; +} diff --git a/tools/net/sunrpc/xdrgen/templates/C/union/decoder/default_spec.j2 b/tools/net/sunrpc/xdrgen/templates/C/union/decoder/default_spec.j2 new file mode 100644 index 000000000000..044a002d0589 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/union/decoder/default_spec.j2 @@ -0,0 +1,2 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + default: diff --git a/tools/net/sunrpc/xdrgen/templates/C/union/decoder/open.j2 b/tools/net/sunrpc/xdrgen/templates/C/union/decoder/open.j2 new file mode 100644 index 000000000000..eb9941376e49 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/union/decoder/open.j2 @@ -0,0 +1,12 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +{% if annotate %} +/* union {{ name }} */ +{% endif %} +{% if name in public_apis %} +bool +{% else %} +static bool __maybe_unused +{% endif %} +xdrgen_decode_{{ name }}(struct xdr_stream *xdr, struct {{ name }} *ptr) +{ diff --git a/tools/net/sunrpc/xdrgen/templates/C/union/decoder/optional_data.j2 b/tools/net/sunrpc/xdrgen/templates/C/union/decoder/optional_data.j2 new file mode 100644 index 000000000000..e4476f5fd8d3 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/union/decoder/optional_data.j2 @@ -0,0 +1,6 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* member {{ name }} (optional data) */ +{% endif %} + if (!xdrgen_decode_{{ type }}(xdr, &ptr->u.{{ name }})) + return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/union/decoder/string.j2 b/tools/net/sunrpc/xdrgen/templates/C/union/decoder/string.j2 new file mode 100644 index 000000000000..83b6e5a14e7f --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/union/decoder/string.j2 @@ -0,0 +1,6 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* member {{ name }} (variable-length string) */ +{% endif %} + if (!xdrgen_decode_string(xdr, (struct string *)ptr->u.{{ name }}, {{ maxsize }})) + return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/union/decoder/switch_spec.j2 b/tools/net/sunrpc/xdrgen/templates/C/union/decoder/switch_spec.j2 new file mode 100644 index 000000000000..99b3067ef617 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/union/decoder/switch_spec.j2 @@ -0,0 +1,7 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* discriminant {{ name }} */ +{% endif %} + if (!xdrgen_decode_{{ type }}(xdr, &ptr->{{ name }})) + return false; + switch (ptr->{{ name }}) { diff --git a/tools/net/sunrpc/xdrgen/templates/C/union/decoder/variable_length_array.j2 b/tools/net/sunrpc/xdrgen/templates/C/union/decoder/variable_length_array.j2 new file mode 100644 index 000000000000..53dfaf9cec68 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/union/decoder/variable_length_array.j2 @@ -0,0 +1,15 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* member {{ name }} (variable-length array) */ +{% endif %} + if (xdr_stream_decode_u32(xdr, &count) < 0) + return false; +{% if maxsize != "0" %} + if (count > {{ maxsize }}) + return false; +{% endif %} + for (u32 i = 0; i < count; i++) { + if (xdrgen_decode_{{ type }}(xdr, &ptr->{{ name }}.items[i]) < 0) + return false; + } + ptr->{{ name }}.len = count; diff --git a/tools/net/sunrpc/xdrgen/templates/C/union/decoder/variable_length_opaque.j2 b/tools/net/sunrpc/xdrgen/templates/C/union/decoder/variable_length_opaque.j2 new file mode 100644 index 000000000000..c9d88ed29c78 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/union/decoder/variable_length_opaque.j2 @@ -0,0 +1,6 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* member {{ name }} (variable-length opaque) */ +{% endif %} + if (!xdrgen_decode_opaque(xdr, (struct opaque *)ptr->u.{{ name }}, {{ maxsize }})) + return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/union/decoder/void.j2 b/tools/net/sunrpc/xdrgen/templates/C/union/decoder/void.j2 new file mode 100644 index 000000000000..65205ce37b36 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/union/decoder/void.j2 @@ -0,0 +1,3 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + if (!xdrgen_decode_void(xdr)) + return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/union/definition/case_spec.j2 b/tools/net/sunrpc/xdrgen/templates/C/union/definition/case_spec.j2 new file mode 100644 index 000000000000..52f8d131b805 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/union/definition/case_spec.j2 @@ -0,0 +1,2 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + {{ classifier }}{{ type }} {{ name }}; diff --git a/tools/net/sunrpc/xdrgen/templates/C/union/definition/close.j2 b/tools/net/sunrpc/xdrgen/templates/C/union/definition/close.j2 new file mode 100644 index 000000000000..01d716d0099e --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/union/definition/close.j2 @@ -0,0 +1,8 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + } u; +}; +{%- if name in public_apis %} + +bool xdrgen_decode_{{ name }}(struct xdr_stream *xdr, struct {{ name }} *ptr); +bool xdrgen_encode_{{ name }}(struct xdr_stream *xdr, const struct {{ name }} *ptr); +{%- endif -%} diff --git a/tools/net/sunrpc/xdrgen/templates/C/union/definition/default_spec.j2 b/tools/net/sunrpc/xdrgen/templates/C/union/definition/default_spec.j2 new file mode 100644 index 000000000000..52f8d131b805 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/union/definition/default_spec.j2 @@ -0,0 +1,2 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + {{ classifier }}{{ type }} {{ name }}; diff --git a/tools/net/sunrpc/xdrgen/templates/C/union/definition/open.j2 b/tools/net/sunrpc/xdrgen/templates/C/union/definition/open.j2 new file mode 100644 index 000000000000..20fcfd1fc4e5 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/union/definition/open.j2 @@ -0,0 +1,6 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +{% if annotate %} +/* union {{ name }} */ +{% endif %} +struct {{ name }} { diff --git a/tools/net/sunrpc/xdrgen/templates/C/union/definition/switch_spec.j2 b/tools/net/sunrpc/xdrgen/templates/C/union/definition/switch_spec.j2 new file mode 100644 index 000000000000..3e552732502c --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/union/definition/switch_spec.j2 @@ -0,0 +1,3 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + {{ classifier }}{{ type }} {{ name }}; + union { diff --git a/tools/net/sunrpc/xdrgen/templates/C/union/encoder/basic.j2 b/tools/net/sunrpc/xdrgen/templates/C/union/encoder/basic.j2 new file mode 100644 index 000000000000..6452d75c6f9a --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/union/encoder/basic.j2 @@ -0,0 +1,10 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* member {{ name }} (basic) */ +{% endif %} +{% if type in pass_by_reference %} + if (!xdrgen_encode_{{ type }}(xdr, &ptr->u.{{ name }})) +{% else %} + if (!xdrgen_encode_{{ type }}(xdr, ptr->u.{{ name }})) +{% endif %} + return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/union/encoder/break.j2 b/tools/net/sunrpc/xdrgen/templates/C/union/encoder/break.j2 new file mode 100644 index 000000000000..b286d1407029 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/union/encoder/break.j2 @@ -0,0 +1,2 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + break; diff --git a/tools/net/sunrpc/xdrgen/templates/C/union/encoder/case_spec.j2 b/tools/net/sunrpc/xdrgen/templates/C/union/encoder/case_spec.j2 new file mode 100644 index 000000000000..5fa2163f0a74 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/union/encoder/case_spec.j2 @@ -0,0 +1,2 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + case {{ case }}: diff --git a/tools/net/sunrpc/xdrgen/templates/C/union/encoder/case_spec_be.j2 b/tools/net/sunrpc/xdrgen/templates/C/union/encoder/case_spec_be.j2 new file mode 100644 index 000000000000..917f3a1c4588 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/union/encoder/case_spec_be.j2 @@ -0,0 +1,2 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + case __constant_cpu_to_be32({{ case }}): diff --git a/tools/net/sunrpc/xdrgen/templates/C/union/encoder/close.j2 b/tools/net/sunrpc/xdrgen/templates/C/union/encoder/close.j2 new file mode 100644 index 000000000000..39d8d6c5094d --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/union/encoder/close.j2 @@ -0,0 +1,4 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + } + return true; +} diff --git a/tools/net/sunrpc/xdrgen/templates/C/union/encoder/default_spec.j2 b/tools/net/sunrpc/xdrgen/templates/C/union/encoder/default_spec.j2 new file mode 100644 index 000000000000..044a002d0589 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/union/encoder/default_spec.j2 @@ -0,0 +1,2 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + default: diff --git a/tools/net/sunrpc/xdrgen/templates/C/union/encoder/open.j2 b/tools/net/sunrpc/xdrgen/templates/C/union/encoder/open.j2 new file mode 100644 index 000000000000..e5a206df10c6 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/union/encoder/open.j2 @@ -0,0 +1,12 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +{% if annotate %} +/* union {{ name }} */ +{% endif %} +{% if name in public_apis %} +bool +{% else %} +static bool __maybe_unused +{% endif %} +xdrgen_encode_{{ name }}(struct xdr_stream *xdr, const struct {{ name }} *ptr) +{ diff --git a/tools/net/sunrpc/xdrgen/templates/C/union/encoder/string.j2 b/tools/net/sunrpc/xdrgen/templates/C/union/encoder/string.j2 new file mode 100644 index 000000000000..2f035a64f1f4 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/union/encoder/string.j2 @@ -0,0 +1,6 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* member {{ name }} (variable-length string) */ +{% endif %} + if (!xdrgen_encode_string(xdr, ptr->u.{{ name }}, {{ maxsize }})) + return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/union/encoder/switch_spec.j2 b/tools/net/sunrpc/xdrgen/templates/C/union/encoder/switch_spec.j2 new file mode 100644 index 000000000000..c8c3ecbe038b --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/union/encoder/switch_spec.j2 @@ -0,0 +1,7 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* discriminant {{ name }} */ +{% endif %} + if (!xdrgen_encode_{{ type }}(xdr, ptr->{{ name }})) + return false; + switch (ptr->{{ name }}) { diff --git a/tools/net/sunrpc/xdrgen/templates/C/union/encoder/void.j2 b/tools/net/sunrpc/xdrgen/templates/C/union/encoder/void.j2 new file mode 100644 index 000000000000..84e7c2127d75 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/union/encoder/void.j2 @@ -0,0 +1,3 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + if (!xdrgen_encode_void(xdr)) + return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/union/maxsize/union.j2 b/tools/net/sunrpc/xdrgen/templates/C/union/maxsize/union.j2 new file mode 100644 index 000000000000..9f3bfb47d2f4 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/union/maxsize/union.j2 @@ -0,0 +1,3 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +#define {{ '{:<31}'.format(macro) }} \ + ({{ width }}) diff --git a/tools/net/sunrpc/xdrgen/tests/test.x b/tools/net/sunrpc/xdrgen/tests/test.x new file mode 100644 index 000000000000..90c8587f6fe5 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/tests/test.x @@ -0,0 +1,36 @@ +/* Sample XDR specification from RFC 1832 Section 5.5 */ + +const MAXUSERNAME = 32; /* max length of a user name */ +const MAXFILELEN = 65535; /* max length of a file */ +const MAXNAMELEN = 255; /* max length of a file name */ + +/* + * Types of files: + */ +enum filekind { + TEXT = 0, /* ascii data */ + DATA = 1, /* raw data */ + EXEC = 2 /* executable */ +}; + +/* + * File information, per kind of file: + */ +union filetype switch (filekind kind) { +case TEXT: + void; /* no extra information */ +case DATA: + string creator<MAXNAMELEN>; /* data creator */ +case EXEC: + string interpretor<MAXNAMELEN>; /* program interpretor */ +}; + +/* + * A complete file: + */ +struct file { + string filename<MAXNAMELEN>; /* name of file */ + filetype type; /* info about file */ + string owner<MAXUSERNAME>; /* owner of file */ + opaque data<MAXFILELEN>; /* file data */ +}; diff --git a/tools/net/sunrpc/xdrgen/xdr_ast.py b/tools/net/sunrpc/xdrgen/xdr_ast.py new file mode 100644 index 000000000000..5233e73c7046 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/xdr_ast.py @@ -0,0 +1,753 @@ +#!/usr/bin/env python3 +# ex: set filetype=python: + +"""Define and implement the Abstract Syntax Tree for the XDR language.""" + +import sys +from typing import List +from dataclasses import dataclass + +from lark import ast_utils, Transformer +from lark.tree import Meta + +this_module = sys.modules[__name__] + +big_endian = [] +excluded_apis = [] +header_name = "none" +public_apis = [] +structs = set() +pass_by_reference = set() + +constants = {} + + +def xdr_quadlen(val: str) -> int: + """Return integer XDR width of an XDR type""" + if val in constants: + octets = constants[val] + else: + octets = int(val) + return int((octets + 3) / 4) + + +symbolic_widths = { + "void": ["XDR_void"], + "bool": ["XDR_bool"], + "int": ["XDR_int"], + "unsigned_int": ["XDR_unsigned_int"], + "long": ["XDR_long"], + "unsigned_long": ["XDR_unsigned_long"], + "hyper": ["XDR_hyper"], + "unsigned_hyper": ["XDR_unsigned_hyper"], +} + +# Numeric XDR widths are tracked in a dictionary that is keyed +# by type_name because sometimes a caller has nothing more than +# the type_name to use to figure out the numeric width. +max_widths = { + "void": 0, + "bool": 1, + "int": 1, + "unsigned_int": 1, + "long": 1, + "unsigned_long": 1, + "hyper": 2, + "unsigned_hyper": 2, +} + + +@dataclass +class _XdrAst(ast_utils.Ast): + """Base class for the XDR abstract syntax tree""" + + +@dataclass +class _XdrIdentifier(_XdrAst): + """Corresponds to 'identifier' in the XDR language grammar""" + + symbol: str + + +@dataclass +class _XdrValue(_XdrAst): + """Corresponds to 'value' in the XDR language grammar""" + + value: str + + +@dataclass +class _XdrConstantValue(_XdrAst): + """Corresponds to 'constant' in the XDR language grammar""" + + value: int + + +@dataclass +class _XdrTypeSpecifier(_XdrAst): + """Corresponds to 'type_specifier' in the XDR language grammar""" + + type_name: str + c_classifier: str = "" + + +@dataclass +class _XdrDefinedType(_XdrTypeSpecifier): + """Corresponds to a type defined by the input specification""" + + def symbolic_width(self) -> List: + """Return list containing XDR width of type's components""" + return [get_header_name().upper() + "_" + self.type_name + "_sz"] + + def __post_init__(self): + if self.type_name in structs: + self.c_classifier = "struct " + symbolic_widths[self.type_name] = self.symbolic_width() + + +@dataclass +class _XdrBuiltInType(_XdrTypeSpecifier): + """Corresponds to a built-in XDR type""" + + def symbolic_width(self) -> List: + """Return list containing XDR width of type's components""" + return symbolic_widths[self.type_name] + + +@dataclass +class _XdrDeclaration(_XdrAst): + """Base class of XDR type declarations""" + + +@dataclass +class _XdrFixedLengthOpaque(_XdrDeclaration): + """A fixed-length opaque declaration""" + + name: str + size: str + template: str = "fixed_length_opaque" + + def max_width(self) -> int: + """Return width of type in XDR_UNITS""" + return xdr_quadlen(self.size) + + def symbolic_width(self) -> List: + """Return list containing XDR width of type's components""" + return ["XDR_QUADLEN(" + self.size + ")"] + + def __post_init__(self): + max_widths[self.name] = self.max_width() + symbolic_widths[self.name] = self.symbolic_width() + + +@dataclass +class _XdrVariableLengthOpaque(_XdrDeclaration): + """A variable-length opaque declaration""" + + name: str + maxsize: str + template: str = "variable_length_opaque" + + def max_width(self) -> int: + """Return width of type in XDR_UNITS""" + return 1 + xdr_quadlen(self.maxsize) + + def symbolic_width(self) -> List: + """Return list containing XDR width of type's components""" + widths = ["XDR_unsigned_int"] + if self.maxsize != "0": + widths.append("XDR_QUADLEN(" + self.maxsize + ")") + return widths + + def __post_init__(self): + max_widths[self.name] = self.max_width() + symbolic_widths[self.name] = self.symbolic_width() + + +@dataclass +class _XdrString(_XdrDeclaration): + """A (NUL-terminated) variable-length string declaration""" + + name: str + maxsize: str + template: str = "string" + + def max_width(self) -> int: + """Return width of type in XDR_UNITS""" + return 1 + xdr_quadlen(self.maxsize) + + def symbolic_width(self) -> List: + """Return list containing XDR width of type's components""" + widths = ["XDR_unsigned_int"] + if self.maxsize != "0": + widths.append("XDR_QUADLEN(" + self.maxsize + ")") + return widths + + def __post_init__(self): + max_widths[self.name] = self.max_width() + symbolic_widths[self.name] = self.symbolic_width() + + +@dataclass +class _XdrFixedLengthArray(_XdrDeclaration): + """A fixed-length array declaration""" + + name: str + spec: _XdrTypeSpecifier + size: str + template: str = "fixed_length_array" + + def max_width(self) -> int: + """Return width of type in XDR_UNITS""" + return xdr_quadlen(self.size) * max_widths[self.spec.type_name] + + def symbolic_width(self) -> List: + """Return list containing XDR width of type's components""" + item_width = " + ".join(symbolic_widths[self.spec.type_name]) + return ["(" + self.size + " * (" + item_width + "))"] + + def __post_init__(self): + max_widths[self.name] = self.max_width() + symbolic_widths[self.name] = self.symbolic_width() + + +@dataclass +class _XdrVariableLengthArray(_XdrDeclaration): + """A variable-length array declaration""" + + name: str + spec: _XdrTypeSpecifier + maxsize: str + template: str = "variable_length_array" + + def max_width(self) -> int: + """Return width of type in XDR_UNITS""" + return 1 + (xdr_quadlen(self.maxsize) * max_widths[self.spec.type_name]) + + def symbolic_width(self) -> List: + """Return list containing XDR width of type's components""" + widths = ["XDR_unsigned_int"] + if self.maxsize != "0": + item_width = " + ".join(symbolic_widths[self.spec.type_name]) + widths.append("(" + self.maxsize + " * (" + item_width + "))") + return widths + + def __post_init__(self): + max_widths[self.name] = self.max_width() + symbolic_widths[self.name] = self.symbolic_width() + + +@dataclass +class _XdrOptionalData(_XdrDeclaration): + """An 'optional_data' declaration""" + + name: str + spec: _XdrTypeSpecifier + template: str = "optional_data" + + def max_width(self) -> int: + """Return width of type in XDR_UNITS""" + return 1 + + def symbolic_width(self) -> List: + """Return list containing XDR width of type's components""" + return ["XDR_bool"] + + def __post_init__(self): + structs.add(self.name) + pass_by_reference.add(self.name) + max_widths[self.name] = self.max_width() + symbolic_widths[self.name] = self.symbolic_width() + + +@dataclass +class _XdrBasic(_XdrDeclaration): + """A 'basic' declaration""" + + name: str + spec: _XdrTypeSpecifier + template: str = "basic" + + def max_width(self) -> int: + """Return width of type in XDR_UNITS""" + return max_widths[self.spec.type_name] + + def symbolic_width(self) -> List: + """Return list containing XDR width of type's components""" + return symbolic_widths[self.spec.type_name] + + def __post_init__(self): + max_widths[self.name] = self.max_width() + symbolic_widths[self.name] = self.symbolic_width() + + +@dataclass +class _XdrVoid(_XdrDeclaration): + """A void declaration""" + + name: str = "void" + template: str = "void" + + def max_width(self) -> int: + """Return width of type in XDR_UNITS""" + return 0 + + def symbolic_width(self) -> List: + """Return list containing XDR width of type's components""" + return [] + + +@dataclass +class _XdrConstant(_XdrAst): + """Corresponds to 'constant_def' in the grammar""" + + name: str + value: str + + def __post_init__(self): + if self.value not in constants: + constants[self.name] = int(self.value, 0) + + +@dataclass +class _XdrEnumerator(_XdrAst): + """An 'identifier = value' enumerator""" + + name: str + value: str + + def __post_init__(self): + if self.value not in constants: + constants[self.name] = int(self.value, 0) + + +@dataclass +class _XdrEnum(_XdrAst): + """An XDR enum definition""" + + name: str + minimum: int + maximum: int + enumerators: List[_XdrEnumerator] + + def max_width(self) -> int: + """Return width of type in XDR_UNITS""" + return 1 + + def symbolic_width(self) -> List: + """Return list containing XDR width of type's components""" + return ["XDR_int"] + + def __post_init__(self): + max_widths[self.name] = self.max_width() + symbolic_widths[self.name] = self.symbolic_width() + + +@dataclass +class _XdrStruct(_XdrAst): + """An XDR struct definition""" + + name: str + fields: List[_XdrDeclaration] + + def max_width(self) -> int: + """Return width of type in XDR_UNITS""" + width = 0 + for field in self.fields: + width += field.max_width() + return width + + def symbolic_width(self) -> List: + """Return list containing XDR width of type's components""" + widths = [] + for field in self.fields: + widths += field.symbolic_width() + return widths + + def __post_init__(self): + structs.add(self.name) + pass_by_reference.add(self.name) + max_widths[self.name] = self.max_width() + symbolic_widths[self.name] = self.symbolic_width() + + +@dataclass +class _XdrPointer(_XdrAst): + """An XDR pointer definition""" + + name: str + fields: List[_XdrDeclaration] + + def max_width(self) -> int: + """Return width of type in XDR_UNITS""" + width = 1 + for field in self.fields[0:-1]: + width += field.max_width() + return width + + def symbolic_width(self) -> List: + """Return list containing XDR width of type's components""" + widths = [] + widths += ["XDR_bool"] + for field in self.fields[0:-1]: + widths += field.symbolic_width() + return widths + + def __post_init__(self): + structs.add(self.name) + pass_by_reference.add(self.name) + max_widths[self.name] = self.max_width() + symbolic_widths[self.name] = self.symbolic_width() + + +@dataclass +class _XdrTypedef(_XdrAst): + """An XDR typedef""" + + declaration: _XdrDeclaration + + def max_width(self) -> int: + """Return width of type in XDR_UNITS""" + return self.declaration.max_width() + + def symbolic_width(self) -> List: + """Return list containing XDR width of type's components""" + return self.declaration.symbolic_width() + + def __post_init__(self): + if isinstance(self.declaration, _XdrBasic): + new_type = self.declaration + if isinstance(new_type.spec, _XdrDefinedType): + if new_type.spec.type_name in pass_by_reference: + pass_by_reference.add(new_type.name) + max_widths[new_type.name] = self.max_width() + symbolic_widths[new_type.name] = self.symbolic_width() + + +@dataclass +class _XdrCaseSpec(_XdrAst): + """One case in an XDR union""" + + values: List[str] + arm: _XdrDeclaration + template: str = "case_spec" + + +@dataclass +class _XdrDefaultSpec(_XdrAst): + """Default case in an XDR union""" + + arm: _XdrDeclaration + template: str = "default_spec" + + +@dataclass +class _XdrUnion(_XdrAst): + """An XDR union""" + + name: str + discriminant: _XdrDeclaration + cases: List[_XdrCaseSpec] + default: _XdrDeclaration + + def max_width(self) -> int: + """Return width of type in XDR_UNITS""" + max_width = 0 + for case in self.cases: + if case.arm.max_width() > max_width: + max_width = case.arm.max_width() + if self.default: + if self.default.arm.max_width() > max_width: + max_width = self.default.arm.max_width() + return 1 + max_width + + def symbolic_width(self) -> List: + """Return list containing XDR width of type's components""" + max_width = 0 + for case in self.cases: + if case.arm.max_width() > max_width: + max_width = case.arm.max_width() + width = case.arm.symbolic_width() + if self.default: + if self.default.arm.max_width() > max_width: + max_width = self.default.arm.max_width() + width = self.default.arm.symbolic_width() + return symbolic_widths[self.discriminant.name] + width + + def __post_init__(self): + structs.add(self.name) + pass_by_reference.add(self.name) + max_widths[self.name] = self.max_width() + symbolic_widths[self.name] = self.symbolic_width() + + +@dataclass +class _RpcProcedure(_XdrAst): + """RPC procedure definition""" + + name: str + number: str + argument: _XdrTypeSpecifier + result: _XdrTypeSpecifier + + +@dataclass +class _RpcVersion(_XdrAst): + """RPC version definition""" + + name: str + number: str + procedures: List[_RpcProcedure] + + +@dataclass +class _RpcProgram(_XdrAst): + """RPC program definition""" + + name: str + number: str + versions: List[_RpcVersion] + + +@dataclass +class _Pragma(_XdrAst): + """Empty class for pragma directives""" + + +@dataclass +class Definition(_XdrAst, ast_utils.WithMeta): + """Corresponds to 'definition' in the grammar""" + + meta: Meta + value: _XdrAst + + +@dataclass +class Specification(_XdrAst, ast_utils.AsList): + """Corresponds to 'specification' in the grammar""" + + definitions: List[Definition] + + +class ParseToAst(Transformer): + """Functions that transform productions into AST nodes""" + + def identifier(self, children): + """Instantiate one _XdrIdentifier object""" + return _XdrIdentifier(children[0].value) + + def value(self, children): + """Instantiate one _XdrValue object""" + if isinstance(children[0], _XdrIdentifier): + return _XdrValue(children[0].symbol) + return _XdrValue(children[0].children[0].value) + + def constant(self, children): + """Instantiate one _XdrConstantValue object""" + match children[0].data: + case "decimal_constant": + value = int(children[0].children[0].value, base=10) + case "hexadecimal_constant": + value = int(children[0].children[0].value, base=16) + case "octal_constant": + value = int(children[0].children[0].value, base=8) + return _XdrConstantValue(value) + + def type_specifier(self, children): + """Instantiate one _XdrTypeSpecifier object""" + if isinstance(children[0], _XdrIdentifier): + name = children[0].symbol + return _XdrDefinedType(type_name=name) + + name = children[0].data.value + return _XdrBuiltInType(type_name=name) + + def constant_def(self, children): + """Instantiate one _XdrConstant object""" + name = children[0].symbol + value = children[1].value + return _XdrConstant(name, value) + + # cel: Python can compute a min() and max() for the enumerator values + # so that the generated code can perform proper range checking. + def enum(self, children): + """Instantiate one _XdrEnum object""" + enum_name = children[0].symbol + + i = 0 + enumerators = [] + body = children[1] + while i < len(body.children): + name = body.children[i].symbol + value = body.children[i + 1].value + enumerators.append(_XdrEnumerator(name, value)) + i = i + 2 + + return _XdrEnum(enum_name, 0, 0, enumerators) + + def fixed_length_opaque(self, children): + """Instantiate one _XdrFixedLengthOpaque declaration object""" + name = children[0].symbol + size = children[1].value + + return _XdrFixedLengthOpaque(name, size) + + def variable_length_opaque(self, children): + """Instantiate one _XdrVariableLengthOpaque declaration object""" + name = children[0].symbol + if children[1] is not None: + maxsize = children[1].value + else: + maxsize = "0" + + return _XdrVariableLengthOpaque(name, maxsize) + + def string(self, children): + """Instantiate one _XdrString declaration object""" + name = children[0].symbol + if children[1] is not None: + maxsize = children[1].value + else: + maxsize = "0" + + return _XdrString(name, maxsize) + + def fixed_length_array(self, children): + """Instantiate one _XdrFixedLengthArray declaration object""" + spec = children[0] + name = children[1].symbol + size = children[2].value + + return _XdrFixedLengthArray(name, spec, size) + + def variable_length_array(self, children): + """Instantiate one _XdrVariableLengthArray declaration object""" + spec = children[0] + name = children[1].symbol + if children[2] is not None: + maxsize = children[2].value + else: + maxsize = "0" + + return _XdrVariableLengthArray(name, spec, maxsize) + + def optional_data(self, children): + """Instantiate one _XdrOptionalData declaration object""" + spec = children[0] + name = children[1].symbol + + return _XdrOptionalData(name, spec) + + def basic(self, children): + """Instantiate one _XdrBasic object""" + spec = children[0] + name = children[1].symbol + + return _XdrBasic(name, spec) + + def void(self, children): + """Instantiate one _XdrVoid declaration object""" + + return _XdrVoid() + + def struct(self, children): + """Instantiate one _XdrStruct object""" + name = children[0].symbol + fields = children[1].children + + last_field = fields[-1] + if ( + isinstance(last_field, _XdrOptionalData) + and name == last_field.spec.type_name + ): + return _XdrPointer(name, fields) + + return _XdrStruct(name, fields) + + def typedef(self, children): + """Instantiate one _XdrTypedef object""" + new_type = children[0] + + return _XdrTypedef(new_type) + + def case_spec(self, children): + """Instantiate one _XdrCaseSpec object""" + values = [] + for item in children[0:-1]: + values.append(item.value) + arm = children[-1] + + return _XdrCaseSpec(values, arm) + + def default_spec(self, children): + """Instantiate one _XdrDefaultSpec object""" + arm = children[0] + + return _XdrDefaultSpec(arm) + + def union(self, children): + """Instantiate one _XdrUnion object""" + name = children[0].symbol + + body = children[1] + discriminant = body.children[0].children[0] + cases = body.children[1:-1] + default = body.children[-1] + + return _XdrUnion(name, discriminant, cases, default) + + def procedure_def(self, children): + """Instantiate one _RpcProcedure object""" + result = children[0] + name = children[1].symbol + argument = children[2] + number = children[3].value + + return _RpcProcedure(name, number, argument, result) + + def version_def(self, children): + """Instantiate one _RpcVersion object""" + name = children[0].symbol + number = children[-1].value + procedures = children[1:-1] + + return _RpcVersion(name, number, procedures) + + def program_def(self, children): + """Instantiate one _RpcProgram object""" + name = children[0].symbol + number = children[-1].value + versions = children[1:-1] + + return _RpcProgram(name, number, versions) + + def pragma_def(self, children): + """Instantiate one _Pragma object""" + directive = children[0].children[0].data + match directive: + case "big_endian_directive": + big_endian.append(children[1].symbol) + case "exclude_directive": + excluded_apis.append(children[1].symbol) + case "header_directive": + global header_name + header_name = children[1].symbol + case "public_directive": + public_apis.append(children[1].symbol) + case _: + raise NotImplementedError("Directive not supported") + return _Pragma() + + +transformer = ast_utils.create_transformer(this_module, ParseToAst()) + + +def transform_parse_tree(parse_tree): + """Transform productions into an abstract syntax tree""" + + return transformer.transform(parse_tree) + + +def get_header_name() -> str: + """Return header name set by pragma header directive""" + return header_name diff --git a/tools/net/sunrpc/xdrgen/xdr_parse.py b/tools/net/sunrpc/xdrgen/xdr_parse.py new file mode 100644 index 000000000000..964b44e675df --- /dev/null +++ b/tools/net/sunrpc/xdrgen/xdr_parse.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 +# ex: set filetype=python: + +"""Common parsing code for xdrgen""" + +from lark import Lark + + +# Set to True to emit annotation comments in generated source +annotate = False + + +def set_xdr_annotate(set_it: bool) -> None: + """Set 'annotate' if --annotate was specified on the command line""" + global annotate + annotate = set_it + + +def get_xdr_annotate() -> bool: + """Return True if --annotate was specified on the command line""" + return annotate + + +def xdr_parser() -> Lark: + """Return a Lark parser instance configured with the XDR language grammar""" + + return Lark.open( + "grammars/xdr.lark", + rel_to=__file__, + start="specification", + debug=True, + strict=True, + propagate_positions=True, + parser="lalr", + lexer="contextual", + ) diff --git a/tools/net/sunrpc/xdrgen/xdrgen b/tools/net/sunrpc/xdrgen/xdrgen new file mode 100755 index 000000000000..3afd0547d67c --- /dev/null +++ b/tools/net/sunrpc/xdrgen/xdrgen @@ -0,0 +1,139 @@ +#!/usr/bin/env python3 +# ex: set filetype=python: + +"""Translate an XDR specification into executable code that +can be compiled for the Linux kernel.""" + +__author__ = "Chuck Lever" +__copyright__ = "Copyright (c) 2024 Oracle and/or its affiliates." +__license__ = "GPL-2.0 only" +__version__ = "0.2" + +import sys +from pathlib import Path +import argparse + +_XDRGEN_DIR = Path(__file__).resolve().parent +if str(_XDRGEN_DIR) not in sys.path: + sys.path.insert(0, str(_XDRGEN_DIR)) + +from subcmds import definitions +from subcmds import declarations +from subcmds import lint +from subcmds import source + + +sys.path.insert(1, "@pythondir@") + + +def main() -> int: + """Parse command-line options""" + parser = argparse.ArgumentParser( + formatter_class=argparse.RawDescriptionHelpFormatter, + description="Convert an XDR specification to Linux kernel source code", + epilog="""\ +Copyright (c) 2024 Oracle and/or its affiliates. + +License GPLv2: <http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt> +This is free software. You are free to change and redistribute it. +There is NO WARRANTY, to the extent permitted by law.""", + ) + parser.add_argument( + "--version", + help="Display the version of this tool", + action="version", + version=__version__, + ) + + subcommands = parser.add_subparsers(title="Subcommands", required=True) + + definitions_parser = subcommands.add_parser( + "definitions", help="Generate XDR definitions" + ) + definitions_parser.add_argument( + "--annotate", + action="store_true", + default=False, + help="Add annotation comments", + ) + definitions_parser.add_argument( + "--language", + action="store_true", + default="C", + help="Output language", + ) + definitions_parser.add_argument( + "--peer", + choices=["server", "client",], + default="server", + help="Generate header code for client or server side", + type=str, + ) + definitions_parser.add_argument("filename", help="File containing an XDR specification") + definitions_parser.set_defaults(func=definitions.subcmd) + + declarations_parser = subcommands.add_parser( + "declarations", help="Generate function declarations" + ) + declarations_parser.add_argument( + "--annotate", + action="store_true", + default=False, + help="Add annotation comments", + ) + declarations_parser.add_argument( + "--language", + action="store_true", + default="C", + help="Output language", + ) + declarations_parser.add_argument( + "--peer", + choices=["server", "client",], + default="server", + help="Generate code for client or server side", + type=str, + ) + declarations_parser.add_argument("filename", help="File containing an XDR specification") + declarations_parser.set_defaults(func=declarations.subcmd) + + linter_parser = subcommands.add_parser("lint", help="Check an XDR specification") + linter_parser.add_argument("filename", help="File containing an XDR specification") + linter_parser.set_defaults(func=lint.subcmd) + + source_parser = subcommands.add_parser( + "source", help="Generate XDR encoder and decoder source code" + ) + source_parser.add_argument( + "--annotate", + action="store_true", + default=False, + help="Add annotation comments", + ) + source_parser.add_argument( + "--language", + action="store_true", + default="C", + help="Output language", + ) + source_parser.add_argument( + "--peer", + choices=["server", "client",], + default="server", + help="Generate code for client or server side", + type=str, + ) + source_parser.add_argument("filename", help="File containing an XDR specification") + source_parser.set_defaults(func=source.subcmd) + + args = parser.parse_args() + return args.func(args) + + +try: + if __name__ == "__main__": + sys.exit(main()) +except SystemExit: + sys.exit(0) +except (KeyboardInterrupt, BrokenPipeError): + sys.exit(1) diff --git a/tools/net/ynl/Makefile b/tools/net/ynl/Makefile index 8156f03e23ac..7736b492f559 100644 --- a/tools/net/ynl/Makefile +++ b/tools/net/ynl/Makefile @@ -1,20 +1,77 @@ # SPDX-License-Identifier: GPL-2.0 -SUBDIRS = lib generated samples +include ../../scripts/Makefile.arch -all: $(SUBDIRS) - ./ynl-regen.sh -f -p $(PWD)/../../../ +INSTALL ?= install +prefix ?= /usr +ifeq ($(LP64), 1) + libdir_relative = lib64 +else + libdir_relative = lib +endif +libdir ?= $(prefix)/$(libdir_relative) +includedir ?= $(prefix)/include + +SPECDIR=../../../Documentation/netlink/specs + +SUBDIRS = lib generated samples ynltool tests + +all: $(SUBDIRS) libynl.a + +ynltool: | lib generated libynl.a +samples: | lib generated +libynl.a: | lib generated + @echo -e "\tAR $@" + @ar rcs $@ lib/ynl.o generated/*-user.o $(SUBDIRS): @if [ -f "$@/Makefile" ] ; then \ $(MAKE) -C $@ ; \ fi -clean hardclean: +clean distclean: @for dir in $(SUBDIRS) ; do \ if [ -f "$$dir/Makefile" ] ; then \ $(MAKE) -C $$dir $@; \ fi \ done + rm -f libynl.a + rm -rf pyynl/__pycache__ + rm -rf pyynl/lib/__pycache__ + rm -rf pyynl.egg-info + rm -rf build + +install: libynl.a lib/*.h + @echo -e "\tINSTALL libynl.a" + @$(INSTALL) -d $(DESTDIR)$(libdir) + @$(INSTALL) -m 0644 libynl.a $(DESTDIR)$(libdir)/libynl.a + @echo -e "\tINSTALL libynl headers" + @$(INSTALL) -d $(DESTDIR)$(includedir)/ynl + @$(INSTALL) -m 0644 lib/*.h $(DESTDIR)$(includedir)/ynl/ + @echo -e "\tINSTALL pyynl" + @pip install --prefix=$(DESTDIR)$(prefix) . + @make -C generated install + @make -C tests install + +run_tests: + @$(MAKE) -C tests run_tests + +lint: + yamllint $(SPECDIR) + +schema_check: + @N=1; \ + for spec in $(SPECDIR)/*.yaml ; do \ + NAME=$$(basename $$spec) ; \ + OUTPUT=$$(./pyynl/cli.py --spec $$spec --validate) ; \ + if [ $$? -eq 0 ] ; then \ + echo "ok $$N $$NAME schema validation" ; \ + else \ + echo "not ok $$N $$NAME schema validation" ; \ + echo "$$OUTPUT" ; \ + echo ; \ + fi ; \ + N=$$((N+1)) ; \ + done -.PHONY: clean all $(SUBDIRS) +.PHONY: all clean distclean install run_tests lint schema_check $(SUBDIRS) diff --git a/tools/net/ynl/Makefile.deps b/tools/net/ynl/Makefile.deps index f842bc66b967..865fd2e8519e 100644 --- a/tools/net/ynl/Makefile.deps +++ b/tools/net/ynl/Makefile.deps @@ -15,6 +15,36 @@ UAPI_PATH:=../../../../include/uapi/ get_hdr_inc=-D$(1) -include $(UAPI_PATH)/linux/$(2) CFLAGS_devlink:=$(call get_hdr_inc,_LINUX_DEVLINK_H_,devlink.h) -CFLAGS_ethtool:=$(call get_hdr_inc,_LINUX_ETHTOOL_NETLINK_H_,ethtool_netlink.h) +CFLAGS_dpll:=$(call get_hdr_inc,_LINUX_DPLL_H,dpll.h) +CFLAGS_ethtool:=$(call get_hdr_inc,_LINUX_ETHTOOL_H,ethtool.h) \ + $(call get_hdr_inc,_LINUX_ETHTOOL_NETLINK_H_,ethtool_netlink.h) \ + $(call get_hdr_inc,_LINUX_ETHTOOL_NETLINK_GENERATED_H,ethtool_netlink_generated.h) CFLAGS_handshake:=$(call get_hdr_inc,_LINUX_HANDSHAKE_H,handshake.h) +CFLAGS_lockd_netlink:=$(call get_hdr_inc,_LINUX_LOCKD_NETLINK_H,lockd_netlink.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_ovpn:=$(call get_hdr_inc,_LINUX_OVPN_H,ovpn.h) +CFLAGS_ovs_datapath:=$(call get_hdr_inc,__LINUX_OPENVSWITCH_H,openvswitch.h) +CFLAGS_ovs_flow:=$(call get_hdr_inc,__LINUX_OPENVSWITCH_H,openvswitch.h) +CFLAGS_ovs_vport:=$(call get_hdr_inc,__LINUX_OPENVSWITCH_H,openvswitch.h) +CFLAGS_psp:=$(call get_hdr_inc,_LINUX_PSP_H,psp.h) +CFLAGS_rt-addr:=$(call get_hdr_inc,__LINUX_RTNETLINK_H,rtnetlink.h) \ + $(call get_hdr_inc,__LINUX_IF_ADDR_H,if_addr.h) +CFLAGS_rt-link:=$(call get_hdr_inc,__LINUX_RTNETLINK_H,rtnetlink.h) \ + $(call get_hdr_inc,_LINUX_IF_LINK_H,if_link.h) +CFLAGS_rt-neigh:=$(call get_hdr_inc,__LINUX_RTNETLINK_H,rtnetlink.h) \ + $(call get_hdr_inc,__LINUX_NEIGHBOUR_H,neighbour.h) +CFLAGS_rt-route:=$(call get_hdr_inc,__LINUX_RTNETLINK_H,rtnetlink.h) +CFLAGS_rt-rule:=$(call get_hdr_inc,__LINUX_FIB_RULES_H,fib_rules.h) +CFLAGS_tc:= $(call get_hdr_inc,__LINUX_RTNETLINK_H,rtnetlink.h) \ + $(call get_hdr_inc,__LINUX_PKT_SCHED_H,pkt_sched.h) \ + $(call get_hdr_inc,__LINUX_PKT_CLS_H,pkt_cls.h) \ + $(call get_hdr_inc,_TC_CT_H,tc_act/tc_ct.h) \ + $(call get_hdr_inc,_TC_MIRRED_H,tc_act/tc_mirred.h) \ + $(call get_hdr_inc,_TC_SKBEDIT_H,tc_act/tc_skbedit.h) \ + $(call get_hdr_inc,_TC_TUNNEL_KEY_H,tc_act/tc_tunnel_key.h) +CFLAGS_tcp_metrics:=$(call get_hdr_inc,_LINUX_TCP_METRICS_H,tcp_metrics.h) diff --git a/tools/net/ynl/cli.py b/tools/net/ynl/cli.py deleted file mode 100755 index 564ecf07cd2c..000000000000 --- a/tools/net/ynl/cli.py +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env python3 -# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause - -import argparse -import json -import pprint -import time - -from lib import YnlFamily, Netlink - - -def main(): - parser = argparse.ArgumentParser(description='YNL CLI sample') - parser.add_argument('--spec', dest='spec', type=str, required=True) - parser.add_argument('--schema', dest='schema', type=str) - parser.add_argument('--no-schema', action='store_true') - parser.add_argument('--json', dest='json_text', type=str) - parser.add_argument('--do', dest='do', type=str) - parser.add_argument('--dump', dest='dump', type=str) - parser.add_argument('--sleep', dest='sleep', type=int) - parser.add_argument('--subscribe', dest='ntf', type=str) - parser.add_argument('--replace', dest='flags', action='append_const', - const=Netlink.NLM_F_REPLACE) - parser.add_argument('--excl', dest='flags', action='append_const', - const=Netlink.NLM_F_EXCL) - parser.add_argument('--create', dest='flags', action='append_const', - const=Netlink.NLM_F_CREATE) - parser.add_argument('--append', dest='flags', action='append_const', - const=Netlink.NLM_F_APPEND) - args = parser.parse_args() - - if args.no_schema: - args.schema = '' - - attrs = {} - if args.json_text: - attrs = json.loads(args.json_text) - - ynl = YnlFamily(args.spec, args.schema) - - if args.ntf: - ynl.ntf_subscribe(args.ntf) - - if args.sleep: - time.sleep(args.sleep) - - if args.do: - reply = ynl.do(args.do, attrs, args.flags) - pprint.PrettyPrinter().pprint(reply) - if args.dump: - reply = ynl.dump(args.dump, attrs) - pprint.PrettyPrinter().pprint(reply) - - if args.ntf: - ynl.check_ntf() - pprint.PrettyPrinter().pprint(ynl.async_msg_queue) - - -if __name__ == "__main__": - main() diff --git a/tools/net/ynl/generated/.gitignore b/tools/net/ynl/generated/.gitignore new file mode 100644 index 000000000000..859a6fb446e1 --- /dev/null +++ b/tools/net/ynl/generated/.gitignore @@ -0,0 +1,3 @@ +*-user.c +*-user.h +*.rst diff --git a/tools/net/ynl/generated/Makefile b/tools/net/ynl/generated/Makefile index f8817d2e56e4..86e1e4a959a7 100644 --- a/tools/net/ynl/generated/Makefile +++ b/tools/net/ynl/generated/Makefile @@ -1,50 +1,87 @@ # SPDX-License-Identifier: GPL-2.0 CC=gcc -CFLAGS=-std=gnu11 -O2 -W -Wall -Wextra -Wno-unused-parameter -Wshadow \ +CFLAGS += -std=gnu11 -O2 -W -Wall -Wextra -Wno-unused-parameter -Wshadow \ -I../lib/ -idirafter $(UAPI_PATH) ifeq ("$(DEBUG)","1") CFLAGS += -g -fsanitize=address -fsanitize=leak -static-libasan endif +INSTALL ?= install +prefix ?= /usr +datarootdir ?= $(prefix)/share +docdir ?= $(datarootdir)/doc +includedir ?= $(prefix)/include + include ../Makefile.deps YNL_GEN_ARG_ethtool:=--user-header linux/ethtool_netlink.h \ --exclude-op stats-get -TOOL:=../ynl-gen-c.py +TOOL:=../pyynl/ynl_gen_c.py +TOOL_RST:=../pyynl/ynl_gen_rst.py -GENS:=ethtool devlink handshake fou netdev +SPECS_DIR:=../../../../Documentation/netlink/specs +SPECS_PATHS=$(wildcard $(SPECS_DIR)/*.yaml) +GENS_UNSUP=conntrack nftables +GENS=$(filter-out ${GENS_UNSUP},$(patsubst $(SPECS_DIR)/%.yaml,%,${SPECS_PATHS})) SRCS=$(patsubst %,%-user.c,${GENS}) HDRS=$(patsubst %,%-user.h,${GENS}) OBJS=$(patsubst %,%-user.o,${GENS}) -all: protos.a $(HDRS) $(SRCS) $(KHDRS) $(KSRCS) $(UAPI) regen +SPECS_PATHS=$(wildcard $(SPECS_DIR)/*.yaml) +SPECS=$(patsubst $(SPECS_DIR)/%.yaml,%,${SPECS_PATHS}) +RSTS=$(patsubst %,%.rst,${SPECS}) + +all: protos.a $(HDRS) $(SRCS) $(KHDRS) $(KSRCS) $(UAPI) $(RSTS) protos.a: $(OBJS) @echo -e "\tAR $@" @ar rcs $@ $(OBJS) -%-user.h: ../../../../Documentation/netlink/specs/%.yaml $(TOOL) +%-user.h: $(SPECS_DIR)/%.yaml $(TOOL) @echo -e "\tGEN $@" - @$(TOOL) --mode user --header --spec $< $(YNL_GEN_ARG_$*) > $@ + @$(TOOL) --mode user --header --spec $< -o $@ $(YNL_GEN_ARG_$*) -%-user.c: ../../../../Documentation/netlink/specs/%.yaml $(TOOL) +%-user.c: $(SPECS_DIR)/%.yaml $(TOOL) @echo -e "\tGEN $@" - @$(TOOL) --mode user --source --spec $< $(YNL_GEN_ARG_$*) > $@ + @$(TOOL) --mode user --source --spec $< -o $@ $(YNL_GEN_ARG_$*) %-user.o: %-user.c %-user.h @echo -e "\tCC $@" @$(COMPILE.c) $(CFLAGS_$*) -o $@ $< +%.rst: $(SPECS_DIR)/%.yaml $(TOOL_RST) + @echo -e "\tGEN_RST $@" + @$(TOOL_RST) -o $@ -i $< + clean: rm -f *.o -hardclean: clean - rm -f *.c *.h *.a +distclean: clean + rm -f *.c *.h *.a *.rst regen: @../ynl-regen.sh -.PHONY: all clean hardclean regen +install-headers: $(HDRS) + @echo -e "\tINSTALL generated headers" + @$(INSTALL) -d $(DESTDIR)$(includedir)/ynl + @$(INSTALL) -m 0644 *.h $(DESTDIR)$(includedir)/ynl/ + +install-rsts: $(RSTS) + @echo -e "\tINSTALL generated docs" + @$(INSTALL) -d $(DESTDIR)$(docdir)/ynl + @$(INSTALL) -m 0644 $(RSTS) $(DESTDIR)$(docdir)/ynl/ + +install-specs: + @echo -e "\tINSTALL specs" + @$(INSTALL) -d $(DESTDIR)$(datarootdir)/ynl + @$(INSTALL) -m 0644 ../../../../Documentation/netlink/*.yaml $(DESTDIR)$(datarootdir)/ynl/ + @$(INSTALL) -d $(DESTDIR)$(datarootdir)/ynl/specs + @$(INSTALL) -m 0644 $(SPECS_DIR)/*.yaml $(DESTDIR)$(datarootdir)/ynl/specs/ + +install: install-headers install-rsts install-specs + +.PHONY: all clean distclean regen install install-headers install-rsts install-specs .DEFAULT_GOAL: all diff --git a/tools/net/ynl/generated/devlink-user.c b/tools/net/ynl/generated/devlink-user.c deleted file mode 100644 index 3a8d8499fab6..000000000000 --- a/tools/net/ynl/generated/devlink-user.c +++ /dev/null @@ -1,2982 +0,0 @@ -// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) -/* Do not edit directly, auto-generated from: */ -/* Documentation/netlink/specs/devlink.yaml */ -/* YNL-GEN user source */ - -#include <stdlib.h> -#include <string.h> -#include "devlink-user.h" -#include "ynl.h" -#include <linux/devlink.h> - -#include <libmnl/libmnl.h> -#include <linux/genetlink.h> - -/* Enums */ -static const char * const devlink_op_strmap[] = { - [3] = "get", - [7] = "port-get", - [DEVLINK_CMD_SB_GET] = "sb-get", - [DEVLINK_CMD_SB_POOL_GET] = "sb-pool-get", - [DEVLINK_CMD_SB_PORT_POOL_GET] = "sb-port-pool-get", - [DEVLINK_CMD_SB_TC_POOL_BIND_GET] = "sb-tc-pool-bind-get", - [DEVLINK_CMD_PARAM_GET] = "param-get", - [DEVLINK_CMD_REGION_GET] = "region-get", - [DEVLINK_CMD_INFO_GET] = "info-get", - [DEVLINK_CMD_HEALTH_REPORTER_GET] = "health-reporter-get", - [DEVLINK_CMD_TRAP_GET] = "trap-get", - [DEVLINK_CMD_TRAP_GROUP_GET] = "trap-group-get", - [DEVLINK_CMD_TRAP_POLICER_GET] = "trap-policer-get", - [DEVLINK_CMD_RATE_GET] = "rate-get", - [DEVLINK_CMD_LINECARD_GET] = "linecard-get", - [DEVLINK_CMD_SELFTESTS_GET] = "selftests-get", -}; - -const char *devlink_op_str(int op) -{ - if (op < 0 || op >= (int)MNL_ARRAY_SIZE(devlink_op_strmap)) - return NULL; - return devlink_op_strmap[op]; -} - -static const char * const devlink_sb_pool_type_strmap[] = { - [0] = "ingress", - [1] = "egress", -}; - -const char *devlink_sb_pool_type_str(enum devlink_sb_pool_type value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_sb_pool_type_strmap)) - return NULL; - return devlink_sb_pool_type_strmap[value]; -} - -/* Policies */ -struct ynl_policy_attr devlink_dl_info_version_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_INFO_VERSION_NAME] = { .name = "info-version-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_INFO_VERSION_VALUE] = { .name = "info-version-value", .type = YNL_PT_NUL_STR, }, -}; - -struct ynl_policy_nest devlink_dl_info_version_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_info_version_policy, -}; - -struct ynl_policy_attr devlink_dl_reload_stats_entry_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_RELOAD_STATS_LIMIT] = { .name = "reload-stats-limit", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_RELOAD_STATS_VALUE] = { .name = "reload-stats-value", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest devlink_dl_reload_stats_entry_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_reload_stats_entry_policy, -}; - -struct ynl_policy_attr devlink_dl_reload_act_stats_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_RELOAD_STATS_ENTRY] = { .name = "reload-stats-entry", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_stats_entry_nest, }, -}; - -struct ynl_policy_nest devlink_dl_reload_act_stats_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_reload_act_stats_policy, -}; - -struct ynl_policy_attr devlink_dl_reload_act_info_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_RELOAD_ACTION] = { .name = "reload-action", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_RELOAD_ACTION_STATS] = { .name = "reload-action-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_act_stats_nest, }, -}; - -struct ynl_policy_nest devlink_dl_reload_act_info_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_reload_act_info_policy, -}; - -struct ynl_policy_attr devlink_dl_reload_stats_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_RELOAD_ACTION_INFO] = { .name = "reload-action-info", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_act_info_nest, }, -}; - -struct ynl_policy_nest devlink_dl_reload_stats_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_reload_stats_policy, -}; - -struct ynl_policy_attr devlink_dl_dev_stats_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_RELOAD_STATS] = { .name = "reload-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_stats_nest, }, - [DEVLINK_ATTR_REMOTE_RELOAD_STATS] = { .name = "remote-reload-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_stats_nest, }, -}; - -struct ynl_policy_nest devlink_dl_dev_stats_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_dev_stats_policy, -}; - -struct ynl_policy_attr devlink_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_BUS_NAME] = { .name = "bus-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_DEV_NAME] = { .name = "dev-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_PORT_INDEX] = { .name = "port-index", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_SB_INDEX] = { .name = "sb-index", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_SB_POOL_INDEX] = { .name = "sb-pool-index", .type = YNL_PT_U16, }, - [DEVLINK_ATTR_SB_POOL_TYPE] = { .name = "sb-pool-type", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_SB_TC_INDEX] = { .name = "sb-tc-index", .type = YNL_PT_U16, }, - [DEVLINK_ATTR_PARAM_NAME] = { .name = "param-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_REGION_NAME] = { .name = "region-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_INFO_DRIVER_NAME] = { .name = "info-driver-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_INFO_SERIAL_NUMBER] = { .name = "info-serial-number", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_INFO_VERSION_FIXED] = { .name = "info-version-fixed", .type = YNL_PT_NEST, .nest = &devlink_dl_info_version_nest, }, - [DEVLINK_ATTR_INFO_VERSION_RUNNING] = { .name = "info-version-running", .type = YNL_PT_NEST, .nest = &devlink_dl_info_version_nest, }, - [DEVLINK_ATTR_INFO_VERSION_STORED] = { .name = "info-version-stored", .type = YNL_PT_NEST, .nest = &devlink_dl_info_version_nest, }, - [DEVLINK_ATTR_INFO_VERSION_NAME] = { .name = "info-version-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_INFO_VERSION_VALUE] = { .name = "info-version-value", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_HEALTH_REPORTER_NAME] = { .name = "health-reporter-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_TRAP_NAME] = { .name = "trap-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_TRAP_GROUP_NAME] = { .name = "trap-group-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_RELOAD_FAILED] = { .name = "reload-failed", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_TRAP_POLICER_ID] = { .name = "trap-policer-id", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_RELOAD_ACTION] = { .name = "reload-action", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_DEV_STATS] = { .name = "dev-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_dev_stats_nest, }, - [DEVLINK_ATTR_RELOAD_STATS] = { .name = "reload-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_stats_nest, }, - [DEVLINK_ATTR_RELOAD_STATS_ENTRY] = { .name = "reload-stats-entry", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_stats_entry_nest, }, - [DEVLINK_ATTR_RELOAD_STATS_LIMIT] = { .name = "reload-stats-limit", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_RELOAD_STATS_VALUE] = { .name = "reload-stats-value", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_REMOTE_RELOAD_STATS] = { .name = "remote-reload-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_stats_nest, }, - [DEVLINK_ATTR_RELOAD_ACTION_INFO] = { .name = "reload-action-info", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_act_info_nest, }, - [DEVLINK_ATTR_RELOAD_ACTION_STATS] = { .name = "reload-action-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_act_stats_nest, }, - [DEVLINK_ATTR_RATE_NODE_NAME] = { .name = "rate-node-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_LINECARD_INDEX] = { .name = "linecard-index", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest devlink_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_policy, -}; - -/* Common nested types */ -void devlink_dl_info_version_free(struct devlink_dl_info_version *obj) -{ - free(obj->info_version_name); - free(obj->info_version_value); -} - -int devlink_dl_info_version_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_info_version *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_INFO_VERSION_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.info_version_name_len = len; - dst->info_version_name = malloc(len + 1); - memcpy(dst->info_version_name, mnl_attr_get_str(attr), len); - dst->info_version_name[len] = 0; - } else if (type == DEVLINK_ATTR_INFO_VERSION_VALUE) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.info_version_value_len = len; - dst->info_version_value = malloc(len + 1); - memcpy(dst->info_version_value, mnl_attr_get_str(attr), len); - dst->info_version_value[len] = 0; - } - } - - return 0; -} - -void -devlink_dl_reload_stats_entry_free(struct devlink_dl_reload_stats_entry *obj) -{ -} - -int devlink_dl_reload_stats_entry_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_reload_stats_entry *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_RELOAD_STATS_LIMIT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.reload_stats_limit = 1; - dst->reload_stats_limit = mnl_attr_get_u8(attr); - } else if (type == DEVLINK_ATTR_RELOAD_STATS_VALUE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.reload_stats_value = 1; - dst->reload_stats_value = mnl_attr_get_u32(attr); - } - } - - return 0; -} - -void devlink_dl_reload_act_stats_free(struct devlink_dl_reload_act_stats *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_reload_stats_entry; i++) - devlink_dl_reload_stats_entry_free(&obj->reload_stats_entry[i]); - free(obj->reload_stats_entry); -} - -int devlink_dl_reload_act_stats_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_reload_act_stats *dst = yarg->data; - unsigned int n_reload_stats_entry = 0; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - parg.ys = yarg->ys; - - if (dst->reload_stats_entry) - return ynl_error_parse(yarg, "attribute already present (dl-reload-act-stats.reload-stats-entry)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_RELOAD_STATS_ENTRY) { - n_reload_stats_entry++; - } - } - - if (n_reload_stats_entry) { - dst->reload_stats_entry = calloc(n_reload_stats_entry, sizeof(*dst->reload_stats_entry)); - dst->n_reload_stats_entry = n_reload_stats_entry; - i = 0; - parg.rsp_policy = &devlink_dl_reload_stats_entry_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_STATS_ENTRY) { - parg.data = &dst->reload_stats_entry[i]; - if (devlink_dl_reload_stats_entry_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void devlink_dl_reload_act_info_free(struct devlink_dl_reload_act_info *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_reload_action_stats; i++) - devlink_dl_reload_act_stats_free(&obj->reload_action_stats[i]); - free(obj->reload_action_stats); -} - -int devlink_dl_reload_act_info_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_reload_act_info *dst = yarg->data; - unsigned int n_reload_action_stats = 0; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - parg.ys = yarg->ys; - - if (dst->reload_action_stats) - return ynl_error_parse(yarg, "attribute already present (dl-reload-act-info.reload-action-stats)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_RELOAD_ACTION) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.reload_action = 1; - dst->reload_action = mnl_attr_get_u8(attr); - } else if (type == DEVLINK_ATTR_RELOAD_ACTION_STATS) { - n_reload_action_stats++; - } - } - - if (n_reload_action_stats) { - dst->reload_action_stats = calloc(n_reload_action_stats, sizeof(*dst->reload_action_stats)); - dst->n_reload_action_stats = n_reload_action_stats; - i = 0; - parg.rsp_policy = &devlink_dl_reload_act_stats_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_ACTION_STATS) { - parg.data = &dst->reload_action_stats[i]; - if (devlink_dl_reload_act_stats_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void devlink_dl_reload_stats_free(struct devlink_dl_reload_stats *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_reload_action_info; i++) - devlink_dl_reload_act_info_free(&obj->reload_action_info[i]); - free(obj->reload_action_info); -} - -int devlink_dl_reload_stats_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_reload_stats *dst = yarg->data; - unsigned int n_reload_action_info = 0; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - parg.ys = yarg->ys; - - if (dst->reload_action_info) - return ynl_error_parse(yarg, "attribute already present (dl-reload-stats.reload-action-info)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_RELOAD_ACTION_INFO) { - n_reload_action_info++; - } - } - - if (n_reload_action_info) { - dst->reload_action_info = calloc(n_reload_action_info, sizeof(*dst->reload_action_info)); - dst->n_reload_action_info = n_reload_action_info; - i = 0; - parg.rsp_policy = &devlink_dl_reload_act_info_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_ACTION_INFO) { - parg.data = &dst->reload_action_info[i]; - if (devlink_dl_reload_act_info_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void devlink_dl_dev_stats_free(struct devlink_dl_dev_stats *obj) -{ - devlink_dl_reload_stats_free(&obj->reload_stats); - devlink_dl_reload_stats_free(&obj->remote_reload_stats); -} - -int devlink_dl_dev_stats_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_dev_stats *dst = yarg->data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - parg.ys = yarg->ys; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_RELOAD_STATS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.reload_stats = 1; - - parg.rsp_policy = &devlink_dl_reload_stats_nest; - parg.data = &dst->reload_stats; - if (devlink_dl_reload_stats_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == DEVLINK_ATTR_REMOTE_RELOAD_STATS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.remote_reload_stats = 1; - - parg.rsp_policy = &devlink_dl_reload_stats_nest; - parg.data = &dst->remote_reload_stats; - if (devlink_dl_reload_stats_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return 0; -} - -/* ============== DEVLINK_CMD_GET ============== */ -/* DEVLINK_CMD_GET - do */ -void devlink_get_req_free(struct devlink_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void devlink_get_rsp_free(struct devlink_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - devlink_dl_dev_stats_free(&rsp->dev_stats); - free(rsp); -} - -int devlink_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct devlink_get_rsp *dst; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_RELOAD_FAILED) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.reload_failed = 1; - dst->reload_failed = mnl_attr_get_u8(attr); - } else if (type == DEVLINK_ATTR_RELOAD_ACTION) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.reload_action = 1; - dst->reload_action = mnl_attr_get_u8(attr); - } else if (type == DEVLINK_ATTR_DEV_STATS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dev_stats = 1; - - parg.rsp_policy = &devlink_dl_dev_stats_nest; - parg.data = &dst->dev_stats; - if (devlink_dl_dev_stats_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return MNL_CB_OK; -} - -struct devlink_get_rsp * -devlink_get(struct ynl_sock *ys, struct devlink_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_get_rsp_parse; - yrs.rsp_cmd = 3; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_GET - dump */ -void devlink_get_list_free(struct devlink_get_list *rsp) -{ - struct devlink_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - devlink_dl_dev_stats_free(&rsp->obj.dev_stats); - free(rsp); - } -} - -struct devlink_get_list *devlink_get_dump(struct ynl_sock *ys) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_get_list); - yds.cb = devlink_get_rsp_parse; - yds.rsp_cmd = 3; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_GET, 1); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_PORT_GET ============== */ -/* DEVLINK_CMD_PORT_GET - do */ -void devlink_port_get_req_free(struct devlink_port_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void devlink_port_get_rsp_free(struct devlink_port_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp); -} - -int devlink_port_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct devlink_port_get_rsp *dst; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_PORT_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.port_index = 1; - dst->port_index = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct devlink_port_get_rsp * -devlink_port_get(struct ynl_sock *ys, struct devlink_port_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_port_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_PORT_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_port_get_rsp_parse; - yrs.rsp_cmd = 7; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_port_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_PORT_GET - dump */ -int devlink_port_get_rsp_dump_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_port_get_rsp_dump *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_PORT_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.port_index = 1; - dst->port_index = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -void devlink_port_get_rsp_list_free(struct devlink_port_get_rsp_list *rsp) -{ - struct devlink_port_get_rsp_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp); - } -} - -struct devlink_port_get_rsp_list * -devlink_port_get_dump(struct ynl_sock *ys, - struct devlink_port_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_port_get_rsp_list); - yds.cb = devlink_port_get_rsp_dump_parse; - yds.rsp_cmd = 7; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_PORT_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_port_get_rsp_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_SB_GET ============== */ -/* DEVLINK_CMD_SB_GET - do */ -void devlink_sb_get_req_free(struct devlink_sb_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void devlink_sb_get_rsp_free(struct devlink_sb_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp); -} - -int devlink_sb_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct devlink_sb_get_rsp *dst; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_SB_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.sb_index = 1; - dst->sb_index = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct devlink_sb_get_rsp * -devlink_sb_get(struct ynl_sock *ys, struct devlink_sb_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_sb_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_SB_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.sb_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, req->sb_index); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_sb_get_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_SB_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_sb_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_SB_GET - dump */ -void devlink_sb_get_list_free(struct devlink_sb_get_list *rsp) -{ - struct devlink_sb_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp); - } -} - -struct devlink_sb_get_list * -devlink_sb_get_dump(struct ynl_sock *ys, struct devlink_sb_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_sb_get_list); - yds.cb = devlink_sb_get_rsp_parse; - yds.rsp_cmd = DEVLINK_CMD_SB_GET; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_SB_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_sb_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_SB_POOL_GET ============== */ -/* DEVLINK_CMD_SB_POOL_GET - do */ -void devlink_sb_pool_get_req_free(struct devlink_sb_pool_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void devlink_sb_pool_get_rsp_free(struct devlink_sb_pool_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp); -} - -int devlink_sb_pool_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_sb_pool_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_SB_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.sb_index = 1; - dst->sb_index = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_SB_POOL_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.sb_pool_index = 1; - dst->sb_pool_index = mnl_attr_get_u16(attr); - } - } - - return MNL_CB_OK; -} - -struct devlink_sb_pool_get_rsp * -devlink_sb_pool_get(struct ynl_sock *ys, struct devlink_sb_pool_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_sb_pool_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_SB_POOL_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.sb_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, req->sb_index); - if (req->_present.sb_pool_index) - mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_POOL_INDEX, req->sb_pool_index); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_sb_pool_get_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_SB_POOL_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_sb_pool_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_SB_POOL_GET - dump */ -void devlink_sb_pool_get_list_free(struct devlink_sb_pool_get_list *rsp) -{ - struct devlink_sb_pool_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp); - } -} - -struct devlink_sb_pool_get_list * -devlink_sb_pool_get_dump(struct ynl_sock *ys, - struct devlink_sb_pool_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_sb_pool_get_list); - yds.cb = devlink_sb_pool_get_rsp_parse; - yds.rsp_cmd = DEVLINK_CMD_SB_POOL_GET; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_SB_POOL_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_sb_pool_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_SB_PORT_POOL_GET ============== */ -/* DEVLINK_CMD_SB_PORT_POOL_GET - do */ -void -devlink_sb_port_pool_get_req_free(struct devlink_sb_port_pool_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void -devlink_sb_port_pool_get_rsp_free(struct devlink_sb_port_pool_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp); -} - -int devlink_sb_port_pool_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_sb_port_pool_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_PORT_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.port_index = 1; - dst->port_index = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_SB_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.sb_index = 1; - dst->sb_index = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_SB_POOL_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.sb_pool_index = 1; - dst->sb_pool_index = mnl_attr_get_u16(attr); - } - } - - return MNL_CB_OK; -} - -struct devlink_sb_port_pool_get_rsp * -devlink_sb_port_pool_get(struct ynl_sock *ys, - struct devlink_sb_port_pool_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_sb_port_pool_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_SB_PORT_POOL_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.sb_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, req->sb_index); - if (req->_present.sb_pool_index) - mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_POOL_INDEX, req->sb_pool_index); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_sb_port_pool_get_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_SB_PORT_POOL_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_sb_port_pool_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_SB_PORT_POOL_GET - dump */ -void -devlink_sb_port_pool_get_list_free(struct devlink_sb_port_pool_get_list *rsp) -{ - struct devlink_sb_port_pool_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp); - } -} - -struct devlink_sb_port_pool_get_list * -devlink_sb_port_pool_get_dump(struct ynl_sock *ys, - struct devlink_sb_port_pool_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_sb_port_pool_get_list); - yds.cb = devlink_sb_port_pool_get_rsp_parse; - yds.rsp_cmd = DEVLINK_CMD_SB_PORT_POOL_GET; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_SB_PORT_POOL_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_sb_port_pool_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_SB_TC_POOL_BIND_GET ============== */ -/* DEVLINK_CMD_SB_TC_POOL_BIND_GET - do */ -void -devlink_sb_tc_pool_bind_get_req_free(struct devlink_sb_tc_pool_bind_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void -devlink_sb_tc_pool_bind_get_rsp_free(struct devlink_sb_tc_pool_bind_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp); -} - -int devlink_sb_tc_pool_bind_get_rsp_parse(const struct nlmsghdr *nlh, - void *data) -{ - struct devlink_sb_tc_pool_bind_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_PORT_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.port_index = 1; - dst->port_index = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_SB_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.sb_index = 1; - dst->sb_index = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_SB_POOL_TYPE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.sb_pool_type = 1; - dst->sb_pool_type = mnl_attr_get_u8(attr); - } else if (type == DEVLINK_ATTR_SB_TC_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.sb_tc_index = 1; - dst->sb_tc_index = mnl_attr_get_u16(attr); - } - } - - return MNL_CB_OK; -} - -struct devlink_sb_tc_pool_bind_get_rsp * -devlink_sb_tc_pool_bind_get(struct ynl_sock *ys, - struct devlink_sb_tc_pool_bind_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_sb_tc_pool_bind_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_SB_TC_POOL_BIND_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.sb_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, req->sb_index); - if (req->_present.sb_pool_type) - mnl_attr_put_u8(nlh, DEVLINK_ATTR_SB_POOL_TYPE, req->sb_pool_type); - if (req->_present.sb_tc_index) - mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_TC_INDEX, req->sb_tc_index); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_sb_tc_pool_bind_get_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_SB_TC_POOL_BIND_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_sb_tc_pool_bind_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_SB_TC_POOL_BIND_GET - dump */ -void -devlink_sb_tc_pool_bind_get_list_free(struct devlink_sb_tc_pool_bind_get_list *rsp) -{ - struct devlink_sb_tc_pool_bind_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp); - } -} - -struct devlink_sb_tc_pool_bind_get_list * -devlink_sb_tc_pool_bind_get_dump(struct ynl_sock *ys, - struct devlink_sb_tc_pool_bind_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_sb_tc_pool_bind_get_list); - yds.cb = devlink_sb_tc_pool_bind_get_rsp_parse; - yds.rsp_cmd = DEVLINK_CMD_SB_TC_POOL_BIND_GET; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_SB_TC_POOL_BIND_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_sb_tc_pool_bind_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_PARAM_GET ============== */ -/* DEVLINK_CMD_PARAM_GET - do */ -void devlink_param_get_req_free(struct devlink_param_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->param_name); - free(req); -} - -void devlink_param_get_rsp_free(struct devlink_param_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp->param_name); - free(rsp); -} - -int devlink_param_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_param_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_PARAM_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.param_name_len = len; - dst->param_name = malloc(len + 1); - memcpy(dst->param_name, mnl_attr_get_str(attr), len); - dst->param_name[len] = 0; - } - } - - return MNL_CB_OK; -} - -struct devlink_param_get_rsp * -devlink_param_get(struct ynl_sock *ys, struct devlink_param_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_param_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_PARAM_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.param_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_PARAM_NAME, req->param_name); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_param_get_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_PARAM_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_param_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_PARAM_GET - dump */ -void devlink_param_get_list_free(struct devlink_param_get_list *rsp) -{ - struct devlink_param_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp->obj.param_name); - free(rsp); - } -} - -struct devlink_param_get_list * -devlink_param_get_dump(struct ynl_sock *ys, - struct devlink_param_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_param_get_list); - yds.cb = devlink_param_get_rsp_parse; - yds.rsp_cmd = DEVLINK_CMD_PARAM_GET; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_PARAM_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_param_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_REGION_GET ============== */ -/* DEVLINK_CMD_REGION_GET - do */ -void devlink_region_get_req_free(struct devlink_region_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->region_name); - free(req); -} - -void devlink_region_get_rsp_free(struct devlink_region_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp->region_name); - free(rsp); -} - -int devlink_region_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_region_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_PORT_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.port_index = 1; - dst->port_index = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_REGION_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.region_name_len = len; - dst->region_name = malloc(len + 1); - memcpy(dst->region_name, mnl_attr_get_str(attr), len); - dst->region_name[len] = 0; - } - } - - return MNL_CB_OK; -} - -struct devlink_region_get_rsp * -devlink_region_get(struct ynl_sock *ys, struct devlink_region_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_region_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_REGION_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.region_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_REGION_NAME, req->region_name); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_region_get_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_REGION_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_region_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_REGION_GET - dump */ -void devlink_region_get_list_free(struct devlink_region_get_list *rsp) -{ - struct devlink_region_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp->obj.region_name); - free(rsp); - } -} - -struct devlink_region_get_list * -devlink_region_get_dump(struct ynl_sock *ys, - struct devlink_region_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_region_get_list); - yds.cb = devlink_region_get_rsp_parse; - yds.rsp_cmd = DEVLINK_CMD_REGION_GET; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_REGION_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_region_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_INFO_GET ============== */ -/* DEVLINK_CMD_INFO_GET - do */ -void devlink_info_get_req_free(struct devlink_info_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void devlink_info_get_rsp_free(struct devlink_info_get_rsp *rsp) -{ - unsigned int i; - - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp->info_driver_name); - free(rsp->info_serial_number); - for (i = 0; i < rsp->n_info_version_fixed; i++) - devlink_dl_info_version_free(&rsp->info_version_fixed[i]); - free(rsp->info_version_fixed); - for (i = 0; i < rsp->n_info_version_running; i++) - devlink_dl_info_version_free(&rsp->info_version_running[i]); - free(rsp->info_version_running); - for (i = 0; i < rsp->n_info_version_stored; i++) - devlink_dl_info_version_free(&rsp->info_version_stored[i]); - free(rsp->info_version_stored); - free(rsp); -} - -int devlink_info_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - unsigned int n_info_version_running = 0; - unsigned int n_info_version_stored = 0; - unsigned int n_info_version_fixed = 0; - struct ynl_parse_arg *yarg = data; - struct devlink_info_get_rsp *dst; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - dst = yarg->data; - parg.ys = yarg->ys; - - if (dst->info_version_fixed) - return ynl_error_parse(yarg, "attribute already present (devlink.info-version-fixed)"); - if (dst->info_version_running) - return ynl_error_parse(yarg, "attribute already present (devlink.info-version-running)"); - if (dst->info_version_stored) - return ynl_error_parse(yarg, "attribute already present (devlink.info-version-stored)"); - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_INFO_DRIVER_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.info_driver_name_len = len; - dst->info_driver_name = malloc(len + 1); - memcpy(dst->info_driver_name, mnl_attr_get_str(attr), len); - dst->info_driver_name[len] = 0; - } else if (type == DEVLINK_ATTR_INFO_SERIAL_NUMBER) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.info_serial_number_len = len; - dst->info_serial_number = malloc(len + 1); - memcpy(dst->info_serial_number, mnl_attr_get_str(attr), len); - dst->info_serial_number[len] = 0; - } else if (type == DEVLINK_ATTR_INFO_VERSION_FIXED) { - n_info_version_fixed++; - } else if (type == DEVLINK_ATTR_INFO_VERSION_RUNNING) { - n_info_version_running++; - } else if (type == DEVLINK_ATTR_INFO_VERSION_STORED) { - n_info_version_stored++; - } - } - - if (n_info_version_fixed) { - dst->info_version_fixed = calloc(n_info_version_fixed, sizeof(*dst->info_version_fixed)); - dst->n_info_version_fixed = n_info_version_fixed; - i = 0; - parg.rsp_policy = &devlink_dl_info_version_nest; - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_INFO_VERSION_FIXED) { - parg.data = &dst->info_version_fixed[i]; - if (devlink_dl_info_version_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - if (n_info_version_running) { - dst->info_version_running = calloc(n_info_version_running, sizeof(*dst->info_version_running)); - dst->n_info_version_running = n_info_version_running; - i = 0; - parg.rsp_policy = &devlink_dl_info_version_nest; - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_INFO_VERSION_RUNNING) { - parg.data = &dst->info_version_running[i]; - if (devlink_dl_info_version_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - if (n_info_version_stored) { - dst->info_version_stored = calloc(n_info_version_stored, sizeof(*dst->info_version_stored)); - dst->n_info_version_stored = n_info_version_stored; - i = 0; - parg.rsp_policy = &devlink_dl_info_version_nest; - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_INFO_VERSION_STORED) { - parg.data = &dst->info_version_stored[i]; - if (devlink_dl_info_version_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return MNL_CB_OK; -} - -struct devlink_info_get_rsp * -devlink_info_get(struct ynl_sock *ys, struct devlink_info_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_info_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_INFO_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_info_get_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_INFO_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_info_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_INFO_GET - dump */ -void devlink_info_get_list_free(struct devlink_info_get_list *rsp) -{ - struct devlink_info_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - unsigned int i; - - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp->obj.info_driver_name); - free(rsp->obj.info_serial_number); - for (i = 0; i < rsp->obj.n_info_version_fixed; i++) - devlink_dl_info_version_free(&rsp->obj.info_version_fixed[i]); - free(rsp->obj.info_version_fixed); - for (i = 0; i < rsp->obj.n_info_version_running; i++) - devlink_dl_info_version_free(&rsp->obj.info_version_running[i]); - free(rsp->obj.info_version_running); - for (i = 0; i < rsp->obj.n_info_version_stored; i++) - devlink_dl_info_version_free(&rsp->obj.info_version_stored[i]); - free(rsp->obj.info_version_stored); - free(rsp); - } -} - -struct devlink_info_get_list *devlink_info_get_dump(struct ynl_sock *ys) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_info_get_list); - yds.cb = devlink_info_get_rsp_parse; - yds.rsp_cmd = DEVLINK_CMD_INFO_GET; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_INFO_GET, 1); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_info_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_HEALTH_REPORTER_GET ============== */ -/* DEVLINK_CMD_HEALTH_REPORTER_GET - do */ -void -devlink_health_reporter_get_req_free(struct devlink_health_reporter_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->health_reporter_name); - free(req); -} - -void -devlink_health_reporter_get_rsp_free(struct devlink_health_reporter_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp->health_reporter_name); - free(rsp); -} - -int devlink_health_reporter_get_rsp_parse(const struct nlmsghdr *nlh, - void *data) -{ - struct devlink_health_reporter_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_PORT_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.port_index = 1; - dst->port_index = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_HEALTH_REPORTER_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.health_reporter_name_len = len; - dst->health_reporter_name = malloc(len + 1); - memcpy(dst->health_reporter_name, mnl_attr_get_str(attr), len); - dst->health_reporter_name[len] = 0; - } - } - - return MNL_CB_OK; -} - -struct devlink_health_reporter_get_rsp * -devlink_health_reporter_get(struct ynl_sock *ys, - struct devlink_health_reporter_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_health_reporter_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_HEALTH_REPORTER_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.health_reporter_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_HEALTH_REPORTER_NAME, req->health_reporter_name); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_health_reporter_get_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_HEALTH_REPORTER_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_health_reporter_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_HEALTH_REPORTER_GET - dump */ -void -devlink_health_reporter_get_list_free(struct devlink_health_reporter_get_list *rsp) -{ - struct devlink_health_reporter_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp->obj.health_reporter_name); - free(rsp); - } -} - -struct devlink_health_reporter_get_list * -devlink_health_reporter_get_dump(struct ynl_sock *ys, - struct devlink_health_reporter_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_health_reporter_get_list); - yds.cb = devlink_health_reporter_get_rsp_parse; - yds.rsp_cmd = DEVLINK_CMD_HEALTH_REPORTER_GET; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_HEALTH_REPORTER_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_health_reporter_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_TRAP_GET ============== */ -/* DEVLINK_CMD_TRAP_GET - do */ -void devlink_trap_get_req_free(struct devlink_trap_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->trap_name); - free(req); -} - -void devlink_trap_get_rsp_free(struct devlink_trap_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp->trap_name); - free(rsp); -} - -int devlink_trap_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct devlink_trap_get_rsp *dst; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_TRAP_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.trap_name_len = len; - dst->trap_name = malloc(len + 1); - memcpy(dst->trap_name, mnl_attr_get_str(attr), len); - dst->trap_name[len] = 0; - } - } - - return MNL_CB_OK; -} - -struct devlink_trap_get_rsp * -devlink_trap_get(struct ynl_sock *ys, struct devlink_trap_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_trap_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_TRAP_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.trap_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_TRAP_NAME, req->trap_name); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_trap_get_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_TRAP_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_trap_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_TRAP_GET - dump */ -void devlink_trap_get_list_free(struct devlink_trap_get_list *rsp) -{ - struct devlink_trap_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp->obj.trap_name); - free(rsp); - } -} - -struct devlink_trap_get_list * -devlink_trap_get_dump(struct ynl_sock *ys, - struct devlink_trap_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_trap_get_list); - yds.cb = devlink_trap_get_rsp_parse; - yds.rsp_cmd = DEVLINK_CMD_TRAP_GET; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_TRAP_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_trap_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_TRAP_GROUP_GET ============== */ -/* DEVLINK_CMD_TRAP_GROUP_GET - do */ -void devlink_trap_group_get_req_free(struct devlink_trap_group_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->trap_group_name); - free(req); -} - -void devlink_trap_group_get_rsp_free(struct devlink_trap_group_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp->trap_group_name); - free(rsp); -} - -int devlink_trap_group_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_trap_group_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_TRAP_GROUP_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.trap_group_name_len = len; - dst->trap_group_name = malloc(len + 1); - memcpy(dst->trap_group_name, mnl_attr_get_str(attr), len); - dst->trap_group_name[len] = 0; - } - } - - return MNL_CB_OK; -} - -struct devlink_trap_group_get_rsp * -devlink_trap_group_get(struct ynl_sock *ys, - struct devlink_trap_group_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_trap_group_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_TRAP_GROUP_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.trap_group_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_TRAP_GROUP_NAME, req->trap_group_name); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_trap_group_get_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_TRAP_GROUP_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_trap_group_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_TRAP_GROUP_GET - dump */ -void devlink_trap_group_get_list_free(struct devlink_trap_group_get_list *rsp) -{ - struct devlink_trap_group_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp->obj.trap_group_name); - free(rsp); - } -} - -struct devlink_trap_group_get_list * -devlink_trap_group_get_dump(struct ynl_sock *ys, - struct devlink_trap_group_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_trap_group_get_list); - yds.cb = devlink_trap_group_get_rsp_parse; - yds.rsp_cmd = DEVLINK_CMD_TRAP_GROUP_GET; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_TRAP_GROUP_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_trap_group_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_TRAP_POLICER_GET ============== */ -/* DEVLINK_CMD_TRAP_POLICER_GET - do */ -void -devlink_trap_policer_get_req_free(struct devlink_trap_policer_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void -devlink_trap_policer_get_rsp_free(struct devlink_trap_policer_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp); -} - -int devlink_trap_policer_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_trap_policer_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_TRAP_POLICER_ID) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.trap_policer_id = 1; - dst->trap_policer_id = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct devlink_trap_policer_get_rsp * -devlink_trap_policer_get(struct ynl_sock *ys, - struct devlink_trap_policer_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_trap_policer_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_TRAP_POLICER_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.trap_policer_id) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_TRAP_POLICER_ID, req->trap_policer_id); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_trap_policer_get_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_TRAP_POLICER_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_trap_policer_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_TRAP_POLICER_GET - dump */ -void -devlink_trap_policer_get_list_free(struct devlink_trap_policer_get_list *rsp) -{ - struct devlink_trap_policer_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp); - } -} - -struct devlink_trap_policer_get_list * -devlink_trap_policer_get_dump(struct ynl_sock *ys, - struct devlink_trap_policer_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_trap_policer_get_list); - yds.cb = devlink_trap_policer_get_rsp_parse; - yds.rsp_cmd = DEVLINK_CMD_TRAP_POLICER_GET; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_TRAP_POLICER_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_trap_policer_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_RATE_GET ============== */ -/* DEVLINK_CMD_RATE_GET - do */ -void devlink_rate_get_req_free(struct devlink_rate_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->rate_node_name); - free(req); -} - -void devlink_rate_get_rsp_free(struct devlink_rate_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp->rate_node_name); - free(rsp); -} - -int devlink_rate_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct devlink_rate_get_rsp *dst; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_PORT_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.port_index = 1; - dst->port_index = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_RATE_NODE_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.rate_node_name_len = len; - dst->rate_node_name = malloc(len + 1); - memcpy(dst->rate_node_name, mnl_attr_get_str(attr), len); - dst->rate_node_name[len] = 0; - } - } - - return MNL_CB_OK; -} - -struct devlink_rate_get_rsp * -devlink_rate_get(struct ynl_sock *ys, struct devlink_rate_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_rate_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_RATE_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.rate_node_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_RATE_NODE_NAME, req->rate_node_name); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_rate_get_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_RATE_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_rate_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_RATE_GET - dump */ -void devlink_rate_get_list_free(struct devlink_rate_get_list *rsp) -{ - struct devlink_rate_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp->obj.rate_node_name); - free(rsp); - } -} - -struct devlink_rate_get_list * -devlink_rate_get_dump(struct ynl_sock *ys, - struct devlink_rate_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_rate_get_list); - yds.cb = devlink_rate_get_rsp_parse; - yds.rsp_cmd = DEVLINK_CMD_RATE_GET; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_RATE_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_rate_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_LINECARD_GET ============== */ -/* DEVLINK_CMD_LINECARD_GET - do */ -void devlink_linecard_get_req_free(struct devlink_linecard_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void devlink_linecard_get_rsp_free(struct devlink_linecard_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp); -} - -int devlink_linecard_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_linecard_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_LINECARD_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.linecard_index = 1; - dst->linecard_index = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct devlink_linecard_get_rsp * -devlink_linecard_get(struct ynl_sock *ys, struct devlink_linecard_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_linecard_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_LINECARD_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.linecard_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_LINECARD_INDEX, req->linecard_index); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_linecard_get_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_LINECARD_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_linecard_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_LINECARD_GET - dump */ -void devlink_linecard_get_list_free(struct devlink_linecard_get_list *rsp) -{ - struct devlink_linecard_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp); - } -} - -struct devlink_linecard_get_list * -devlink_linecard_get_dump(struct ynl_sock *ys, - struct devlink_linecard_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_linecard_get_list); - yds.cb = devlink_linecard_get_rsp_parse; - yds.rsp_cmd = DEVLINK_CMD_LINECARD_GET; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_LINECARD_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_linecard_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_SELFTESTS_GET ============== */ -/* DEVLINK_CMD_SELFTESTS_GET - do */ -void devlink_selftests_get_req_free(struct devlink_selftests_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void devlink_selftests_get_rsp_free(struct devlink_selftests_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp); -} - -int devlink_selftests_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_selftests_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } - } - - return MNL_CB_OK; -} - -struct devlink_selftests_get_rsp * -devlink_selftests_get(struct ynl_sock *ys, - struct devlink_selftests_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_selftests_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_SELFTESTS_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_selftests_get_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_SELFTESTS_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_selftests_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_SELFTESTS_GET - dump */ -void devlink_selftests_get_list_free(struct devlink_selftests_get_list *rsp) -{ - struct devlink_selftests_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp); - } -} - -struct devlink_selftests_get_list * -devlink_selftests_get_dump(struct ynl_sock *ys) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_selftests_get_list); - yds.cb = devlink_selftests_get_rsp_parse; - yds.rsp_cmd = DEVLINK_CMD_SELFTESTS_GET; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_SELFTESTS_GET, 1); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_selftests_get_list_free(yds.first); - return NULL; -} - -const struct ynl_family ynl_devlink_family = { - .name = "devlink", -}; diff --git a/tools/net/ynl/generated/devlink-user.h b/tools/net/ynl/generated/devlink-user.h deleted file mode 100644 index 4b686d147613..000000000000 --- a/tools/net/ynl/generated/devlink-user.h +++ /dev/null @@ -1,1992 +0,0 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ -/* Do not edit directly, auto-generated from: */ -/* Documentation/netlink/specs/devlink.yaml */ -/* YNL-GEN user header */ - -#ifndef _LINUX_DEVLINK_GEN_H -#define _LINUX_DEVLINK_GEN_H - -#include <stdlib.h> -#include <string.h> -#include <linux/types.h> -#include <linux/devlink.h> - -struct ynl_sock; - -extern const struct ynl_family ynl_devlink_family; - -/* Enums */ -const char *devlink_op_str(int op); -const char *devlink_sb_pool_type_str(enum devlink_sb_pool_type value); - -/* Common nested types */ -struct devlink_dl_info_version { - struct { - __u32 info_version_name_len; - __u32 info_version_value_len; - } _present; - - char *info_version_name; - char *info_version_value; -}; - -struct devlink_dl_reload_stats_entry { - struct { - __u32 reload_stats_limit:1; - __u32 reload_stats_value:1; - } _present; - - __u8 reload_stats_limit; - __u32 reload_stats_value; -}; - -struct devlink_dl_reload_act_stats { - unsigned int n_reload_stats_entry; - struct devlink_dl_reload_stats_entry *reload_stats_entry; -}; - -struct devlink_dl_reload_act_info { - struct { - __u32 reload_action:1; - } _present; - - __u8 reload_action; - unsigned int n_reload_action_stats; - struct devlink_dl_reload_act_stats *reload_action_stats; -}; - -struct devlink_dl_reload_stats { - unsigned int n_reload_action_info; - struct devlink_dl_reload_act_info *reload_action_info; -}; - -struct devlink_dl_dev_stats { - struct { - __u32 reload_stats:1; - __u32 remote_reload_stats:1; - } _present; - - struct devlink_dl_reload_stats reload_stats; - struct devlink_dl_reload_stats remote_reload_stats; -}; - -/* ============== DEVLINK_CMD_GET ============== */ -/* DEVLINK_CMD_GET - do */ -struct devlink_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_get_req *devlink_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_get_req)); -} -void devlink_get_req_free(struct devlink_get_req *req); - -static inline void -devlink_get_req_set_bus_name(struct devlink_get_req *req, const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_get_req_set_dev_name(struct devlink_get_req *req, const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 reload_failed:1; - __u32 reload_action:1; - __u32 dev_stats:1; - } _present; - - char *bus_name; - char *dev_name; - __u8 reload_failed; - __u8 reload_action; - struct devlink_dl_dev_stats dev_stats; -}; - -void devlink_get_rsp_free(struct devlink_get_rsp *rsp); - -/* - * Get devlink instances. - */ -struct devlink_get_rsp * -devlink_get(struct ynl_sock *ys, struct devlink_get_req *req); - -/* DEVLINK_CMD_GET - dump */ -struct devlink_get_list { - struct devlink_get_list *next; - struct devlink_get_rsp obj __attribute__ ((aligned (8))); -}; - -void devlink_get_list_free(struct devlink_get_list *rsp); - -struct devlink_get_list *devlink_get_dump(struct ynl_sock *ys); - -/* ============== DEVLINK_CMD_PORT_GET ============== */ -/* DEVLINK_CMD_PORT_GET - do */ -struct devlink_port_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; -}; - -static inline struct devlink_port_get_req *devlink_port_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_port_get_req)); -} -void devlink_port_get_req_free(struct devlink_port_get_req *req); - -static inline void -devlink_port_get_req_set_bus_name(struct devlink_port_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_port_get_req_set_dev_name(struct devlink_port_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_port_get_req_set_port_index(struct devlink_port_get_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} - -struct devlink_port_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; -}; - -void devlink_port_get_rsp_free(struct devlink_port_get_rsp *rsp); - -/* - * Get devlink port instances. - */ -struct devlink_port_get_rsp * -devlink_port_get(struct ynl_sock *ys, struct devlink_port_get_req *req); - -/* DEVLINK_CMD_PORT_GET - dump */ -struct devlink_port_get_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_port_get_req_dump * -devlink_port_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_port_get_req_dump)); -} -void devlink_port_get_req_dump_free(struct devlink_port_get_req_dump *req); - -static inline void -devlink_port_get_req_dump_set_bus_name(struct devlink_port_get_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_port_get_req_dump_set_dev_name(struct devlink_port_get_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_port_get_rsp_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; -}; - -struct devlink_port_get_rsp_list { - struct devlink_port_get_rsp_list *next; - struct devlink_port_get_rsp_dump obj __attribute__ ((aligned (8))); -}; - -void devlink_port_get_rsp_list_free(struct devlink_port_get_rsp_list *rsp); - -struct devlink_port_get_rsp_list * -devlink_port_get_dump(struct ynl_sock *ys, - struct devlink_port_get_req_dump *req); - -/* ============== DEVLINK_CMD_SB_GET ============== */ -/* DEVLINK_CMD_SB_GET - do */ -struct devlink_sb_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 sb_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 sb_index; -}; - -static inline struct devlink_sb_get_req *devlink_sb_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_sb_get_req)); -} -void devlink_sb_get_req_free(struct devlink_sb_get_req *req); - -static inline void -devlink_sb_get_req_set_bus_name(struct devlink_sb_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_sb_get_req_set_dev_name(struct devlink_sb_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_sb_get_req_set_sb_index(struct devlink_sb_get_req *req, __u32 sb_index) -{ - req->_present.sb_index = 1; - req->sb_index = sb_index; -} - -struct devlink_sb_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 sb_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 sb_index; -}; - -void devlink_sb_get_rsp_free(struct devlink_sb_get_rsp *rsp); - -/* - * Get shared buffer instances. - */ -struct devlink_sb_get_rsp * -devlink_sb_get(struct ynl_sock *ys, struct devlink_sb_get_req *req); - -/* DEVLINK_CMD_SB_GET - dump */ -struct devlink_sb_get_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_sb_get_req_dump * -devlink_sb_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_sb_get_req_dump)); -} -void devlink_sb_get_req_dump_free(struct devlink_sb_get_req_dump *req); - -static inline void -devlink_sb_get_req_dump_set_bus_name(struct devlink_sb_get_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_sb_get_req_dump_set_dev_name(struct devlink_sb_get_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_sb_get_list { - struct devlink_sb_get_list *next; - struct devlink_sb_get_rsp obj __attribute__ ((aligned (8))); -}; - -void devlink_sb_get_list_free(struct devlink_sb_get_list *rsp); - -struct devlink_sb_get_list * -devlink_sb_get_dump(struct ynl_sock *ys, struct devlink_sb_get_req_dump *req); - -/* ============== DEVLINK_CMD_SB_POOL_GET ============== */ -/* DEVLINK_CMD_SB_POOL_GET - do */ -struct devlink_sb_pool_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 sb_index:1; - __u32 sb_pool_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 sb_index; - __u16 sb_pool_index; -}; - -static inline struct devlink_sb_pool_get_req * -devlink_sb_pool_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_sb_pool_get_req)); -} -void devlink_sb_pool_get_req_free(struct devlink_sb_pool_get_req *req); - -static inline void -devlink_sb_pool_get_req_set_bus_name(struct devlink_sb_pool_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_sb_pool_get_req_set_dev_name(struct devlink_sb_pool_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_sb_pool_get_req_set_sb_index(struct devlink_sb_pool_get_req *req, - __u32 sb_index) -{ - req->_present.sb_index = 1; - req->sb_index = sb_index; -} -static inline void -devlink_sb_pool_get_req_set_sb_pool_index(struct devlink_sb_pool_get_req *req, - __u16 sb_pool_index) -{ - req->_present.sb_pool_index = 1; - req->sb_pool_index = sb_pool_index; -} - -struct devlink_sb_pool_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 sb_index:1; - __u32 sb_pool_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 sb_index; - __u16 sb_pool_index; -}; - -void devlink_sb_pool_get_rsp_free(struct devlink_sb_pool_get_rsp *rsp); - -/* - * Get shared buffer pool instances. - */ -struct devlink_sb_pool_get_rsp * -devlink_sb_pool_get(struct ynl_sock *ys, struct devlink_sb_pool_get_req *req); - -/* DEVLINK_CMD_SB_POOL_GET - dump */ -struct devlink_sb_pool_get_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_sb_pool_get_req_dump * -devlink_sb_pool_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_sb_pool_get_req_dump)); -} -void -devlink_sb_pool_get_req_dump_free(struct devlink_sb_pool_get_req_dump *req); - -static inline void -devlink_sb_pool_get_req_dump_set_bus_name(struct devlink_sb_pool_get_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_sb_pool_get_req_dump_set_dev_name(struct devlink_sb_pool_get_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_sb_pool_get_list { - struct devlink_sb_pool_get_list *next; - struct devlink_sb_pool_get_rsp obj __attribute__ ((aligned (8))); -}; - -void devlink_sb_pool_get_list_free(struct devlink_sb_pool_get_list *rsp); - -struct devlink_sb_pool_get_list * -devlink_sb_pool_get_dump(struct ynl_sock *ys, - struct devlink_sb_pool_get_req_dump *req); - -/* ============== DEVLINK_CMD_SB_PORT_POOL_GET ============== */ -/* DEVLINK_CMD_SB_PORT_POOL_GET - do */ -struct devlink_sb_port_pool_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 sb_index:1; - __u32 sb_pool_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - __u32 sb_index; - __u16 sb_pool_index; -}; - -static inline struct devlink_sb_port_pool_get_req * -devlink_sb_port_pool_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_sb_port_pool_get_req)); -} -void -devlink_sb_port_pool_get_req_free(struct devlink_sb_port_pool_get_req *req); - -static inline void -devlink_sb_port_pool_get_req_set_bus_name(struct devlink_sb_port_pool_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_sb_port_pool_get_req_set_dev_name(struct devlink_sb_port_pool_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_sb_port_pool_get_req_set_port_index(struct devlink_sb_port_pool_get_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_sb_port_pool_get_req_set_sb_index(struct devlink_sb_port_pool_get_req *req, - __u32 sb_index) -{ - req->_present.sb_index = 1; - req->sb_index = sb_index; -} -static inline void -devlink_sb_port_pool_get_req_set_sb_pool_index(struct devlink_sb_port_pool_get_req *req, - __u16 sb_pool_index) -{ - req->_present.sb_pool_index = 1; - req->sb_pool_index = sb_pool_index; -} - -struct devlink_sb_port_pool_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 sb_index:1; - __u32 sb_pool_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - __u32 sb_index; - __u16 sb_pool_index; -}; - -void -devlink_sb_port_pool_get_rsp_free(struct devlink_sb_port_pool_get_rsp *rsp); - -/* - * Get shared buffer port-pool combinations and threshold. - */ -struct devlink_sb_port_pool_get_rsp * -devlink_sb_port_pool_get(struct ynl_sock *ys, - struct devlink_sb_port_pool_get_req *req); - -/* DEVLINK_CMD_SB_PORT_POOL_GET - dump */ -struct devlink_sb_port_pool_get_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_sb_port_pool_get_req_dump * -devlink_sb_port_pool_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_sb_port_pool_get_req_dump)); -} -void -devlink_sb_port_pool_get_req_dump_free(struct devlink_sb_port_pool_get_req_dump *req); - -static inline void -devlink_sb_port_pool_get_req_dump_set_bus_name(struct devlink_sb_port_pool_get_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_sb_port_pool_get_req_dump_set_dev_name(struct devlink_sb_port_pool_get_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_sb_port_pool_get_list { - struct devlink_sb_port_pool_get_list *next; - struct devlink_sb_port_pool_get_rsp obj __attribute__ ((aligned (8))); -}; - -void -devlink_sb_port_pool_get_list_free(struct devlink_sb_port_pool_get_list *rsp); - -struct devlink_sb_port_pool_get_list * -devlink_sb_port_pool_get_dump(struct ynl_sock *ys, - struct devlink_sb_port_pool_get_req_dump *req); - -/* ============== DEVLINK_CMD_SB_TC_POOL_BIND_GET ============== */ -/* DEVLINK_CMD_SB_TC_POOL_BIND_GET - do */ -struct devlink_sb_tc_pool_bind_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 sb_index:1; - __u32 sb_pool_type:1; - __u32 sb_tc_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - __u32 sb_index; - enum devlink_sb_pool_type sb_pool_type; - __u16 sb_tc_index; -}; - -static inline struct devlink_sb_tc_pool_bind_get_req * -devlink_sb_tc_pool_bind_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_sb_tc_pool_bind_get_req)); -} -void -devlink_sb_tc_pool_bind_get_req_free(struct devlink_sb_tc_pool_bind_get_req *req); - -static inline void -devlink_sb_tc_pool_bind_get_req_set_bus_name(struct devlink_sb_tc_pool_bind_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_sb_tc_pool_bind_get_req_set_dev_name(struct devlink_sb_tc_pool_bind_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_sb_tc_pool_bind_get_req_set_port_index(struct devlink_sb_tc_pool_bind_get_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_sb_tc_pool_bind_get_req_set_sb_index(struct devlink_sb_tc_pool_bind_get_req *req, - __u32 sb_index) -{ - req->_present.sb_index = 1; - req->sb_index = sb_index; -} -static inline void -devlink_sb_tc_pool_bind_get_req_set_sb_pool_type(struct devlink_sb_tc_pool_bind_get_req *req, - enum devlink_sb_pool_type sb_pool_type) -{ - req->_present.sb_pool_type = 1; - req->sb_pool_type = sb_pool_type; -} -static inline void -devlink_sb_tc_pool_bind_get_req_set_sb_tc_index(struct devlink_sb_tc_pool_bind_get_req *req, - __u16 sb_tc_index) -{ - req->_present.sb_tc_index = 1; - req->sb_tc_index = sb_tc_index; -} - -struct devlink_sb_tc_pool_bind_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 sb_index:1; - __u32 sb_pool_type:1; - __u32 sb_tc_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - __u32 sb_index; - enum devlink_sb_pool_type sb_pool_type; - __u16 sb_tc_index; -}; - -void -devlink_sb_tc_pool_bind_get_rsp_free(struct devlink_sb_tc_pool_bind_get_rsp *rsp); - -/* - * Get shared buffer port-TC to pool bindings and threshold. - */ -struct devlink_sb_tc_pool_bind_get_rsp * -devlink_sb_tc_pool_bind_get(struct ynl_sock *ys, - struct devlink_sb_tc_pool_bind_get_req *req); - -/* DEVLINK_CMD_SB_TC_POOL_BIND_GET - dump */ -struct devlink_sb_tc_pool_bind_get_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_sb_tc_pool_bind_get_req_dump * -devlink_sb_tc_pool_bind_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_sb_tc_pool_bind_get_req_dump)); -} -void -devlink_sb_tc_pool_bind_get_req_dump_free(struct devlink_sb_tc_pool_bind_get_req_dump *req); - -static inline void -devlink_sb_tc_pool_bind_get_req_dump_set_bus_name(struct devlink_sb_tc_pool_bind_get_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_sb_tc_pool_bind_get_req_dump_set_dev_name(struct devlink_sb_tc_pool_bind_get_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_sb_tc_pool_bind_get_list { - struct devlink_sb_tc_pool_bind_get_list *next; - struct devlink_sb_tc_pool_bind_get_rsp obj __attribute__ ((aligned (8))); -}; - -void -devlink_sb_tc_pool_bind_get_list_free(struct devlink_sb_tc_pool_bind_get_list *rsp); - -struct devlink_sb_tc_pool_bind_get_list * -devlink_sb_tc_pool_bind_get_dump(struct ynl_sock *ys, - struct devlink_sb_tc_pool_bind_get_req_dump *req); - -/* ============== DEVLINK_CMD_PARAM_GET ============== */ -/* DEVLINK_CMD_PARAM_GET - do */ -struct devlink_param_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 param_name_len; - } _present; - - char *bus_name; - char *dev_name; - char *param_name; -}; - -static inline struct devlink_param_get_req *devlink_param_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_param_get_req)); -} -void devlink_param_get_req_free(struct devlink_param_get_req *req); - -static inline void -devlink_param_get_req_set_bus_name(struct devlink_param_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_param_get_req_set_dev_name(struct devlink_param_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_param_get_req_set_param_name(struct devlink_param_get_req *req, - const char *param_name) -{ - free(req->param_name); - req->_present.param_name_len = strlen(param_name); - req->param_name = malloc(req->_present.param_name_len + 1); - memcpy(req->param_name, param_name, req->_present.param_name_len); - req->param_name[req->_present.param_name_len] = 0; -} - -struct devlink_param_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 param_name_len; - } _present; - - char *bus_name; - char *dev_name; - char *param_name; -}; - -void devlink_param_get_rsp_free(struct devlink_param_get_rsp *rsp); - -/* - * Get param instances. - */ -struct devlink_param_get_rsp * -devlink_param_get(struct ynl_sock *ys, struct devlink_param_get_req *req); - -/* DEVLINK_CMD_PARAM_GET - dump */ -struct devlink_param_get_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_param_get_req_dump * -devlink_param_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_param_get_req_dump)); -} -void devlink_param_get_req_dump_free(struct devlink_param_get_req_dump *req); - -static inline void -devlink_param_get_req_dump_set_bus_name(struct devlink_param_get_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_param_get_req_dump_set_dev_name(struct devlink_param_get_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_param_get_list { - struct devlink_param_get_list *next; - struct devlink_param_get_rsp obj __attribute__ ((aligned (8))); -}; - -void devlink_param_get_list_free(struct devlink_param_get_list *rsp); - -struct devlink_param_get_list * -devlink_param_get_dump(struct ynl_sock *ys, - struct devlink_param_get_req_dump *req); - -/* ============== DEVLINK_CMD_REGION_GET ============== */ -/* DEVLINK_CMD_REGION_GET - do */ -struct devlink_region_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 region_name_len; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - char *region_name; -}; - -static inline struct devlink_region_get_req *devlink_region_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_region_get_req)); -} -void devlink_region_get_req_free(struct devlink_region_get_req *req); - -static inline void -devlink_region_get_req_set_bus_name(struct devlink_region_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_region_get_req_set_dev_name(struct devlink_region_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_region_get_req_set_port_index(struct devlink_region_get_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_region_get_req_set_region_name(struct devlink_region_get_req *req, - const char *region_name) -{ - free(req->region_name); - req->_present.region_name_len = strlen(region_name); - req->region_name = malloc(req->_present.region_name_len + 1); - memcpy(req->region_name, region_name, req->_present.region_name_len); - req->region_name[req->_present.region_name_len] = 0; -} - -struct devlink_region_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 region_name_len; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - char *region_name; -}; - -void devlink_region_get_rsp_free(struct devlink_region_get_rsp *rsp); - -/* - * Get region instances. - */ -struct devlink_region_get_rsp * -devlink_region_get(struct ynl_sock *ys, struct devlink_region_get_req *req); - -/* DEVLINK_CMD_REGION_GET - dump */ -struct devlink_region_get_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_region_get_req_dump * -devlink_region_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_region_get_req_dump)); -} -void devlink_region_get_req_dump_free(struct devlink_region_get_req_dump *req); - -static inline void -devlink_region_get_req_dump_set_bus_name(struct devlink_region_get_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_region_get_req_dump_set_dev_name(struct devlink_region_get_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_region_get_list { - struct devlink_region_get_list *next; - struct devlink_region_get_rsp obj __attribute__ ((aligned (8))); -}; - -void devlink_region_get_list_free(struct devlink_region_get_list *rsp); - -struct devlink_region_get_list * -devlink_region_get_dump(struct ynl_sock *ys, - struct devlink_region_get_req_dump *req); - -/* ============== DEVLINK_CMD_INFO_GET ============== */ -/* DEVLINK_CMD_INFO_GET - do */ -struct devlink_info_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_info_get_req *devlink_info_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_info_get_req)); -} -void devlink_info_get_req_free(struct devlink_info_get_req *req); - -static inline void -devlink_info_get_req_set_bus_name(struct devlink_info_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_info_get_req_set_dev_name(struct devlink_info_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_info_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 info_driver_name_len; - __u32 info_serial_number_len; - } _present; - - char *bus_name; - char *dev_name; - char *info_driver_name; - char *info_serial_number; - unsigned int n_info_version_fixed; - struct devlink_dl_info_version *info_version_fixed; - unsigned int n_info_version_running; - struct devlink_dl_info_version *info_version_running; - unsigned int n_info_version_stored; - struct devlink_dl_info_version *info_version_stored; -}; - -void devlink_info_get_rsp_free(struct devlink_info_get_rsp *rsp); - -/* - * Get device information, like driver name, hardware and firmware versions etc. - */ -struct devlink_info_get_rsp * -devlink_info_get(struct ynl_sock *ys, struct devlink_info_get_req *req); - -/* DEVLINK_CMD_INFO_GET - dump */ -struct devlink_info_get_list { - struct devlink_info_get_list *next; - struct devlink_info_get_rsp obj __attribute__ ((aligned (8))); -}; - -void devlink_info_get_list_free(struct devlink_info_get_list *rsp); - -struct devlink_info_get_list *devlink_info_get_dump(struct ynl_sock *ys); - -/* ============== DEVLINK_CMD_HEALTH_REPORTER_GET ============== */ -/* DEVLINK_CMD_HEALTH_REPORTER_GET - do */ -struct devlink_health_reporter_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 health_reporter_name_len; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - char *health_reporter_name; -}; - -static inline struct devlink_health_reporter_get_req * -devlink_health_reporter_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_health_reporter_get_req)); -} -void -devlink_health_reporter_get_req_free(struct devlink_health_reporter_get_req *req); - -static inline void -devlink_health_reporter_get_req_set_bus_name(struct devlink_health_reporter_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_health_reporter_get_req_set_dev_name(struct devlink_health_reporter_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_health_reporter_get_req_set_port_index(struct devlink_health_reporter_get_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_health_reporter_get_req_set_health_reporter_name(struct devlink_health_reporter_get_req *req, - const char *health_reporter_name) -{ - free(req->health_reporter_name); - req->_present.health_reporter_name_len = strlen(health_reporter_name); - req->health_reporter_name = malloc(req->_present.health_reporter_name_len + 1); - memcpy(req->health_reporter_name, health_reporter_name, req->_present.health_reporter_name_len); - req->health_reporter_name[req->_present.health_reporter_name_len] = 0; -} - -struct devlink_health_reporter_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 health_reporter_name_len; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - char *health_reporter_name; -}; - -void -devlink_health_reporter_get_rsp_free(struct devlink_health_reporter_get_rsp *rsp); - -/* - * Get health reporter instances. - */ -struct devlink_health_reporter_get_rsp * -devlink_health_reporter_get(struct ynl_sock *ys, - struct devlink_health_reporter_get_req *req); - -/* DEVLINK_CMD_HEALTH_REPORTER_GET - dump */ -struct devlink_health_reporter_get_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; -}; - -static inline struct devlink_health_reporter_get_req_dump * -devlink_health_reporter_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_health_reporter_get_req_dump)); -} -void -devlink_health_reporter_get_req_dump_free(struct devlink_health_reporter_get_req_dump *req); - -static inline void -devlink_health_reporter_get_req_dump_set_bus_name(struct devlink_health_reporter_get_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_health_reporter_get_req_dump_set_dev_name(struct devlink_health_reporter_get_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_health_reporter_get_req_dump_set_port_index(struct devlink_health_reporter_get_req_dump *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} - -struct devlink_health_reporter_get_list { - struct devlink_health_reporter_get_list *next; - struct devlink_health_reporter_get_rsp obj __attribute__ ((aligned (8))); -}; - -void -devlink_health_reporter_get_list_free(struct devlink_health_reporter_get_list *rsp); - -struct devlink_health_reporter_get_list * -devlink_health_reporter_get_dump(struct ynl_sock *ys, - struct devlink_health_reporter_get_req_dump *req); - -/* ============== DEVLINK_CMD_TRAP_GET ============== */ -/* DEVLINK_CMD_TRAP_GET - do */ -struct devlink_trap_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 trap_name_len; - } _present; - - char *bus_name; - char *dev_name; - char *trap_name; -}; - -static inline struct devlink_trap_get_req *devlink_trap_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_trap_get_req)); -} -void devlink_trap_get_req_free(struct devlink_trap_get_req *req); - -static inline void -devlink_trap_get_req_set_bus_name(struct devlink_trap_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_trap_get_req_set_dev_name(struct devlink_trap_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_trap_get_req_set_trap_name(struct devlink_trap_get_req *req, - const char *trap_name) -{ - free(req->trap_name); - req->_present.trap_name_len = strlen(trap_name); - req->trap_name = malloc(req->_present.trap_name_len + 1); - memcpy(req->trap_name, trap_name, req->_present.trap_name_len); - req->trap_name[req->_present.trap_name_len] = 0; -} - -struct devlink_trap_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 trap_name_len; - } _present; - - char *bus_name; - char *dev_name; - char *trap_name; -}; - -void devlink_trap_get_rsp_free(struct devlink_trap_get_rsp *rsp); - -/* - * Get trap instances. - */ -struct devlink_trap_get_rsp * -devlink_trap_get(struct ynl_sock *ys, struct devlink_trap_get_req *req); - -/* DEVLINK_CMD_TRAP_GET - dump */ -struct devlink_trap_get_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_trap_get_req_dump * -devlink_trap_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_trap_get_req_dump)); -} -void devlink_trap_get_req_dump_free(struct devlink_trap_get_req_dump *req); - -static inline void -devlink_trap_get_req_dump_set_bus_name(struct devlink_trap_get_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_trap_get_req_dump_set_dev_name(struct devlink_trap_get_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_trap_get_list { - struct devlink_trap_get_list *next; - struct devlink_trap_get_rsp obj __attribute__ ((aligned (8))); -}; - -void devlink_trap_get_list_free(struct devlink_trap_get_list *rsp); - -struct devlink_trap_get_list * -devlink_trap_get_dump(struct ynl_sock *ys, - struct devlink_trap_get_req_dump *req); - -/* ============== DEVLINK_CMD_TRAP_GROUP_GET ============== */ -/* DEVLINK_CMD_TRAP_GROUP_GET - do */ -struct devlink_trap_group_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 trap_group_name_len; - } _present; - - char *bus_name; - char *dev_name; - char *trap_group_name; -}; - -static inline struct devlink_trap_group_get_req * -devlink_trap_group_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_trap_group_get_req)); -} -void devlink_trap_group_get_req_free(struct devlink_trap_group_get_req *req); - -static inline void -devlink_trap_group_get_req_set_bus_name(struct devlink_trap_group_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_trap_group_get_req_set_dev_name(struct devlink_trap_group_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_trap_group_get_req_set_trap_group_name(struct devlink_trap_group_get_req *req, - const char *trap_group_name) -{ - free(req->trap_group_name); - req->_present.trap_group_name_len = strlen(trap_group_name); - req->trap_group_name = malloc(req->_present.trap_group_name_len + 1); - memcpy(req->trap_group_name, trap_group_name, req->_present.trap_group_name_len); - req->trap_group_name[req->_present.trap_group_name_len] = 0; -} - -struct devlink_trap_group_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 trap_group_name_len; - } _present; - - char *bus_name; - char *dev_name; - char *trap_group_name; -}; - -void devlink_trap_group_get_rsp_free(struct devlink_trap_group_get_rsp *rsp); - -/* - * Get trap group instances. - */ -struct devlink_trap_group_get_rsp * -devlink_trap_group_get(struct ynl_sock *ys, - struct devlink_trap_group_get_req *req); - -/* DEVLINK_CMD_TRAP_GROUP_GET - dump */ -struct devlink_trap_group_get_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_trap_group_get_req_dump * -devlink_trap_group_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_trap_group_get_req_dump)); -} -void -devlink_trap_group_get_req_dump_free(struct devlink_trap_group_get_req_dump *req); - -static inline void -devlink_trap_group_get_req_dump_set_bus_name(struct devlink_trap_group_get_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_trap_group_get_req_dump_set_dev_name(struct devlink_trap_group_get_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_trap_group_get_list { - struct devlink_trap_group_get_list *next; - struct devlink_trap_group_get_rsp obj __attribute__ ((aligned (8))); -}; - -void devlink_trap_group_get_list_free(struct devlink_trap_group_get_list *rsp); - -struct devlink_trap_group_get_list * -devlink_trap_group_get_dump(struct ynl_sock *ys, - struct devlink_trap_group_get_req_dump *req); - -/* ============== DEVLINK_CMD_TRAP_POLICER_GET ============== */ -/* DEVLINK_CMD_TRAP_POLICER_GET - do */ -struct devlink_trap_policer_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 trap_policer_id:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 trap_policer_id; -}; - -static inline struct devlink_trap_policer_get_req * -devlink_trap_policer_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_trap_policer_get_req)); -} -void -devlink_trap_policer_get_req_free(struct devlink_trap_policer_get_req *req); - -static inline void -devlink_trap_policer_get_req_set_bus_name(struct devlink_trap_policer_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_trap_policer_get_req_set_dev_name(struct devlink_trap_policer_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_trap_policer_get_req_set_trap_policer_id(struct devlink_trap_policer_get_req *req, - __u32 trap_policer_id) -{ - req->_present.trap_policer_id = 1; - req->trap_policer_id = trap_policer_id; -} - -struct devlink_trap_policer_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 trap_policer_id:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 trap_policer_id; -}; - -void -devlink_trap_policer_get_rsp_free(struct devlink_trap_policer_get_rsp *rsp); - -/* - * Get trap policer instances. - */ -struct devlink_trap_policer_get_rsp * -devlink_trap_policer_get(struct ynl_sock *ys, - struct devlink_trap_policer_get_req *req); - -/* DEVLINK_CMD_TRAP_POLICER_GET - dump */ -struct devlink_trap_policer_get_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_trap_policer_get_req_dump * -devlink_trap_policer_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_trap_policer_get_req_dump)); -} -void -devlink_trap_policer_get_req_dump_free(struct devlink_trap_policer_get_req_dump *req); - -static inline void -devlink_trap_policer_get_req_dump_set_bus_name(struct devlink_trap_policer_get_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_trap_policer_get_req_dump_set_dev_name(struct devlink_trap_policer_get_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_trap_policer_get_list { - struct devlink_trap_policer_get_list *next; - struct devlink_trap_policer_get_rsp obj __attribute__ ((aligned (8))); -}; - -void -devlink_trap_policer_get_list_free(struct devlink_trap_policer_get_list *rsp); - -struct devlink_trap_policer_get_list * -devlink_trap_policer_get_dump(struct ynl_sock *ys, - struct devlink_trap_policer_get_req_dump *req); - -/* ============== DEVLINK_CMD_RATE_GET ============== */ -/* DEVLINK_CMD_RATE_GET - do */ -struct devlink_rate_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 rate_node_name_len; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - char *rate_node_name; -}; - -static inline struct devlink_rate_get_req *devlink_rate_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_rate_get_req)); -} -void devlink_rate_get_req_free(struct devlink_rate_get_req *req); - -static inline void -devlink_rate_get_req_set_bus_name(struct devlink_rate_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_rate_get_req_set_dev_name(struct devlink_rate_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_rate_get_req_set_port_index(struct devlink_rate_get_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_rate_get_req_set_rate_node_name(struct devlink_rate_get_req *req, - const char *rate_node_name) -{ - free(req->rate_node_name); - req->_present.rate_node_name_len = strlen(rate_node_name); - req->rate_node_name = malloc(req->_present.rate_node_name_len + 1); - memcpy(req->rate_node_name, rate_node_name, req->_present.rate_node_name_len); - req->rate_node_name[req->_present.rate_node_name_len] = 0; -} - -struct devlink_rate_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 rate_node_name_len; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - char *rate_node_name; -}; - -void devlink_rate_get_rsp_free(struct devlink_rate_get_rsp *rsp); - -/* - * Get rate instances. - */ -struct devlink_rate_get_rsp * -devlink_rate_get(struct ynl_sock *ys, struct devlink_rate_get_req *req); - -/* DEVLINK_CMD_RATE_GET - dump */ -struct devlink_rate_get_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_rate_get_req_dump * -devlink_rate_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_rate_get_req_dump)); -} -void devlink_rate_get_req_dump_free(struct devlink_rate_get_req_dump *req); - -static inline void -devlink_rate_get_req_dump_set_bus_name(struct devlink_rate_get_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_rate_get_req_dump_set_dev_name(struct devlink_rate_get_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_rate_get_list { - struct devlink_rate_get_list *next; - struct devlink_rate_get_rsp obj __attribute__ ((aligned (8))); -}; - -void devlink_rate_get_list_free(struct devlink_rate_get_list *rsp); - -struct devlink_rate_get_list * -devlink_rate_get_dump(struct ynl_sock *ys, - struct devlink_rate_get_req_dump *req); - -/* ============== DEVLINK_CMD_LINECARD_GET ============== */ -/* DEVLINK_CMD_LINECARD_GET - do */ -struct devlink_linecard_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 linecard_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 linecard_index; -}; - -static inline struct devlink_linecard_get_req * -devlink_linecard_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_linecard_get_req)); -} -void devlink_linecard_get_req_free(struct devlink_linecard_get_req *req); - -static inline void -devlink_linecard_get_req_set_bus_name(struct devlink_linecard_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_linecard_get_req_set_dev_name(struct devlink_linecard_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_linecard_get_req_set_linecard_index(struct devlink_linecard_get_req *req, - __u32 linecard_index) -{ - req->_present.linecard_index = 1; - req->linecard_index = linecard_index; -} - -struct devlink_linecard_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 linecard_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 linecard_index; -}; - -void devlink_linecard_get_rsp_free(struct devlink_linecard_get_rsp *rsp); - -/* - * Get line card instances. - */ -struct devlink_linecard_get_rsp * -devlink_linecard_get(struct ynl_sock *ys, struct devlink_linecard_get_req *req); - -/* DEVLINK_CMD_LINECARD_GET - dump */ -struct devlink_linecard_get_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_linecard_get_req_dump * -devlink_linecard_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_linecard_get_req_dump)); -} -void -devlink_linecard_get_req_dump_free(struct devlink_linecard_get_req_dump *req); - -static inline void -devlink_linecard_get_req_dump_set_bus_name(struct devlink_linecard_get_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_linecard_get_req_dump_set_dev_name(struct devlink_linecard_get_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_linecard_get_list { - struct devlink_linecard_get_list *next; - struct devlink_linecard_get_rsp obj __attribute__ ((aligned (8))); -}; - -void devlink_linecard_get_list_free(struct devlink_linecard_get_list *rsp); - -struct devlink_linecard_get_list * -devlink_linecard_get_dump(struct ynl_sock *ys, - struct devlink_linecard_get_req_dump *req); - -/* ============== DEVLINK_CMD_SELFTESTS_GET ============== */ -/* DEVLINK_CMD_SELFTESTS_GET - do */ -struct devlink_selftests_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_selftests_get_req * -devlink_selftests_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_selftests_get_req)); -} -void devlink_selftests_get_req_free(struct devlink_selftests_get_req *req); - -static inline void -devlink_selftests_get_req_set_bus_name(struct devlink_selftests_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_selftests_get_req_set_dev_name(struct devlink_selftests_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_selftests_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -void devlink_selftests_get_rsp_free(struct devlink_selftests_get_rsp *rsp); - -/* - * Get device selftest instances. - */ -struct devlink_selftests_get_rsp * -devlink_selftests_get(struct ynl_sock *ys, - struct devlink_selftests_get_req *req); - -/* DEVLINK_CMD_SELFTESTS_GET - dump */ -struct devlink_selftests_get_list { - struct devlink_selftests_get_list *next; - struct devlink_selftests_get_rsp obj __attribute__ ((aligned (8))); -}; - -void devlink_selftests_get_list_free(struct devlink_selftests_get_list *rsp); - -struct devlink_selftests_get_list * -devlink_selftests_get_dump(struct ynl_sock *ys); - -#endif /* _LINUX_DEVLINK_GEN_H */ diff --git a/tools/net/ynl/generated/ethtool-user.c b/tools/net/ynl/generated/ethtool-user.c deleted file mode 100644 index 74b883a14958..000000000000 --- a/tools/net/ynl/generated/ethtool-user.c +++ /dev/null @@ -1,6353 +0,0 @@ -// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) -/* Do not edit directly, auto-generated from: */ -/* Documentation/netlink/specs/ethtool.yaml */ -/* YNL-GEN user source */ -/* YNL-ARG --user-header linux/ethtool_netlink.h --exclude-op stats-get */ - -#include <stdlib.h> -#include <string.h> -#include "ethtool-user.h" -#include "ynl.h" -#include <linux/ethtool.h> - -#include <libmnl/libmnl.h> -#include <linux/genetlink.h> - -#include "linux/ethtool_netlink.h" - -/* Enums */ -static const char * const ethtool_op_strmap[] = { - [ETHTOOL_MSG_STRSET_GET] = "strset-get", - [ETHTOOL_MSG_LINKINFO_GET] = "linkinfo-get", - [3] = "linkinfo-ntf", - [ETHTOOL_MSG_LINKMODES_GET] = "linkmodes-get", - [5] = "linkmodes-ntf", - [ETHTOOL_MSG_LINKSTATE_GET] = "linkstate-get", - [ETHTOOL_MSG_DEBUG_GET] = "debug-get", - [8] = "debug-ntf", - [ETHTOOL_MSG_WOL_GET] = "wol-get", - [10] = "wol-ntf", - [ETHTOOL_MSG_FEATURES_GET] = "features-get", - [ETHTOOL_MSG_FEATURES_SET] = "features-set", - [13] = "features-ntf", - [14] = "privflags-get", - [15] = "privflags-ntf", - [16] = "rings-get", - [17] = "rings-ntf", - [18] = "channels-get", - [19] = "channels-ntf", - [20] = "coalesce-get", - [21] = "coalesce-ntf", - [22] = "pause-get", - [23] = "pause-ntf", - [24] = "eee-get", - [25] = "eee-ntf", - [26] = "tsinfo-get", - [27] = "cable-test-ntf", - [28] = "cable-test-tdr-ntf", - [29] = "tunnel-info-get", - [30] = "fec-get", - [31] = "fec-ntf", - [32] = "module-eeprom-get", - [34] = "phc-vclocks-get", - [35] = "module-get", - [36] = "module-ntf", - [37] = "pse-get", - [ETHTOOL_MSG_RSS_GET] = "rss-get", - [ETHTOOL_MSG_PLCA_GET_CFG] = "plca-get-cfg", - [40] = "plca-get-status", - [41] = "plca-ntf", - [ETHTOOL_MSG_MM_GET] = "mm-get", - [43] = "mm-ntf", -}; - -const char *ethtool_op_str(int op) -{ - if (op < 0 || op >= (int)MNL_ARRAY_SIZE(ethtool_op_strmap)) - return NULL; - return ethtool_op_strmap[op]; -} - -static const char * const ethtool_udp_tunnel_type_strmap[] = { - [0] = "vxlan", - [1] = "geneve", - [2] = "vxlan-gpe", -}; - -const char *ethtool_udp_tunnel_type_str(int value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(ethtool_udp_tunnel_type_strmap)) - return NULL; - return ethtool_udp_tunnel_type_strmap[value]; -} - -static const char * const ethtool_stringset_strmap[] = { -}; - -const char *ethtool_stringset_str(enum ethtool_stringset value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(ethtool_stringset_strmap)) - return NULL; - return ethtool_stringset_strmap[value]; -} - -/* Policies */ -struct ynl_policy_attr ethtool_header_policy[ETHTOOL_A_HEADER_MAX + 1] = { - [ETHTOOL_A_HEADER_DEV_INDEX] = { .name = "dev-index", .type = YNL_PT_U32, }, - [ETHTOOL_A_HEADER_DEV_NAME] = { .name = "dev-name", .type = YNL_PT_NUL_STR, }, - [ETHTOOL_A_HEADER_FLAGS] = { .name = "flags", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest ethtool_header_nest = { - .max_attr = ETHTOOL_A_HEADER_MAX, - .table = ethtool_header_policy, -}; - -struct ynl_policy_attr ethtool_pause_stat_policy[ETHTOOL_A_PAUSE_STAT_MAX + 1] = { - [ETHTOOL_A_PAUSE_STAT_PAD] = { .name = "pad", .type = YNL_PT_IGNORE, }, - [ETHTOOL_A_PAUSE_STAT_TX_FRAMES] = { .name = "tx-frames", .type = YNL_PT_U64, }, - [ETHTOOL_A_PAUSE_STAT_RX_FRAMES] = { .name = "rx-frames", .type = YNL_PT_U64, }, -}; - -struct ynl_policy_nest ethtool_pause_stat_nest = { - .max_attr = ETHTOOL_A_PAUSE_STAT_MAX, - .table = ethtool_pause_stat_policy, -}; - -struct ynl_policy_attr ethtool_cable_test_tdr_cfg_policy[ETHTOOL_A_CABLE_TEST_TDR_CFG_MAX + 1] = { - [ETHTOOL_A_CABLE_TEST_TDR_CFG_FIRST] = { .name = "first", .type = YNL_PT_U32, }, - [ETHTOOL_A_CABLE_TEST_TDR_CFG_LAST] = { .name = "last", .type = YNL_PT_U32, }, - [ETHTOOL_A_CABLE_TEST_TDR_CFG_STEP] = { .name = "step", .type = YNL_PT_U32, }, - [ETHTOOL_A_CABLE_TEST_TDR_CFG_PAIR] = { .name = "pair", .type = YNL_PT_U8, }, -}; - -struct ynl_policy_nest ethtool_cable_test_tdr_cfg_nest = { - .max_attr = ETHTOOL_A_CABLE_TEST_TDR_CFG_MAX, - .table = ethtool_cable_test_tdr_cfg_policy, -}; - -struct ynl_policy_attr ethtool_fec_stat_policy[ETHTOOL_A_FEC_STAT_MAX + 1] = { - [ETHTOOL_A_FEC_STAT_PAD] = { .name = "pad", .type = YNL_PT_IGNORE, }, - [ETHTOOL_A_FEC_STAT_CORRECTED] = { .name = "corrected", .type = YNL_PT_BINARY,}, - [ETHTOOL_A_FEC_STAT_UNCORR] = { .name = "uncorr", .type = YNL_PT_BINARY,}, - [ETHTOOL_A_FEC_STAT_CORR_BITS] = { .name = "corr-bits", .type = YNL_PT_BINARY,}, -}; - -struct ynl_policy_nest ethtool_fec_stat_nest = { - .max_attr = ETHTOOL_A_FEC_STAT_MAX, - .table = ethtool_fec_stat_policy, -}; - -struct ynl_policy_attr ethtool_mm_stat_policy[ETHTOOL_A_MM_STAT_MAX + 1] = { - [ETHTOOL_A_MM_STAT_PAD] = { .name = "pad", .type = YNL_PT_IGNORE, }, - [ETHTOOL_A_MM_STAT_REASSEMBLY_ERRORS] = { .name = "reassembly-errors", .type = YNL_PT_U64, }, - [ETHTOOL_A_MM_STAT_SMD_ERRORS] = { .name = "smd-errors", .type = YNL_PT_U64, }, - [ETHTOOL_A_MM_STAT_REASSEMBLY_OK] = { .name = "reassembly-ok", .type = YNL_PT_U64, }, - [ETHTOOL_A_MM_STAT_RX_FRAG_COUNT] = { .name = "rx-frag-count", .type = YNL_PT_U64, }, - [ETHTOOL_A_MM_STAT_TX_FRAG_COUNT] = { .name = "tx-frag-count", .type = YNL_PT_U64, }, - [ETHTOOL_A_MM_STAT_HOLD_COUNT] = { .name = "hold-count", .type = YNL_PT_U64, }, -}; - -struct ynl_policy_nest ethtool_mm_stat_nest = { - .max_attr = ETHTOOL_A_MM_STAT_MAX, - .table = ethtool_mm_stat_policy, -}; - -struct ynl_policy_attr ethtool_cable_result_policy[ETHTOOL_A_CABLE_RESULT_MAX + 1] = { - [ETHTOOL_A_CABLE_RESULT_PAIR] = { .name = "pair", .type = YNL_PT_U8, }, - [ETHTOOL_A_CABLE_RESULT_CODE] = { .name = "code", .type = YNL_PT_U8, }, -}; - -struct ynl_policy_nest ethtool_cable_result_nest = { - .max_attr = ETHTOOL_A_CABLE_RESULT_MAX, - .table = ethtool_cable_result_policy, -}; - -struct ynl_policy_attr ethtool_cable_fault_length_policy[ETHTOOL_A_CABLE_FAULT_LENGTH_MAX + 1] = { - [ETHTOOL_A_CABLE_FAULT_LENGTH_PAIR] = { .name = "pair", .type = YNL_PT_U8, }, - [ETHTOOL_A_CABLE_FAULT_LENGTH_CM] = { .name = "cm", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest ethtool_cable_fault_length_nest = { - .max_attr = ETHTOOL_A_CABLE_FAULT_LENGTH_MAX, - .table = ethtool_cable_fault_length_policy, -}; - -struct ynl_policy_attr ethtool_bitset_bit_policy[ETHTOOL_A_BITSET_BIT_MAX + 1] = { - [ETHTOOL_A_BITSET_BIT_INDEX] = { .name = "index", .type = YNL_PT_U32, }, - [ETHTOOL_A_BITSET_BIT_NAME] = { .name = "name", .type = YNL_PT_NUL_STR, }, - [ETHTOOL_A_BITSET_BIT_VALUE] = { .name = "value", .type = YNL_PT_FLAG, }, -}; - -struct ynl_policy_nest ethtool_bitset_bit_nest = { - .max_attr = ETHTOOL_A_BITSET_BIT_MAX, - .table = ethtool_bitset_bit_policy, -}; - -struct ynl_policy_attr ethtool_tunnel_udp_entry_policy[ETHTOOL_A_TUNNEL_UDP_ENTRY_MAX + 1] = { - [ETHTOOL_A_TUNNEL_UDP_ENTRY_PORT] = { .name = "port", .type = YNL_PT_U16, }, - [ETHTOOL_A_TUNNEL_UDP_ENTRY_TYPE] = { .name = "type", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest ethtool_tunnel_udp_entry_nest = { - .max_attr = ETHTOOL_A_TUNNEL_UDP_ENTRY_MAX, - .table = ethtool_tunnel_udp_entry_policy, -}; - -struct ynl_policy_attr ethtool_string_policy[ETHTOOL_A_STRING_MAX + 1] = { - [ETHTOOL_A_STRING_INDEX] = { .name = "index", .type = YNL_PT_U32, }, - [ETHTOOL_A_STRING_VALUE] = { .name = "value", .type = YNL_PT_NUL_STR, }, -}; - -struct ynl_policy_nest ethtool_string_nest = { - .max_attr = ETHTOOL_A_STRING_MAX, - .table = ethtool_string_policy, -}; - -struct ynl_policy_attr ethtool_cable_nest_policy[ETHTOOL_A_CABLE_NEST_MAX + 1] = { - [ETHTOOL_A_CABLE_NEST_RESULT] = { .name = "result", .type = YNL_PT_NEST, .nest = ðtool_cable_result_nest, }, - [ETHTOOL_A_CABLE_NEST_FAULT_LENGTH] = { .name = "fault-length", .type = YNL_PT_NEST, .nest = ðtool_cable_fault_length_nest, }, -}; - -struct ynl_policy_nest ethtool_cable_nest_nest = { - .max_attr = ETHTOOL_A_CABLE_NEST_MAX, - .table = ethtool_cable_nest_policy, -}; - -struct ynl_policy_attr ethtool_bitset_bits_policy[ETHTOOL_A_BITSET_BITS_MAX + 1] = { - [ETHTOOL_A_BITSET_BITS_BIT] = { .name = "bit", .type = YNL_PT_NEST, .nest = ðtool_bitset_bit_nest, }, -}; - -struct ynl_policy_nest ethtool_bitset_bits_nest = { - .max_attr = ETHTOOL_A_BITSET_BITS_MAX, - .table = ethtool_bitset_bits_policy, -}; - -struct ynl_policy_attr ethtool_strings_policy[ETHTOOL_A_STRINGS_MAX + 1] = { - [ETHTOOL_A_STRINGS_STRING] = { .name = "string", .type = YNL_PT_NEST, .nest = ðtool_string_nest, }, -}; - -struct ynl_policy_nest ethtool_strings_nest = { - .max_attr = ETHTOOL_A_STRINGS_MAX, - .table = ethtool_strings_policy, -}; - -struct ynl_policy_attr ethtool_bitset_policy[ETHTOOL_A_BITSET_MAX + 1] = { - [ETHTOOL_A_BITSET_NOMASK] = { .name = "nomask", .type = YNL_PT_FLAG, }, - [ETHTOOL_A_BITSET_SIZE] = { .name = "size", .type = YNL_PT_U32, }, - [ETHTOOL_A_BITSET_BITS] = { .name = "bits", .type = YNL_PT_NEST, .nest = ðtool_bitset_bits_nest, }, -}; - -struct ynl_policy_nest ethtool_bitset_nest = { - .max_attr = ETHTOOL_A_BITSET_MAX, - .table = ethtool_bitset_policy, -}; - -struct ynl_policy_attr ethtool_stringset_policy[ETHTOOL_A_STRINGSET_MAX + 1] = { - [ETHTOOL_A_STRINGSET_ID] = { .name = "id", .type = YNL_PT_U32, }, - [ETHTOOL_A_STRINGSET_COUNT] = { .name = "count", .type = YNL_PT_U32, }, - [ETHTOOL_A_STRINGSET_STRINGS] = { .name = "strings", .type = YNL_PT_NEST, .nest = ðtool_strings_nest, }, -}; - -struct ynl_policy_nest ethtool_stringset_nest = { - .max_attr = ETHTOOL_A_STRINGSET_MAX, - .table = ethtool_stringset_policy, -}; - -struct ynl_policy_attr ethtool_tunnel_udp_table_policy[ETHTOOL_A_TUNNEL_UDP_TABLE_MAX + 1] = { - [ETHTOOL_A_TUNNEL_UDP_TABLE_SIZE] = { .name = "size", .type = YNL_PT_U32, }, - [ETHTOOL_A_TUNNEL_UDP_TABLE_TYPES] = { .name = "types", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, - [ETHTOOL_A_TUNNEL_UDP_TABLE_ENTRY] = { .name = "entry", .type = YNL_PT_NEST, .nest = ðtool_tunnel_udp_entry_nest, }, -}; - -struct ynl_policy_nest ethtool_tunnel_udp_table_nest = { - .max_attr = ETHTOOL_A_TUNNEL_UDP_TABLE_MAX, - .table = ethtool_tunnel_udp_table_policy, -}; - -struct ynl_policy_attr ethtool_stringsets_policy[ETHTOOL_A_STRINGSETS_MAX + 1] = { - [ETHTOOL_A_STRINGSETS_STRINGSET] = { .name = "stringset", .type = YNL_PT_NEST, .nest = ðtool_stringset_nest, }, -}; - -struct ynl_policy_nest ethtool_stringsets_nest = { - .max_attr = ETHTOOL_A_STRINGSETS_MAX, - .table = ethtool_stringsets_policy, -}; - -struct ynl_policy_attr ethtool_tunnel_udp_policy[ETHTOOL_A_TUNNEL_UDP_MAX + 1] = { - [ETHTOOL_A_TUNNEL_UDP_TABLE] = { .name = "table", .type = YNL_PT_NEST, .nest = ðtool_tunnel_udp_table_nest, }, -}; - -struct ynl_policy_nest ethtool_tunnel_udp_nest = { - .max_attr = ETHTOOL_A_TUNNEL_UDP_MAX, - .table = ethtool_tunnel_udp_policy, -}; - -struct ynl_policy_attr ethtool_strset_policy[ETHTOOL_A_STRSET_MAX + 1] = { - [ETHTOOL_A_STRSET_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_STRSET_STRINGSETS] = { .name = "stringsets", .type = YNL_PT_NEST, .nest = ðtool_stringsets_nest, }, - [ETHTOOL_A_STRSET_COUNTS_ONLY] = { .name = "counts-only", .type = YNL_PT_FLAG, }, -}; - -struct ynl_policy_nest ethtool_strset_nest = { - .max_attr = ETHTOOL_A_STRSET_MAX, - .table = ethtool_strset_policy, -}; - -struct ynl_policy_attr ethtool_linkinfo_policy[ETHTOOL_A_LINKINFO_MAX + 1] = { - [ETHTOOL_A_LINKINFO_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_LINKINFO_PORT] = { .name = "port", .type = YNL_PT_U8, }, - [ETHTOOL_A_LINKINFO_PHYADDR] = { .name = "phyaddr", .type = YNL_PT_U8, }, - [ETHTOOL_A_LINKINFO_TP_MDIX] = { .name = "tp-mdix", .type = YNL_PT_U8, }, - [ETHTOOL_A_LINKINFO_TP_MDIX_CTRL] = { .name = "tp-mdix-ctrl", .type = YNL_PT_U8, }, - [ETHTOOL_A_LINKINFO_TRANSCEIVER] = { .name = "transceiver", .type = YNL_PT_U8, }, -}; - -struct ynl_policy_nest ethtool_linkinfo_nest = { - .max_attr = ETHTOOL_A_LINKINFO_MAX, - .table = ethtool_linkinfo_policy, -}; - -struct ynl_policy_attr ethtool_linkmodes_policy[ETHTOOL_A_LINKMODES_MAX + 1] = { - [ETHTOOL_A_LINKMODES_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_LINKMODES_AUTONEG] = { .name = "autoneg", .type = YNL_PT_U8, }, - [ETHTOOL_A_LINKMODES_OURS] = { .name = "ours", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, - [ETHTOOL_A_LINKMODES_PEER] = { .name = "peer", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, - [ETHTOOL_A_LINKMODES_SPEED] = { .name = "speed", .type = YNL_PT_U32, }, - [ETHTOOL_A_LINKMODES_DUPLEX] = { .name = "duplex", .type = YNL_PT_U8, }, - [ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG] = { .name = "master-slave-cfg", .type = YNL_PT_U8, }, - [ETHTOOL_A_LINKMODES_MASTER_SLAVE_STATE] = { .name = "master-slave-state", .type = YNL_PT_U8, }, - [ETHTOOL_A_LINKMODES_LANES] = { .name = "lanes", .type = YNL_PT_U32, }, - [ETHTOOL_A_LINKMODES_RATE_MATCHING] = { .name = "rate-matching", .type = YNL_PT_U8, }, -}; - -struct ynl_policy_nest ethtool_linkmodes_nest = { - .max_attr = ETHTOOL_A_LINKMODES_MAX, - .table = ethtool_linkmodes_policy, -}; - -struct ynl_policy_attr ethtool_linkstate_policy[ETHTOOL_A_LINKSTATE_MAX + 1] = { - [ETHTOOL_A_LINKSTATE_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_LINKSTATE_LINK] = { .name = "link", .type = YNL_PT_U8, }, - [ETHTOOL_A_LINKSTATE_SQI] = { .name = "sqi", .type = YNL_PT_U32, }, - [ETHTOOL_A_LINKSTATE_SQI_MAX] = { .name = "sqi-max", .type = YNL_PT_U32, }, - [ETHTOOL_A_LINKSTATE_EXT_STATE] = { .name = "ext-state", .type = YNL_PT_U8, }, - [ETHTOOL_A_LINKSTATE_EXT_SUBSTATE] = { .name = "ext-substate", .type = YNL_PT_U8, }, - [ETHTOOL_A_LINKSTATE_EXT_DOWN_CNT] = { .name = "ext-down-cnt", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest ethtool_linkstate_nest = { - .max_attr = ETHTOOL_A_LINKSTATE_MAX, - .table = ethtool_linkstate_policy, -}; - -struct ynl_policy_attr ethtool_debug_policy[ETHTOOL_A_DEBUG_MAX + 1] = { - [ETHTOOL_A_DEBUG_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_DEBUG_MSGMASK] = { .name = "msgmask", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, -}; - -struct ynl_policy_nest ethtool_debug_nest = { - .max_attr = ETHTOOL_A_DEBUG_MAX, - .table = ethtool_debug_policy, -}; - -struct ynl_policy_attr ethtool_wol_policy[ETHTOOL_A_WOL_MAX + 1] = { - [ETHTOOL_A_WOL_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_WOL_MODES] = { .name = "modes", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, - [ETHTOOL_A_WOL_SOPASS] = { .name = "sopass", .type = YNL_PT_BINARY,}, -}; - -struct ynl_policy_nest ethtool_wol_nest = { - .max_attr = ETHTOOL_A_WOL_MAX, - .table = ethtool_wol_policy, -}; - -struct ynl_policy_attr ethtool_features_policy[ETHTOOL_A_FEATURES_MAX + 1] = { - [ETHTOOL_A_FEATURES_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_FEATURES_HW] = { .name = "hw", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, - [ETHTOOL_A_FEATURES_WANTED] = { .name = "wanted", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, - [ETHTOOL_A_FEATURES_ACTIVE] = { .name = "active", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, - [ETHTOOL_A_FEATURES_NOCHANGE] = { .name = "nochange", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, -}; - -struct ynl_policy_nest ethtool_features_nest = { - .max_attr = ETHTOOL_A_FEATURES_MAX, - .table = ethtool_features_policy, -}; - -struct ynl_policy_attr ethtool_privflags_policy[ETHTOOL_A_PRIVFLAGS_MAX + 1] = { - [ETHTOOL_A_PRIVFLAGS_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_PRIVFLAGS_FLAGS] = { .name = "flags", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, -}; - -struct ynl_policy_nest ethtool_privflags_nest = { - .max_attr = ETHTOOL_A_PRIVFLAGS_MAX, - .table = ethtool_privflags_policy, -}; - -struct ynl_policy_attr ethtool_rings_policy[ETHTOOL_A_RINGS_MAX + 1] = { - [ETHTOOL_A_RINGS_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_RINGS_RX_MAX] = { .name = "rx-max", .type = YNL_PT_U32, }, - [ETHTOOL_A_RINGS_RX_MINI_MAX] = { .name = "rx-mini-max", .type = YNL_PT_U32, }, - [ETHTOOL_A_RINGS_RX_JUMBO_MAX] = { .name = "rx-jumbo-max", .type = YNL_PT_U32, }, - [ETHTOOL_A_RINGS_TX_MAX] = { .name = "tx-max", .type = YNL_PT_U32, }, - [ETHTOOL_A_RINGS_RX] = { .name = "rx", .type = YNL_PT_U32, }, - [ETHTOOL_A_RINGS_RX_MINI] = { .name = "rx-mini", .type = YNL_PT_U32, }, - [ETHTOOL_A_RINGS_RX_JUMBO] = { .name = "rx-jumbo", .type = YNL_PT_U32, }, - [ETHTOOL_A_RINGS_TX] = { .name = "tx", .type = YNL_PT_U32, }, - [ETHTOOL_A_RINGS_RX_BUF_LEN] = { .name = "rx-buf-len", .type = YNL_PT_U32, }, - [ETHTOOL_A_RINGS_TCP_DATA_SPLIT] = { .name = "tcp-data-split", .type = YNL_PT_U8, }, - [ETHTOOL_A_RINGS_CQE_SIZE] = { .name = "cqe-size", .type = YNL_PT_U32, }, - [ETHTOOL_A_RINGS_TX_PUSH] = { .name = "tx-push", .type = YNL_PT_U8, }, - [ETHTOOL_A_RINGS_RX_PUSH] = { .name = "rx-push", .type = YNL_PT_U8, }, - [ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN] = { .name = "tx-push-buf-len", .type = YNL_PT_U32, }, - [ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN_MAX] = { .name = "tx-push-buf-len-max", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest ethtool_rings_nest = { - .max_attr = ETHTOOL_A_RINGS_MAX, - .table = ethtool_rings_policy, -}; - -struct ynl_policy_attr ethtool_channels_policy[ETHTOOL_A_CHANNELS_MAX + 1] = { - [ETHTOOL_A_CHANNELS_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_CHANNELS_RX_MAX] = { .name = "rx-max", .type = YNL_PT_U32, }, - [ETHTOOL_A_CHANNELS_TX_MAX] = { .name = "tx-max", .type = YNL_PT_U32, }, - [ETHTOOL_A_CHANNELS_OTHER_MAX] = { .name = "other-max", .type = YNL_PT_U32, }, - [ETHTOOL_A_CHANNELS_COMBINED_MAX] = { .name = "combined-max", .type = YNL_PT_U32, }, - [ETHTOOL_A_CHANNELS_RX_COUNT] = { .name = "rx-count", .type = YNL_PT_U32, }, - [ETHTOOL_A_CHANNELS_TX_COUNT] = { .name = "tx-count", .type = YNL_PT_U32, }, - [ETHTOOL_A_CHANNELS_OTHER_COUNT] = { .name = "other-count", .type = YNL_PT_U32, }, - [ETHTOOL_A_CHANNELS_COMBINED_COUNT] = { .name = "combined-count", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest ethtool_channels_nest = { - .max_attr = ETHTOOL_A_CHANNELS_MAX, - .table = ethtool_channels_policy, -}; - -struct ynl_policy_attr ethtool_coalesce_policy[ETHTOOL_A_COALESCE_MAX + 1] = { - [ETHTOOL_A_COALESCE_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_COALESCE_RX_USECS] = { .name = "rx-usecs", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_RX_MAX_FRAMES] = { .name = "rx-max-frames", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_RX_USECS_IRQ] = { .name = "rx-usecs-irq", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ] = { .name = "rx-max-frames-irq", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_TX_USECS] = { .name = "tx-usecs", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_TX_MAX_FRAMES] = { .name = "tx-max-frames", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_TX_USECS_IRQ] = { .name = "tx-usecs-irq", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ] = { .name = "tx-max-frames-irq", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_STATS_BLOCK_USECS] = { .name = "stats-block-usecs", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX] = { .name = "use-adaptive-rx", .type = YNL_PT_U8, }, - [ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX] = { .name = "use-adaptive-tx", .type = YNL_PT_U8, }, - [ETHTOOL_A_COALESCE_PKT_RATE_LOW] = { .name = "pkt-rate-low", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_RX_USECS_LOW] = { .name = "rx-usecs-low", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW] = { .name = "rx-max-frames-low", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_TX_USECS_LOW] = { .name = "tx-usecs-low", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW] = { .name = "tx-max-frames-low", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_PKT_RATE_HIGH] = { .name = "pkt-rate-high", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_RX_USECS_HIGH] = { .name = "rx-usecs-high", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH] = { .name = "rx-max-frames-high", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_TX_USECS_HIGH] = { .name = "tx-usecs-high", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH] = { .name = "tx-max-frames-high", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL] = { .name = "rate-sample-interval", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_USE_CQE_MODE_TX] = { .name = "use-cqe-mode-tx", .type = YNL_PT_U8, }, - [ETHTOOL_A_COALESCE_USE_CQE_MODE_RX] = { .name = "use-cqe-mode-rx", .type = YNL_PT_U8, }, - [ETHTOOL_A_COALESCE_TX_AGGR_MAX_BYTES] = { .name = "tx-aggr-max-bytes", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_TX_AGGR_MAX_FRAMES] = { .name = "tx-aggr-max-frames", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_TX_AGGR_TIME_USECS] = { .name = "tx-aggr-time-usecs", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest ethtool_coalesce_nest = { - .max_attr = ETHTOOL_A_COALESCE_MAX, - .table = ethtool_coalesce_policy, -}; - -struct ynl_policy_attr ethtool_pause_policy[ETHTOOL_A_PAUSE_MAX + 1] = { - [ETHTOOL_A_PAUSE_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_PAUSE_AUTONEG] = { .name = "autoneg", .type = YNL_PT_U8, }, - [ETHTOOL_A_PAUSE_RX] = { .name = "rx", .type = YNL_PT_U8, }, - [ETHTOOL_A_PAUSE_TX] = { .name = "tx", .type = YNL_PT_U8, }, - [ETHTOOL_A_PAUSE_STATS] = { .name = "stats", .type = YNL_PT_NEST, .nest = ðtool_pause_stat_nest, }, - [ETHTOOL_A_PAUSE_STATS_SRC] = { .name = "stats-src", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest ethtool_pause_nest = { - .max_attr = ETHTOOL_A_PAUSE_MAX, - .table = ethtool_pause_policy, -}; - -struct ynl_policy_attr ethtool_eee_policy[ETHTOOL_A_EEE_MAX + 1] = { - [ETHTOOL_A_EEE_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_EEE_MODES_OURS] = { .name = "modes-ours", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, - [ETHTOOL_A_EEE_MODES_PEER] = { .name = "modes-peer", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, - [ETHTOOL_A_EEE_ACTIVE] = { .name = "active", .type = YNL_PT_U8, }, - [ETHTOOL_A_EEE_ENABLED] = { .name = "enabled", .type = YNL_PT_U8, }, - [ETHTOOL_A_EEE_TX_LPI_ENABLED] = { .name = "tx-lpi-enabled", .type = YNL_PT_U8, }, - [ETHTOOL_A_EEE_TX_LPI_TIMER] = { .name = "tx-lpi-timer", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest ethtool_eee_nest = { - .max_attr = ETHTOOL_A_EEE_MAX, - .table = ethtool_eee_policy, -}; - -struct ynl_policy_attr ethtool_tsinfo_policy[ETHTOOL_A_TSINFO_MAX + 1] = { - [ETHTOOL_A_TSINFO_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_TSINFO_TIMESTAMPING] = { .name = "timestamping", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, - [ETHTOOL_A_TSINFO_TX_TYPES] = { .name = "tx-types", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, - [ETHTOOL_A_TSINFO_RX_FILTERS] = { .name = "rx-filters", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, - [ETHTOOL_A_TSINFO_PHC_INDEX] = { .name = "phc-index", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest ethtool_tsinfo_nest = { - .max_attr = ETHTOOL_A_TSINFO_MAX, - .table = ethtool_tsinfo_policy, -}; - -struct ynl_policy_attr ethtool_cable_test_policy[ETHTOOL_A_CABLE_TEST_MAX + 1] = { - [ETHTOOL_A_CABLE_TEST_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, -}; - -struct ynl_policy_nest ethtool_cable_test_nest = { - .max_attr = ETHTOOL_A_CABLE_TEST_MAX, - .table = ethtool_cable_test_policy, -}; - -struct ynl_policy_attr ethtool_cable_test_ntf_policy[ETHTOOL_A_CABLE_TEST_NTF_MAX + 1] = { - [ETHTOOL_A_CABLE_TEST_NTF_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_CABLE_TEST_NTF_STATUS] = { .name = "status", .type = YNL_PT_U8, }, - [ETHTOOL_A_CABLE_TEST_NTF_NEST] = { .name = "nest", .type = YNL_PT_NEST, .nest = ðtool_cable_nest_nest, }, -}; - -struct ynl_policy_nest ethtool_cable_test_ntf_nest = { - .max_attr = ETHTOOL_A_CABLE_TEST_NTF_MAX, - .table = ethtool_cable_test_ntf_policy, -}; - -struct ynl_policy_attr ethtool_cable_test_tdr_policy[ETHTOOL_A_CABLE_TEST_TDR_MAX + 1] = { - [ETHTOOL_A_CABLE_TEST_TDR_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_CABLE_TEST_TDR_CFG] = { .name = "cfg", .type = YNL_PT_NEST, .nest = ðtool_cable_test_tdr_cfg_nest, }, -}; - -struct ynl_policy_nest ethtool_cable_test_tdr_nest = { - .max_attr = ETHTOOL_A_CABLE_TEST_TDR_MAX, - .table = ethtool_cable_test_tdr_policy, -}; - -struct ynl_policy_attr ethtool_cable_test_tdr_ntf_policy[ETHTOOL_A_CABLE_TEST_TDR_NTF_MAX + 1] = { - [ETHTOOL_A_CABLE_TEST_TDR_NTF_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_CABLE_TEST_TDR_NTF_STATUS] = { .name = "status", .type = YNL_PT_U8, }, - [ETHTOOL_A_CABLE_TEST_TDR_NTF_NEST] = { .name = "nest", .type = YNL_PT_NEST, .nest = ðtool_cable_nest_nest, }, -}; - -struct ynl_policy_nest ethtool_cable_test_tdr_ntf_nest = { - .max_attr = ETHTOOL_A_CABLE_TEST_TDR_NTF_MAX, - .table = ethtool_cable_test_tdr_ntf_policy, -}; - -struct ynl_policy_attr ethtool_tunnel_info_policy[ETHTOOL_A_TUNNEL_INFO_MAX + 1] = { - [ETHTOOL_A_TUNNEL_INFO_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_TUNNEL_INFO_UDP_PORTS] = { .name = "udp-ports", .type = YNL_PT_NEST, .nest = ðtool_tunnel_udp_nest, }, -}; - -struct ynl_policy_nest ethtool_tunnel_info_nest = { - .max_attr = ETHTOOL_A_TUNNEL_INFO_MAX, - .table = ethtool_tunnel_info_policy, -}; - -struct ynl_policy_attr ethtool_fec_policy[ETHTOOL_A_FEC_MAX + 1] = { - [ETHTOOL_A_FEC_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_FEC_MODES] = { .name = "modes", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, - [ETHTOOL_A_FEC_AUTO] = { .name = "auto", .type = YNL_PT_U8, }, - [ETHTOOL_A_FEC_ACTIVE] = { .name = "active", .type = YNL_PT_U32, }, - [ETHTOOL_A_FEC_STATS] = { .name = "stats", .type = YNL_PT_NEST, .nest = ðtool_fec_stat_nest, }, -}; - -struct ynl_policy_nest ethtool_fec_nest = { - .max_attr = ETHTOOL_A_FEC_MAX, - .table = ethtool_fec_policy, -}; - -struct ynl_policy_attr ethtool_module_eeprom_policy[ETHTOOL_A_MODULE_EEPROM_MAX + 1] = { - [ETHTOOL_A_MODULE_EEPROM_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_MODULE_EEPROM_OFFSET] = { .name = "offset", .type = YNL_PT_U32, }, - [ETHTOOL_A_MODULE_EEPROM_LENGTH] = { .name = "length", .type = YNL_PT_U32, }, - [ETHTOOL_A_MODULE_EEPROM_PAGE] = { .name = "page", .type = YNL_PT_U8, }, - [ETHTOOL_A_MODULE_EEPROM_BANK] = { .name = "bank", .type = YNL_PT_U8, }, - [ETHTOOL_A_MODULE_EEPROM_I2C_ADDRESS] = { .name = "i2c-address", .type = YNL_PT_U8, }, - [ETHTOOL_A_MODULE_EEPROM_DATA] = { .name = "data", .type = YNL_PT_BINARY,}, -}; - -struct ynl_policy_nest ethtool_module_eeprom_nest = { - .max_attr = ETHTOOL_A_MODULE_EEPROM_MAX, - .table = ethtool_module_eeprom_policy, -}; - -struct ynl_policy_attr ethtool_phc_vclocks_policy[ETHTOOL_A_PHC_VCLOCKS_MAX + 1] = { - [ETHTOOL_A_PHC_VCLOCKS_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_PHC_VCLOCKS_NUM] = { .name = "num", .type = YNL_PT_U32, }, - [ETHTOOL_A_PHC_VCLOCKS_INDEX] = { .name = "index", .type = YNL_PT_BINARY,}, -}; - -struct ynl_policy_nest ethtool_phc_vclocks_nest = { - .max_attr = ETHTOOL_A_PHC_VCLOCKS_MAX, - .table = ethtool_phc_vclocks_policy, -}; - -struct ynl_policy_attr ethtool_module_policy[ETHTOOL_A_MODULE_MAX + 1] = { - [ETHTOOL_A_MODULE_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_MODULE_POWER_MODE_POLICY] = { .name = "power-mode-policy", .type = YNL_PT_U8, }, - [ETHTOOL_A_MODULE_POWER_MODE] = { .name = "power-mode", .type = YNL_PT_U8, }, -}; - -struct ynl_policy_nest ethtool_module_nest = { - .max_attr = ETHTOOL_A_MODULE_MAX, - .table = ethtool_module_policy, -}; - -struct ynl_policy_attr ethtool_pse_policy[ETHTOOL_A_PSE_MAX + 1] = { - [ETHTOOL_A_PSE_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_PODL_PSE_ADMIN_STATE] = { .name = "admin-state", .type = YNL_PT_U32, }, - [ETHTOOL_A_PODL_PSE_ADMIN_CONTROL] = { .name = "admin-control", .type = YNL_PT_U32, }, - [ETHTOOL_A_PODL_PSE_PW_D_STATUS] = { .name = "pw-d-status", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest ethtool_pse_nest = { - .max_attr = ETHTOOL_A_PSE_MAX, - .table = ethtool_pse_policy, -}; - -struct ynl_policy_attr ethtool_rss_policy[ETHTOOL_A_RSS_MAX + 1] = { - [ETHTOOL_A_RSS_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_RSS_CONTEXT] = { .name = "context", .type = YNL_PT_U32, }, - [ETHTOOL_A_RSS_HFUNC] = { .name = "hfunc", .type = YNL_PT_U32, }, - [ETHTOOL_A_RSS_INDIR] = { .name = "indir", .type = YNL_PT_BINARY,}, - [ETHTOOL_A_RSS_HKEY] = { .name = "hkey", .type = YNL_PT_BINARY,}, -}; - -struct ynl_policy_nest ethtool_rss_nest = { - .max_attr = ETHTOOL_A_RSS_MAX, - .table = ethtool_rss_policy, -}; - -struct ynl_policy_attr ethtool_plca_policy[ETHTOOL_A_PLCA_MAX + 1] = { - [ETHTOOL_A_PLCA_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_PLCA_VERSION] = { .name = "version", .type = YNL_PT_U16, }, - [ETHTOOL_A_PLCA_ENABLED] = { .name = "enabled", .type = YNL_PT_U8, }, - [ETHTOOL_A_PLCA_STATUS] = { .name = "status", .type = YNL_PT_U8, }, - [ETHTOOL_A_PLCA_NODE_CNT] = { .name = "node-cnt", .type = YNL_PT_U32, }, - [ETHTOOL_A_PLCA_NODE_ID] = { .name = "node-id", .type = YNL_PT_U32, }, - [ETHTOOL_A_PLCA_TO_TMR] = { .name = "to-tmr", .type = YNL_PT_U32, }, - [ETHTOOL_A_PLCA_BURST_CNT] = { .name = "burst-cnt", .type = YNL_PT_U32, }, - [ETHTOOL_A_PLCA_BURST_TMR] = { .name = "burst-tmr", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest ethtool_plca_nest = { - .max_attr = ETHTOOL_A_PLCA_MAX, - .table = ethtool_plca_policy, -}; - -struct ynl_policy_attr ethtool_mm_policy[ETHTOOL_A_MM_MAX + 1] = { - [ETHTOOL_A_MM_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_MM_PMAC_ENABLED] = { .name = "pmac-enabled", .type = YNL_PT_U8, }, - [ETHTOOL_A_MM_TX_ENABLED] = { .name = "tx-enabled", .type = YNL_PT_U8, }, - [ETHTOOL_A_MM_TX_ACTIVE] = { .name = "tx-active", .type = YNL_PT_U8, }, - [ETHTOOL_A_MM_TX_MIN_FRAG_SIZE] = { .name = "tx-min-frag-size", .type = YNL_PT_U32, }, - [ETHTOOL_A_MM_RX_MIN_FRAG_SIZE] = { .name = "rx-min-frag-size", .type = YNL_PT_U32, }, - [ETHTOOL_A_MM_VERIFY_ENABLED] = { .name = "verify-enabled", .type = YNL_PT_U8, }, - [ETHTOOL_A_MM_VERIFY_STATUS] = { .name = "verify-status", .type = YNL_PT_U8, }, - [ETHTOOL_A_MM_VERIFY_TIME] = { .name = "verify-time", .type = YNL_PT_U32, }, - [ETHTOOL_A_MM_MAX_VERIFY_TIME] = { .name = "max-verify-time", .type = YNL_PT_U32, }, - [ETHTOOL_A_MM_STATS] = { .name = "stats", .type = YNL_PT_NEST, .nest = ðtool_mm_stat_nest, }, -}; - -struct ynl_policy_nest ethtool_mm_nest = { - .max_attr = ETHTOOL_A_MM_MAX, - .table = ethtool_mm_policy, -}; - -/* Common nested types */ -void ethtool_header_free(struct ethtool_header *obj) -{ - free(obj->dev_name); -} - -int ethtool_header_put(struct nlmsghdr *nlh, unsigned int attr_type, - struct ethtool_header *obj) -{ - struct nlattr *nest; - - nest = mnl_attr_nest_start(nlh, attr_type); - if (obj->_present.dev_index) - mnl_attr_put_u32(nlh, ETHTOOL_A_HEADER_DEV_INDEX, obj->dev_index); - if (obj->_present.dev_name_len) - mnl_attr_put_strz(nlh, ETHTOOL_A_HEADER_DEV_NAME, obj->dev_name); - if (obj->_present.flags) - mnl_attr_put_u32(nlh, ETHTOOL_A_HEADER_FLAGS, obj->flags); - mnl_attr_nest_end(nlh, nest); - - return 0; -} - -int ethtool_header_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_header *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_HEADER_DEV_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dev_index = 1; - dst->dev_index = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_HEADER_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == ETHTOOL_A_HEADER_FLAGS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.flags = 1; - dst->flags = mnl_attr_get_u32(attr); - } - } - - return 0; -} - -void ethtool_pause_stat_free(struct ethtool_pause_stat *obj) -{ -} - -int ethtool_pause_stat_put(struct nlmsghdr *nlh, unsigned int attr_type, - struct ethtool_pause_stat *obj) -{ - struct nlattr *nest; - - nest = mnl_attr_nest_start(nlh, attr_type); - if (obj->_present.tx_frames) - mnl_attr_put_u64(nlh, ETHTOOL_A_PAUSE_STAT_TX_FRAMES, obj->tx_frames); - if (obj->_present.rx_frames) - mnl_attr_put_u64(nlh, ETHTOOL_A_PAUSE_STAT_RX_FRAMES, obj->rx_frames); - mnl_attr_nest_end(nlh, nest); - - return 0; -} - -int ethtool_pause_stat_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_pause_stat *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_PAUSE_STAT_TX_FRAMES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_frames = 1; - dst->tx_frames = mnl_attr_get_u64(attr); - } else if (type == ETHTOOL_A_PAUSE_STAT_RX_FRAMES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_frames = 1; - dst->rx_frames = mnl_attr_get_u64(attr); - } - } - - return 0; -} - -void ethtool_cable_test_tdr_cfg_free(struct ethtool_cable_test_tdr_cfg *obj) -{ -} - -void ethtool_fec_stat_free(struct ethtool_fec_stat *obj) -{ - free(obj->corrected); - free(obj->uncorr); - free(obj->corr_bits); -} - -int ethtool_fec_stat_put(struct nlmsghdr *nlh, unsigned int attr_type, - struct ethtool_fec_stat *obj) -{ - struct nlattr *nest; - - nest = mnl_attr_nest_start(nlh, attr_type); - if (obj->_present.corrected_len) - mnl_attr_put(nlh, ETHTOOL_A_FEC_STAT_CORRECTED, obj->_present.corrected_len, obj->corrected); - if (obj->_present.uncorr_len) - mnl_attr_put(nlh, ETHTOOL_A_FEC_STAT_UNCORR, obj->_present.uncorr_len, obj->uncorr); - if (obj->_present.corr_bits_len) - mnl_attr_put(nlh, ETHTOOL_A_FEC_STAT_CORR_BITS, obj->_present.corr_bits_len, obj->corr_bits); - mnl_attr_nest_end(nlh, nest); - - return 0; -} - -int ethtool_fec_stat_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_fec_stat *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_FEC_STAT_CORRECTED) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = mnl_attr_get_payload_len(attr); - dst->_present.corrected_len = len; - dst->corrected = malloc(len); - memcpy(dst->corrected, mnl_attr_get_payload(attr), len); - } else if (type == ETHTOOL_A_FEC_STAT_UNCORR) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = mnl_attr_get_payload_len(attr); - dst->_present.uncorr_len = len; - dst->uncorr = malloc(len); - memcpy(dst->uncorr, mnl_attr_get_payload(attr), len); - } else if (type == ETHTOOL_A_FEC_STAT_CORR_BITS) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = mnl_attr_get_payload_len(attr); - dst->_present.corr_bits_len = len; - dst->corr_bits = malloc(len); - memcpy(dst->corr_bits, mnl_attr_get_payload(attr), len); - } - } - - return 0; -} - -void ethtool_mm_stat_free(struct ethtool_mm_stat *obj) -{ -} - -int ethtool_mm_stat_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_mm_stat *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_MM_STAT_REASSEMBLY_ERRORS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.reassembly_errors = 1; - dst->reassembly_errors = mnl_attr_get_u64(attr); - } else if (type == ETHTOOL_A_MM_STAT_SMD_ERRORS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.smd_errors = 1; - dst->smd_errors = mnl_attr_get_u64(attr); - } else if (type == ETHTOOL_A_MM_STAT_REASSEMBLY_OK) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.reassembly_ok = 1; - dst->reassembly_ok = mnl_attr_get_u64(attr); - } else if (type == ETHTOOL_A_MM_STAT_RX_FRAG_COUNT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_frag_count = 1; - dst->rx_frag_count = mnl_attr_get_u64(attr); - } else if (type == ETHTOOL_A_MM_STAT_TX_FRAG_COUNT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_frag_count = 1; - dst->tx_frag_count = mnl_attr_get_u64(attr); - } else if (type == ETHTOOL_A_MM_STAT_HOLD_COUNT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.hold_count = 1; - dst->hold_count = mnl_attr_get_u64(attr); - } - } - - return 0; -} - -void ethtool_cable_result_free(struct ethtool_cable_result *obj) -{ -} - -int ethtool_cable_result_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_cable_result *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_CABLE_RESULT_PAIR) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.pair = 1; - dst->pair = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_CABLE_RESULT_CODE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.code = 1; - dst->code = mnl_attr_get_u8(attr); - } - } - - return 0; -} - -void ethtool_cable_fault_length_free(struct ethtool_cable_fault_length *obj) -{ -} - -int ethtool_cable_fault_length_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_cable_fault_length *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_CABLE_FAULT_LENGTH_PAIR) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.pair = 1; - dst->pair = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_CABLE_FAULT_LENGTH_CM) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.cm = 1; - dst->cm = mnl_attr_get_u32(attr); - } - } - - return 0; -} - -void ethtool_bitset_bit_free(struct ethtool_bitset_bit *obj) -{ - free(obj->name); -} - -int ethtool_bitset_bit_put(struct nlmsghdr *nlh, unsigned int attr_type, - struct ethtool_bitset_bit *obj) -{ - struct nlattr *nest; - - nest = mnl_attr_nest_start(nlh, attr_type); - if (obj->_present.index) - mnl_attr_put_u32(nlh, ETHTOOL_A_BITSET_BIT_INDEX, obj->index); - if (obj->_present.name_len) - mnl_attr_put_strz(nlh, ETHTOOL_A_BITSET_BIT_NAME, obj->name); - if (obj->_present.value) - mnl_attr_put(nlh, ETHTOOL_A_BITSET_BIT_VALUE, 0, NULL); - mnl_attr_nest_end(nlh, nest); - - return 0; -} - -int ethtool_bitset_bit_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_bitset_bit *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_BITSET_BIT_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.index = 1; - dst->index = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_BITSET_BIT_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.name_len = len; - dst->name = malloc(len + 1); - memcpy(dst->name, mnl_attr_get_str(attr), len); - dst->name[len] = 0; - } else if (type == ETHTOOL_A_BITSET_BIT_VALUE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.value = 1; - } - } - - return 0; -} - -void ethtool_tunnel_udp_entry_free(struct ethtool_tunnel_udp_entry *obj) -{ -} - -int ethtool_tunnel_udp_entry_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_tunnel_udp_entry *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_TUNNEL_UDP_ENTRY_PORT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.port = 1; - dst->port = mnl_attr_get_u16(attr); - } else if (type == ETHTOOL_A_TUNNEL_UDP_ENTRY_TYPE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.type = 1; - dst->type = mnl_attr_get_u32(attr); - } - } - - return 0; -} - -void ethtool_string_free(struct ethtool_string *obj) -{ - free(obj->value); -} - -int ethtool_string_put(struct nlmsghdr *nlh, unsigned int attr_type, - struct ethtool_string *obj) -{ - struct nlattr *nest; - - nest = mnl_attr_nest_start(nlh, attr_type); - if (obj->_present.index) - mnl_attr_put_u32(nlh, ETHTOOL_A_STRING_INDEX, obj->index); - if (obj->_present.value_len) - mnl_attr_put_strz(nlh, ETHTOOL_A_STRING_VALUE, obj->value); - mnl_attr_nest_end(nlh, nest); - - return 0; -} - -int ethtool_string_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_string *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_STRING_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.index = 1; - dst->index = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_STRING_VALUE) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.value_len = len; - dst->value = malloc(len + 1); - memcpy(dst->value, mnl_attr_get_str(attr), len); - dst->value[len] = 0; - } - } - - return 0; -} - -void ethtool_cable_nest_free(struct ethtool_cable_nest *obj) -{ - ethtool_cable_result_free(&obj->result); - ethtool_cable_fault_length_free(&obj->fault_length); -} - -int ethtool_cable_nest_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_cable_nest *dst = yarg->data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - parg.ys = yarg->ys; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_CABLE_NEST_RESULT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.result = 1; - - parg.rsp_policy = ðtool_cable_result_nest; - parg.data = &dst->result; - if (ethtool_cable_result_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_CABLE_NEST_FAULT_LENGTH) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.fault_length = 1; - - parg.rsp_policy = ðtool_cable_fault_length_nest; - parg.data = &dst->fault_length; - if (ethtool_cable_fault_length_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return 0; -} - -void ethtool_bitset_bits_free(struct ethtool_bitset_bits *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_bit; i++) - ethtool_bitset_bit_free(&obj->bit[i]); - free(obj->bit); -} - -int ethtool_bitset_bits_put(struct nlmsghdr *nlh, unsigned int attr_type, - struct ethtool_bitset_bits *obj) -{ - struct nlattr *nest; - - nest = mnl_attr_nest_start(nlh, attr_type); - for (unsigned int i = 0; i < obj->n_bit; i++) - ethtool_bitset_bit_put(nlh, ETHTOOL_A_BITSET_BITS_BIT, &obj->bit[i]); - mnl_attr_nest_end(nlh, nest); - - return 0; -} - -int ethtool_bitset_bits_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_bitset_bits *dst = yarg->data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - unsigned int n_bit = 0; - int i; - - parg.ys = yarg->ys; - - if (dst->bit) - return ynl_error_parse(yarg, "attribute already present (bitset-bits.bit)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_BITSET_BITS_BIT) { - n_bit++; - } - } - - if (n_bit) { - dst->bit = calloc(n_bit, sizeof(*dst->bit)); - dst->n_bit = n_bit; - i = 0; - parg.rsp_policy = ðtool_bitset_bit_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == ETHTOOL_A_BITSET_BITS_BIT) { - parg.data = &dst->bit[i]; - if (ethtool_bitset_bit_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void ethtool_strings_free(struct ethtool_strings *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_string; i++) - ethtool_string_free(&obj->string[i]); - free(obj->string); -} - -int ethtool_strings_put(struct nlmsghdr *nlh, unsigned int attr_type, - struct ethtool_strings *obj) -{ - struct nlattr *nest; - - nest = mnl_attr_nest_start(nlh, attr_type); - for (unsigned int i = 0; i < obj->n_string; i++) - ethtool_string_put(nlh, ETHTOOL_A_STRINGS_STRING, &obj->string[i]); - mnl_attr_nest_end(nlh, nest); - - return 0; -} - -int ethtool_strings_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_strings *dst = yarg->data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - unsigned int n_string = 0; - int i; - - parg.ys = yarg->ys; - - if (dst->string) - return ynl_error_parse(yarg, "attribute already present (strings.string)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_STRINGS_STRING) { - n_string++; - } - } - - if (n_string) { - dst->string = calloc(n_string, sizeof(*dst->string)); - dst->n_string = n_string; - i = 0; - parg.rsp_policy = ðtool_string_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == ETHTOOL_A_STRINGS_STRING) { - parg.data = &dst->string[i]; - if (ethtool_string_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void ethtool_bitset_free(struct ethtool_bitset *obj) -{ - ethtool_bitset_bits_free(&obj->bits); -} - -int ethtool_bitset_put(struct nlmsghdr *nlh, unsigned int attr_type, - struct ethtool_bitset *obj) -{ - struct nlattr *nest; - - nest = mnl_attr_nest_start(nlh, attr_type); - if (obj->_present.nomask) - mnl_attr_put(nlh, ETHTOOL_A_BITSET_NOMASK, 0, NULL); - if (obj->_present.size) - mnl_attr_put_u32(nlh, ETHTOOL_A_BITSET_SIZE, obj->size); - if (obj->_present.bits) - ethtool_bitset_bits_put(nlh, ETHTOOL_A_BITSET_BITS, &obj->bits); - mnl_attr_nest_end(nlh, nest); - - return 0; -} - -int ethtool_bitset_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_bitset *dst = yarg->data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - parg.ys = yarg->ys; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_BITSET_NOMASK) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.nomask = 1; - } else if (type == ETHTOOL_A_BITSET_SIZE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.size = 1; - dst->size = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_BITSET_BITS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.bits = 1; - - parg.rsp_policy = ðtool_bitset_bits_nest; - parg.data = &dst->bits; - if (ethtool_bitset_bits_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return 0; -} - -void ethtool_stringset_free(struct ethtool_stringset_ *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_strings; i++) - ethtool_strings_free(&obj->strings[i]); - free(obj->strings); -} - -int ethtool_stringset_put(struct nlmsghdr *nlh, unsigned int attr_type, - struct ethtool_stringset_ *obj) -{ - struct nlattr *nest; - - nest = mnl_attr_nest_start(nlh, attr_type); - if (obj->_present.id) - mnl_attr_put_u32(nlh, ETHTOOL_A_STRINGSET_ID, obj->id); - if (obj->_present.count) - mnl_attr_put_u32(nlh, ETHTOOL_A_STRINGSET_COUNT, obj->count); - for (unsigned int i = 0; i < obj->n_strings; i++) - ethtool_strings_put(nlh, ETHTOOL_A_STRINGSET_STRINGS, &obj->strings[i]); - mnl_attr_nest_end(nlh, nest); - - return 0; -} - -int ethtool_stringset_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_stringset_ *dst = yarg->data; - unsigned int n_strings = 0; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - parg.ys = yarg->ys; - - if (dst->strings) - return ynl_error_parse(yarg, "attribute already present (stringset.strings)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_STRINGSET_ID) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.id = 1; - dst->id = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_STRINGSET_COUNT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.count = 1; - dst->count = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_STRINGSET_STRINGS) { - n_strings++; - } - } - - if (n_strings) { - dst->strings = calloc(n_strings, sizeof(*dst->strings)); - dst->n_strings = n_strings; - i = 0; - parg.rsp_policy = ðtool_strings_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == ETHTOOL_A_STRINGSET_STRINGS) { - parg.data = &dst->strings[i]; - if (ethtool_strings_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void ethtool_tunnel_udp_table_free(struct ethtool_tunnel_udp_table *obj) -{ - unsigned int i; - - ethtool_bitset_free(&obj->types); - for (i = 0; i < obj->n_entry; i++) - ethtool_tunnel_udp_entry_free(&obj->entry[i]); - free(obj->entry); -} - -int ethtool_tunnel_udp_table_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_tunnel_udp_table *dst = yarg->data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - unsigned int n_entry = 0; - int i; - - parg.ys = yarg->ys; - - if (dst->entry) - return ynl_error_parse(yarg, "attribute already present (tunnel-udp-table.entry)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_TUNNEL_UDP_TABLE_SIZE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.size = 1; - dst->size = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_TUNNEL_UDP_TABLE_TYPES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.types = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->types; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_TUNNEL_UDP_TABLE_ENTRY) { - n_entry++; - } - } - - if (n_entry) { - dst->entry = calloc(n_entry, sizeof(*dst->entry)); - dst->n_entry = n_entry; - i = 0; - parg.rsp_policy = ðtool_tunnel_udp_entry_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == ETHTOOL_A_TUNNEL_UDP_TABLE_ENTRY) { - parg.data = &dst->entry[i]; - if (ethtool_tunnel_udp_entry_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void ethtool_stringsets_free(struct ethtool_stringsets *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_stringset; i++) - ethtool_stringset_free(&obj->stringset[i]); - free(obj->stringset); -} - -int ethtool_stringsets_put(struct nlmsghdr *nlh, unsigned int attr_type, - struct ethtool_stringsets *obj) -{ - struct nlattr *nest; - - nest = mnl_attr_nest_start(nlh, attr_type); - for (unsigned int i = 0; i < obj->n_stringset; i++) - ethtool_stringset_put(nlh, ETHTOOL_A_STRINGSETS_STRINGSET, &obj->stringset[i]); - mnl_attr_nest_end(nlh, nest); - - return 0; -} - -int ethtool_stringsets_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_stringsets *dst = yarg->data; - unsigned int n_stringset = 0; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - parg.ys = yarg->ys; - - if (dst->stringset) - return ynl_error_parse(yarg, "attribute already present (stringsets.stringset)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_STRINGSETS_STRINGSET) { - n_stringset++; - } - } - - if (n_stringset) { - dst->stringset = calloc(n_stringset, sizeof(*dst->stringset)); - dst->n_stringset = n_stringset; - i = 0; - parg.rsp_policy = ðtool_stringset_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == ETHTOOL_A_STRINGSETS_STRINGSET) { - parg.data = &dst->stringset[i]; - if (ethtool_stringset_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void ethtool_tunnel_udp_free(struct ethtool_tunnel_udp *obj) -{ - ethtool_tunnel_udp_table_free(&obj->table); -} - -int ethtool_tunnel_udp_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_tunnel_udp *dst = yarg->data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - parg.ys = yarg->ys; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_TUNNEL_UDP_TABLE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.table = 1; - - parg.rsp_policy = ðtool_tunnel_udp_table_nest; - parg.data = &dst->table; - if (ethtool_tunnel_udp_table_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return 0; -} - -/* ============== ETHTOOL_MSG_STRSET_GET ============== */ -/* ETHTOOL_MSG_STRSET_GET - do */ -void ethtool_strset_get_req_free(struct ethtool_strset_get_req *req) -{ - ethtool_header_free(&req->header); - ethtool_stringsets_free(&req->stringsets); - free(req); -} - -void ethtool_strset_get_rsp_free(struct ethtool_strset_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - ethtool_stringsets_free(&rsp->stringsets); - free(rsp); -} - -int ethtool_strset_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_strset_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_STRSET_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_STRSET_STRINGSETS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.stringsets = 1; - - parg.rsp_policy = ðtool_stringsets_nest; - parg.data = &dst->stringsets; - if (ethtool_stringsets_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return MNL_CB_OK; -} - -struct ethtool_strset_get_rsp * -ethtool_strset_get(struct ynl_sock *ys, struct ethtool_strset_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_strset_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_STRSET_GET, 1); - ys->req_policy = ðtool_strset_nest; - yrs.yarg.rsp_policy = ðtool_strset_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_STRSET_HEADER, &req->header); - if (req->_present.stringsets) - ethtool_stringsets_put(nlh, ETHTOOL_A_STRSET_STRINGSETS, &req->stringsets); - if (req->_present.counts_only) - mnl_attr_put(nlh, ETHTOOL_A_STRSET_COUNTS_ONLY, 0, NULL); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_strset_get_rsp_parse; - yrs.rsp_cmd = ETHTOOL_MSG_STRSET_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_strset_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_STRSET_GET - dump */ -void ethtool_strset_get_list_free(struct ethtool_strset_get_list *rsp) -{ - struct ethtool_strset_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - ethtool_stringsets_free(&rsp->obj.stringsets); - free(rsp); - } -} - -struct ethtool_strset_get_list * -ethtool_strset_get_dump(struct ynl_sock *ys, - struct ethtool_strset_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_strset_get_list); - yds.cb = ethtool_strset_get_rsp_parse; - yds.rsp_cmd = ETHTOOL_MSG_STRSET_GET; - yds.rsp_policy = ðtool_strset_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_STRSET_GET, 1); - ys->req_policy = ðtool_strset_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_STRSET_HEADER, &req->header); - if (req->_present.stringsets) - ethtool_stringsets_put(nlh, ETHTOOL_A_STRSET_STRINGSETS, &req->stringsets); - if (req->_present.counts_only) - mnl_attr_put(nlh, ETHTOOL_A_STRSET_COUNTS_ONLY, 0, NULL); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_strset_get_list_free(yds.first); - return NULL; -} - -/* ============== ETHTOOL_MSG_LINKINFO_GET ============== */ -/* ETHTOOL_MSG_LINKINFO_GET - do */ -void ethtool_linkinfo_get_req_free(struct ethtool_linkinfo_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_linkinfo_get_rsp_free(struct ethtool_linkinfo_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - free(rsp); -} - -int ethtool_linkinfo_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_linkinfo_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_LINKINFO_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_LINKINFO_PORT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.port = 1; - dst->port = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_LINKINFO_PHYADDR) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.phyaddr = 1; - dst->phyaddr = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_LINKINFO_TP_MDIX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tp_mdix = 1; - dst->tp_mdix = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_LINKINFO_TP_MDIX_CTRL) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tp_mdix_ctrl = 1; - dst->tp_mdix_ctrl = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_LINKINFO_TRANSCEIVER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.transceiver = 1; - dst->transceiver = mnl_attr_get_u8(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_linkinfo_get_rsp * -ethtool_linkinfo_get(struct ynl_sock *ys, struct ethtool_linkinfo_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_linkinfo_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_LINKINFO_GET, 1); - ys->req_policy = ðtool_linkinfo_nest; - yrs.yarg.rsp_policy = ðtool_linkinfo_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_LINKINFO_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_linkinfo_get_rsp_parse; - yrs.rsp_cmd = ETHTOOL_MSG_LINKINFO_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_linkinfo_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_LINKINFO_GET - dump */ -void ethtool_linkinfo_get_list_free(struct ethtool_linkinfo_get_list *rsp) -{ - struct ethtool_linkinfo_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - free(rsp); - } -} - -struct ethtool_linkinfo_get_list * -ethtool_linkinfo_get_dump(struct ynl_sock *ys, - struct ethtool_linkinfo_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_linkinfo_get_list); - yds.cb = ethtool_linkinfo_get_rsp_parse; - yds.rsp_cmd = ETHTOOL_MSG_LINKINFO_GET; - yds.rsp_policy = ðtool_linkinfo_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_LINKINFO_GET, 1); - ys->req_policy = ðtool_linkinfo_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_LINKINFO_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_linkinfo_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_LINKINFO_GET - notify */ -void ethtool_linkinfo_get_ntf_free(struct ethtool_linkinfo_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - free(rsp); -} - -/* ============== ETHTOOL_MSG_LINKINFO_SET ============== */ -/* ETHTOOL_MSG_LINKINFO_SET - do */ -void ethtool_linkinfo_set_req_free(struct ethtool_linkinfo_set_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -int ethtool_linkinfo_set(struct ynl_sock *ys, - struct ethtool_linkinfo_set_req *req) -{ - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_LINKINFO_SET, 1); - ys->req_policy = ðtool_linkinfo_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_LINKINFO_HEADER, &req->header); - if (req->_present.port) - mnl_attr_put_u8(nlh, ETHTOOL_A_LINKINFO_PORT, req->port); - if (req->_present.phyaddr) - mnl_attr_put_u8(nlh, ETHTOOL_A_LINKINFO_PHYADDR, req->phyaddr); - if (req->_present.tp_mdix) - mnl_attr_put_u8(nlh, ETHTOOL_A_LINKINFO_TP_MDIX, req->tp_mdix); - if (req->_present.tp_mdix_ctrl) - mnl_attr_put_u8(nlh, ETHTOOL_A_LINKINFO_TP_MDIX_CTRL, req->tp_mdix_ctrl); - if (req->_present.transceiver) - mnl_attr_put_u8(nlh, ETHTOOL_A_LINKINFO_TRANSCEIVER, req->transceiver); - - err = ynl_exec(ys, nlh, NULL); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_LINKMODES_GET ============== */ -/* ETHTOOL_MSG_LINKMODES_GET - do */ -void ethtool_linkmodes_get_req_free(struct ethtool_linkmodes_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_linkmodes_get_rsp_free(struct ethtool_linkmodes_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - ethtool_bitset_free(&rsp->ours); - ethtool_bitset_free(&rsp->peer); - free(rsp); -} - -int ethtool_linkmodes_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_linkmodes_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_LINKMODES_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_LINKMODES_AUTONEG) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.autoneg = 1; - dst->autoneg = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_LINKMODES_OURS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.ours = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->ours; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_LINKMODES_PEER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.peer = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->peer; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_LINKMODES_SPEED) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.speed = 1; - dst->speed = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_LINKMODES_DUPLEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.duplex = 1; - dst->duplex = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.master_slave_cfg = 1; - dst->master_slave_cfg = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_LINKMODES_MASTER_SLAVE_STATE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.master_slave_state = 1; - dst->master_slave_state = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_LINKMODES_LANES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.lanes = 1; - dst->lanes = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_LINKMODES_RATE_MATCHING) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rate_matching = 1; - dst->rate_matching = mnl_attr_get_u8(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_linkmodes_get_rsp * -ethtool_linkmodes_get(struct ynl_sock *ys, - struct ethtool_linkmodes_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_linkmodes_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_LINKMODES_GET, 1); - ys->req_policy = ðtool_linkmodes_nest; - yrs.yarg.rsp_policy = ðtool_linkmodes_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_LINKMODES_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_linkmodes_get_rsp_parse; - yrs.rsp_cmd = ETHTOOL_MSG_LINKMODES_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_linkmodes_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_LINKMODES_GET - dump */ -void ethtool_linkmodes_get_list_free(struct ethtool_linkmodes_get_list *rsp) -{ - struct ethtool_linkmodes_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.ours); - ethtool_bitset_free(&rsp->obj.peer); - free(rsp); - } -} - -struct ethtool_linkmodes_get_list * -ethtool_linkmodes_get_dump(struct ynl_sock *ys, - struct ethtool_linkmodes_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_linkmodes_get_list); - yds.cb = ethtool_linkmodes_get_rsp_parse; - yds.rsp_cmd = ETHTOOL_MSG_LINKMODES_GET; - yds.rsp_policy = ðtool_linkmodes_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_LINKMODES_GET, 1); - ys->req_policy = ðtool_linkmodes_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_LINKMODES_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_linkmodes_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_LINKMODES_GET - notify */ -void ethtool_linkmodes_get_ntf_free(struct ethtool_linkmodes_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.ours); - ethtool_bitset_free(&rsp->obj.peer); - free(rsp); -} - -/* ============== ETHTOOL_MSG_LINKMODES_SET ============== */ -/* ETHTOOL_MSG_LINKMODES_SET - do */ -void ethtool_linkmodes_set_req_free(struct ethtool_linkmodes_set_req *req) -{ - ethtool_header_free(&req->header); - ethtool_bitset_free(&req->ours); - ethtool_bitset_free(&req->peer); - free(req); -} - -int ethtool_linkmodes_set(struct ynl_sock *ys, - struct ethtool_linkmodes_set_req *req) -{ - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_LINKMODES_SET, 1); - ys->req_policy = ðtool_linkmodes_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_LINKMODES_HEADER, &req->header); - if (req->_present.autoneg) - mnl_attr_put_u8(nlh, ETHTOOL_A_LINKMODES_AUTONEG, req->autoneg); - if (req->_present.ours) - ethtool_bitset_put(nlh, ETHTOOL_A_LINKMODES_OURS, &req->ours); - if (req->_present.peer) - ethtool_bitset_put(nlh, ETHTOOL_A_LINKMODES_PEER, &req->peer); - if (req->_present.speed) - mnl_attr_put_u32(nlh, ETHTOOL_A_LINKMODES_SPEED, req->speed); - if (req->_present.duplex) - mnl_attr_put_u8(nlh, ETHTOOL_A_LINKMODES_DUPLEX, req->duplex); - if (req->_present.master_slave_cfg) - mnl_attr_put_u8(nlh, ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG, req->master_slave_cfg); - if (req->_present.master_slave_state) - mnl_attr_put_u8(nlh, ETHTOOL_A_LINKMODES_MASTER_SLAVE_STATE, req->master_slave_state); - if (req->_present.lanes) - mnl_attr_put_u32(nlh, ETHTOOL_A_LINKMODES_LANES, req->lanes); - if (req->_present.rate_matching) - mnl_attr_put_u8(nlh, ETHTOOL_A_LINKMODES_RATE_MATCHING, req->rate_matching); - - err = ynl_exec(ys, nlh, NULL); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_LINKSTATE_GET ============== */ -/* ETHTOOL_MSG_LINKSTATE_GET - do */ -void ethtool_linkstate_get_req_free(struct ethtool_linkstate_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_linkstate_get_rsp_free(struct ethtool_linkstate_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - free(rsp); -} - -int ethtool_linkstate_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_linkstate_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_LINKSTATE_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_LINKSTATE_LINK) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.link = 1; - dst->link = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_LINKSTATE_SQI) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.sqi = 1; - dst->sqi = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_LINKSTATE_SQI_MAX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.sqi_max = 1; - dst->sqi_max = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_LINKSTATE_EXT_STATE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.ext_state = 1; - dst->ext_state = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_LINKSTATE_EXT_SUBSTATE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.ext_substate = 1; - dst->ext_substate = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_LINKSTATE_EXT_DOWN_CNT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.ext_down_cnt = 1; - dst->ext_down_cnt = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_linkstate_get_rsp * -ethtool_linkstate_get(struct ynl_sock *ys, - struct ethtool_linkstate_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_linkstate_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_LINKSTATE_GET, 1); - ys->req_policy = ðtool_linkstate_nest; - yrs.yarg.rsp_policy = ðtool_linkstate_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_LINKSTATE_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_linkstate_get_rsp_parse; - yrs.rsp_cmd = ETHTOOL_MSG_LINKSTATE_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_linkstate_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_LINKSTATE_GET - dump */ -void ethtool_linkstate_get_list_free(struct ethtool_linkstate_get_list *rsp) -{ - struct ethtool_linkstate_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - free(rsp); - } -} - -struct ethtool_linkstate_get_list * -ethtool_linkstate_get_dump(struct ynl_sock *ys, - struct ethtool_linkstate_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_linkstate_get_list); - yds.cb = ethtool_linkstate_get_rsp_parse; - yds.rsp_cmd = ETHTOOL_MSG_LINKSTATE_GET; - yds.rsp_policy = ðtool_linkstate_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_LINKSTATE_GET, 1); - ys->req_policy = ðtool_linkstate_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_LINKSTATE_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_linkstate_get_list_free(yds.first); - return NULL; -} - -/* ============== ETHTOOL_MSG_DEBUG_GET ============== */ -/* ETHTOOL_MSG_DEBUG_GET - do */ -void ethtool_debug_get_req_free(struct ethtool_debug_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_debug_get_rsp_free(struct ethtool_debug_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - ethtool_bitset_free(&rsp->msgmask); - free(rsp); -} - -int ethtool_debug_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_debug_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_DEBUG_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_DEBUG_MSGMASK) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.msgmask = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->msgmask; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return MNL_CB_OK; -} - -struct ethtool_debug_get_rsp * -ethtool_debug_get(struct ynl_sock *ys, struct ethtool_debug_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_debug_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_DEBUG_GET, 1); - ys->req_policy = ðtool_debug_nest; - yrs.yarg.rsp_policy = ðtool_debug_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_DEBUG_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_debug_get_rsp_parse; - yrs.rsp_cmd = ETHTOOL_MSG_DEBUG_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_debug_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_DEBUG_GET - dump */ -void ethtool_debug_get_list_free(struct ethtool_debug_get_list *rsp) -{ - struct ethtool_debug_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.msgmask); - free(rsp); - } -} - -struct ethtool_debug_get_list * -ethtool_debug_get_dump(struct ynl_sock *ys, - struct ethtool_debug_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_debug_get_list); - yds.cb = ethtool_debug_get_rsp_parse; - yds.rsp_cmd = ETHTOOL_MSG_DEBUG_GET; - yds.rsp_policy = ðtool_debug_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_DEBUG_GET, 1); - ys->req_policy = ðtool_debug_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_DEBUG_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_debug_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_DEBUG_GET - notify */ -void ethtool_debug_get_ntf_free(struct ethtool_debug_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.msgmask); - free(rsp); -} - -/* ============== ETHTOOL_MSG_DEBUG_SET ============== */ -/* ETHTOOL_MSG_DEBUG_SET - do */ -void ethtool_debug_set_req_free(struct ethtool_debug_set_req *req) -{ - ethtool_header_free(&req->header); - ethtool_bitset_free(&req->msgmask); - free(req); -} - -int ethtool_debug_set(struct ynl_sock *ys, struct ethtool_debug_set_req *req) -{ - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_DEBUG_SET, 1); - ys->req_policy = ðtool_debug_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_DEBUG_HEADER, &req->header); - if (req->_present.msgmask) - ethtool_bitset_put(nlh, ETHTOOL_A_DEBUG_MSGMASK, &req->msgmask); - - err = ynl_exec(ys, nlh, NULL); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_WOL_GET ============== */ -/* ETHTOOL_MSG_WOL_GET - do */ -void ethtool_wol_get_req_free(struct ethtool_wol_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_wol_get_rsp_free(struct ethtool_wol_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - ethtool_bitset_free(&rsp->modes); - free(rsp->sopass); - free(rsp); -} - -int ethtool_wol_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct ethtool_wol_get_rsp *dst; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_WOL_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_WOL_MODES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.modes = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->modes; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_WOL_SOPASS) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = mnl_attr_get_payload_len(attr); - dst->_present.sopass_len = len; - dst->sopass = malloc(len); - memcpy(dst->sopass, mnl_attr_get_payload(attr), len); - } - } - - return MNL_CB_OK; -} - -struct ethtool_wol_get_rsp * -ethtool_wol_get(struct ynl_sock *ys, struct ethtool_wol_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_wol_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_WOL_GET, 1); - ys->req_policy = ðtool_wol_nest; - yrs.yarg.rsp_policy = ðtool_wol_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_WOL_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_wol_get_rsp_parse; - yrs.rsp_cmd = ETHTOOL_MSG_WOL_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_wol_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_WOL_GET - dump */ -void ethtool_wol_get_list_free(struct ethtool_wol_get_list *rsp) -{ - struct ethtool_wol_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.modes); - free(rsp->obj.sopass); - free(rsp); - } -} - -struct ethtool_wol_get_list * -ethtool_wol_get_dump(struct ynl_sock *ys, struct ethtool_wol_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_wol_get_list); - yds.cb = ethtool_wol_get_rsp_parse; - yds.rsp_cmd = ETHTOOL_MSG_WOL_GET; - yds.rsp_policy = ðtool_wol_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_WOL_GET, 1); - ys->req_policy = ðtool_wol_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_WOL_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_wol_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_WOL_GET - notify */ -void ethtool_wol_get_ntf_free(struct ethtool_wol_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.modes); - free(rsp->obj.sopass); - free(rsp); -} - -/* ============== ETHTOOL_MSG_WOL_SET ============== */ -/* ETHTOOL_MSG_WOL_SET - do */ -void ethtool_wol_set_req_free(struct ethtool_wol_set_req *req) -{ - ethtool_header_free(&req->header); - ethtool_bitset_free(&req->modes); - free(req->sopass); - free(req); -} - -int ethtool_wol_set(struct ynl_sock *ys, struct ethtool_wol_set_req *req) -{ - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_WOL_SET, 1); - ys->req_policy = ðtool_wol_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_WOL_HEADER, &req->header); - if (req->_present.modes) - ethtool_bitset_put(nlh, ETHTOOL_A_WOL_MODES, &req->modes); - if (req->_present.sopass_len) - mnl_attr_put(nlh, ETHTOOL_A_WOL_SOPASS, req->_present.sopass_len, req->sopass); - - err = ynl_exec(ys, nlh, NULL); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_FEATURES_GET ============== */ -/* ETHTOOL_MSG_FEATURES_GET - do */ -void ethtool_features_get_req_free(struct ethtool_features_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_features_get_rsp_free(struct ethtool_features_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - ethtool_bitset_free(&rsp->hw); - ethtool_bitset_free(&rsp->wanted); - ethtool_bitset_free(&rsp->active); - ethtool_bitset_free(&rsp->nochange); - free(rsp); -} - -int ethtool_features_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_features_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_FEATURES_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_FEATURES_HW) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.hw = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->hw; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_FEATURES_WANTED) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.wanted = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->wanted; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_FEATURES_ACTIVE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.active = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->active; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_FEATURES_NOCHANGE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.nochange = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->nochange; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return MNL_CB_OK; -} - -struct ethtool_features_get_rsp * -ethtool_features_get(struct ynl_sock *ys, struct ethtool_features_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_features_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_FEATURES_GET, 1); - ys->req_policy = ðtool_features_nest; - yrs.yarg.rsp_policy = ðtool_features_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_FEATURES_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_features_get_rsp_parse; - yrs.rsp_cmd = ETHTOOL_MSG_FEATURES_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_features_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_FEATURES_GET - dump */ -void ethtool_features_get_list_free(struct ethtool_features_get_list *rsp) -{ - struct ethtool_features_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.hw); - ethtool_bitset_free(&rsp->obj.wanted); - ethtool_bitset_free(&rsp->obj.active); - ethtool_bitset_free(&rsp->obj.nochange); - free(rsp); - } -} - -struct ethtool_features_get_list * -ethtool_features_get_dump(struct ynl_sock *ys, - struct ethtool_features_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_features_get_list); - yds.cb = ethtool_features_get_rsp_parse; - yds.rsp_cmd = ETHTOOL_MSG_FEATURES_GET; - yds.rsp_policy = ðtool_features_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_FEATURES_GET, 1); - ys->req_policy = ðtool_features_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_FEATURES_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_features_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_FEATURES_GET - notify */ -void ethtool_features_get_ntf_free(struct ethtool_features_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.hw); - ethtool_bitset_free(&rsp->obj.wanted); - ethtool_bitset_free(&rsp->obj.active); - ethtool_bitset_free(&rsp->obj.nochange); - free(rsp); -} - -/* ============== ETHTOOL_MSG_FEATURES_SET ============== */ -/* ETHTOOL_MSG_FEATURES_SET - do */ -void ethtool_features_set_req_free(struct ethtool_features_set_req *req) -{ - ethtool_header_free(&req->header); - ethtool_bitset_free(&req->hw); - ethtool_bitset_free(&req->wanted); - ethtool_bitset_free(&req->active); - ethtool_bitset_free(&req->nochange); - free(req); -} - -void ethtool_features_set_rsp_free(struct ethtool_features_set_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - ethtool_bitset_free(&rsp->hw); - ethtool_bitset_free(&rsp->wanted); - ethtool_bitset_free(&rsp->active); - ethtool_bitset_free(&rsp->nochange); - free(rsp); -} - -int ethtool_features_set_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_features_set_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_FEATURES_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_FEATURES_HW) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.hw = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->hw; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_FEATURES_WANTED) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.wanted = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->wanted; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_FEATURES_ACTIVE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.active = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->active; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_FEATURES_NOCHANGE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.nochange = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->nochange; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return MNL_CB_OK; -} - -struct ethtool_features_set_rsp * -ethtool_features_set(struct ynl_sock *ys, struct ethtool_features_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_features_set_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_FEATURES_SET, 1); - ys->req_policy = ðtool_features_nest; - yrs.yarg.rsp_policy = ðtool_features_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_FEATURES_HEADER, &req->header); - if (req->_present.hw) - ethtool_bitset_put(nlh, ETHTOOL_A_FEATURES_HW, &req->hw); - if (req->_present.wanted) - ethtool_bitset_put(nlh, ETHTOOL_A_FEATURES_WANTED, &req->wanted); - if (req->_present.active) - ethtool_bitset_put(nlh, ETHTOOL_A_FEATURES_ACTIVE, &req->active); - if (req->_present.nochange) - ethtool_bitset_put(nlh, ETHTOOL_A_FEATURES_NOCHANGE, &req->nochange); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_features_set_rsp_parse; - yrs.rsp_cmd = ETHTOOL_MSG_FEATURES_SET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_features_set_rsp_free(rsp); - return NULL; -} - -/* ============== ETHTOOL_MSG_PRIVFLAGS_GET ============== */ -/* ETHTOOL_MSG_PRIVFLAGS_GET - do */ -void ethtool_privflags_get_req_free(struct ethtool_privflags_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_privflags_get_rsp_free(struct ethtool_privflags_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - ethtool_bitset_free(&rsp->flags); - free(rsp); -} - -int ethtool_privflags_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_privflags_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_PRIVFLAGS_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_PRIVFLAGS_FLAGS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.flags = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->flags; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return MNL_CB_OK; -} - -struct ethtool_privflags_get_rsp * -ethtool_privflags_get(struct ynl_sock *ys, - struct ethtool_privflags_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_privflags_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_PRIVFLAGS_GET, 1); - ys->req_policy = ðtool_privflags_nest; - yrs.yarg.rsp_policy = ðtool_privflags_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PRIVFLAGS_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_privflags_get_rsp_parse; - yrs.rsp_cmd = 14; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_privflags_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_PRIVFLAGS_GET - dump */ -void ethtool_privflags_get_list_free(struct ethtool_privflags_get_list *rsp) -{ - struct ethtool_privflags_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.flags); - free(rsp); - } -} - -struct ethtool_privflags_get_list * -ethtool_privflags_get_dump(struct ynl_sock *ys, - struct ethtool_privflags_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_privflags_get_list); - yds.cb = ethtool_privflags_get_rsp_parse; - yds.rsp_cmd = 14; - yds.rsp_policy = ðtool_privflags_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_PRIVFLAGS_GET, 1); - ys->req_policy = ðtool_privflags_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PRIVFLAGS_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_privflags_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_PRIVFLAGS_GET - notify */ -void ethtool_privflags_get_ntf_free(struct ethtool_privflags_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.flags); - free(rsp); -} - -/* ============== ETHTOOL_MSG_PRIVFLAGS_SET ============== */ -/* ETHTOOL_MSG_PRIVFLAGS_SET - do */ -void ethtool_privflags_set_req_free(struct ethtool_privflags_set_req *req) -{ - ethtool_header_free(&req->header); - ethtool_bitset_free(&req->flags); - free(req); -} - -int ethtool_privflags_set(struct ynl_sock *ys, - struct ethtool_privflags_set_req *req) -{ - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_PRIVFLAGS_SET, 1); - ys->req_policy = ðtool_privflags_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PRIVFLAGS_HEADER, &req->header); - if (req->_present.flags) - ethtool_bitset_put(nlh, ETHTOOL_A_PRIVFLAGS_FLAGS, &req->flags); - - err = ynl_exec(ys, nlh, NULL); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_RINGS_GET ============== */ -/* ETHTOOL_MSG_RINGS_GET - do */ -void ethtool_rings_get_req_free(struct ethtool_rings_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_rings_get_rsp_free(struct ethtool_rings_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - free(rsp); -} - -int ethtool_rings_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_rings_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_RINGS_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_RINGS_RX_MAX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_max = 1; - dst->rx_max = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_RINGS_RX_MINI_MAX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_mini_max = 1; - dst->rx_mini_max = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_RINGS_RX_JUMBO_MAX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_jumbo_max = 1; - dst->rx_jumbo_max = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_RINGS_TX_MAX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_max = 1; - dst->tx_max = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_RINGS_RX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx = 1; - dst->rx = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_RINGS_RX_MINI) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_mini = 1; - dst->rx_mini = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_RINGS_RX_JUMBO) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_jumbo = 1; - dst->rx_jumbo = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_RINGS_TX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx = 1; - dst->tx = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_RINGS_RX_BUF_LEN) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_buf_len = 1; - dst->rx_buf_len = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_RINGS_TCP_DATA_SPLIT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tcp_data_split = 1; - dst->tcp_data_split = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_RINGS_CQE_SIZE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.cqe_size = 1; - dst->cqe_size = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_RINGS_TX_PUSH) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_push = 1; - dst->tx_push = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_RINGS_RX_PUSH) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_push = 1; - dst->rx_push = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_push_buf_len = 1; - dst->tx_push_buf_len = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN_MAX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_push_buf_len_max = 1; - dst->tx_push_buf_len_max = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_rings_get_rsp * -ethtool_rings_get(struct ynl_sock *ys, struct ethtool_rings_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_rings_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_RINGS_GET, 1); - ys->req_policy = ðtool_rings_nest; - yrs.yarg.rsp_policy = ðtool_rings_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_RINGS_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_rings_get_rsp_parse; - yrs.rsp_cmd = 16; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_rings_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_RINGS_GET - dump */ -void ethtool_rings_get_list_free(struct ethtool_rings_get_list *rsp) -{ - struct ethtool_rings_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - free(rsp); - } -} - -struct ethtool_rings_get_list * -ethtool_rings_get_dump(struct ynl_sock *ys, - struct ethtool_rings_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_rings_get_list); - yds.cb = ethtool_rings_get_rsp_parse; - yds.rsp_cmd = 16; - yds.rsp_policy = ðtool_rings_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_RINGS_GET, 1); - ys->req_policy = ðtool_rings_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_RINGS_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_rings_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_RINGS_GET - notify */ -void ethtool_rings_get_ntf_free(struct ethtool_rings_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - free(rsp); -} - -/* ============== ETHTOOL_MSG_RINGS_SET ============== */ -/* ETHTOOL_MSG_RINGS_SET - do */ -void ethtool_rings_set_req_free(struct ethtool_rings_set_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -int ethtool_rings_set(struct ynl_sock *ys, struct ethtool_rings_set_req *req) -{ - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_RINGS_SET, 1); - ys->req_policy = ðtool_rings_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_RINGS_HEADER, &req->header); - if (req->_present.rx_max) - mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_RX_MAX, req->rx_max); - if (req->_present.rx_mini_max) - mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_RX_MINI_MAX, req->rx_mini_max); - if (req->_present.rx_jumbo_max) - mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_RX_JUMBO_MAX, req->rx_jumbo_max); - if (req->_present.tx_max) - mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_TX_MAX, req->tx_max); - if (req->_present.rx) - mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_RX, req->rx); - if (req->_present.rx_mini) - mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_RX_MINI, req->rx_mini); - if (req->_present.rx_jumbo) - mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_RX_JUMBO, req->rx_jumbo); - if (req->_present.tx) - mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_TX, req->tx); - if (req->_present.rx_buf_len) - mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_RX_BUF_LEN, req->rx_buf_len); - if (req->_present.tcp_data_split) - mnl_attr_put_u8(nlh, ETHTOOL_A_RINGS_TCP_DATA_SPLIT, req->tcp_data_split); - if (req->_present.cqe_size) - mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_CQE_SIZE, req->cqe_size); - if (req->_present.tx_push) - mnl_attr_put_u8(nlh, ETHTOOL_A_RINGS_TX_PUSH, req->tx_push); - if (req->_present.rx_push) - mnl_attr_put_u8(nlh, ETHTOOL_A_RINGS_RX_PUSH, req->rx_push); - if (req->_present.tx_push_buf_len) - mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN, req->tx_push_buf_len); - if (req->_present.tx_push_buf_len_max) - mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN_MAX, req->tx_push_buf_len_max); - - err = ynl_exec(ys, nlh, NULL); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_CHANNELS_GET ============== */ -/* ETHTOOL_MSG_CHANNELS_GET - do */ -void ethtool_channels_get_req_free(struct ethtool_channels_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_channels_get_rsp_free(struct ethtool_channels_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - free(rsp); -} - -int ethtool_channels_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_channels_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_CHANNELS_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_CHANNELS_RX_MAX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_max = 1; - dst->rx_max = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_CHANNELS_TX_MAX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_max = 1; - dst->tx_max = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_CHANNELS_OTHER_MAX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.other_max = 1; - dst->other_max = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_CHANNELS_COMBINED_MAX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.combined_max = 1; - dst->combined_max = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_CHANNELS_RX_COUNT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_count = 1; - dst->rx_count = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_CHANNELS_TX_COUNT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_count = 1; - dst->tx_count = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_CHANNELS_OTHER_COUNT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.other_count = 1; - dst->other_count = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_CHANNELS_COMBINED_COUNT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.combined_count = 1; - dst->combined_count = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_channels_get_rsp * -ethtool_channels_get(struct ynl_sock *ys, struct ethtool_channels_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_channels_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_CHANNELS_GET, 1); - ys->req_policy = ðtool_channels_nest; - yrs.yarg.rsp_policy = ðtool_channels_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_CHANNELS_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_channels_get_rsp_parse; - yrs.rsp_cmd = 18; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_channels_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_CHANNELS_GET - dump */ -void ethtool_channels_get_list_free(struct ethtool_channels_get_list *rsp) -{ - struct ethtool_channels_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - free(rsp); - } -} - -struct ethtool_channels_get_list * -ethtool_channels_get_dump(struct ynl_sock *ys, - struct ethtool_channels_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_channels_get_list); - yds.cb = ethtool_channels_get_rsp_parse; - yds.rsp_cmd = 18; - yds.rsp_policy = ðtool_channels_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_CHANNELS_GET, 1); - ys->req_policy = ðtool_channels_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_CHANNELS_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_channels_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_CHANNELS_GET - notify */ -void ethtool_channels_get_ntf_free(struct ethtool_channels_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - free(rsp); -} - -/* ============== ETHTOOL_MSG_CHANNELS_SET ============== */ -/* ETHTOOL_MSG_CHANNELS_SET - do */ -void ethtool_channels_set_req_free(struct ethtool_channels_set_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -int ethtool_channels_set(struct ynl_sock *ys, - struct ethtool_channels_set_req *req) -{ - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_CHANNELS_SET, 1); - ys->req_policy = ðtool_channels_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_CHANNELS_HEADER, &req->header); - if (req->_present.rx_max) - mnl_attr_put_u32(nlh, ETHTOOL_A_CHANNELS_RX_MAX, req->rx_max); - if (req->_present.tx_max) - mnl_attr_put_u32(nlh, ETHTOOL_A_CHANNELS_TX_MAX, req->tx_max); - if (req->_present.other_max) - mnl_attr_put_u32(nlh, ETHTOOL_A_CHANNELS_OTHER_MAX, req->other_max); - if (req->_present.combined_max) - mnl_attr_put_u32(nlh, ETHTOOL_A_CHANNELS_COMBINED_MAX, req->combined_max); - if (req->_present.rx_count) - mnl_attr_put_u32(nlh, ETHTOOL_A_CHANNELS_RX_COUNT, req->rx_count); - if (req->_present.tx_count) - mnl_attr_put_u32(nlh, ETHTOOL_A_CHANNELS_TX_COUNT, req->tx_count); - if (req->_present.other_count) - mnl_attr_put_u32(nlh, ETHTOOL_A_CHANNELS_OTHER_COUNT, req->other_count); - if (req->_present.combined_count) - mnl_attr_put_u32(nlh, ETHTOOL_A_CHANNELS_COMBINED_COUNT, req->combined_count); - - err = ynl_exec(ys, nlh, NULL); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_COALESCE_GET ============== */ -/* ETHTOOL_MSG_COALESCE_GET - do */ -void ethtool_coalesce_get_req_free(struct ethtool_coalesce_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_coalesce_get_rsp_free(struct ethtool_coalesce_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - free(rsp); -} - -int ethtool_coalesce_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_coalesce_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_COALESCE_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_COALESCE_RX_USECS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_usecs = 1; - dst->rx_usecs = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_RX_MAX_FRAMES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_max_frames = 1; - dst->rx_max_frames = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_RX_USECS_IRQ) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_usecs_irq = 1; - dst->rx_usecs_irq = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_max_frames_irq = 1; - dst->rx_max_frames_irq = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_TX_USECS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_usecs = 1; - dst->tx_usecs = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_TX_MAX_FRAMES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_max_frames = 1; - dst->tx_max_frames = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_TX_USECS_IRQ) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_usecs_irq = 1; - dst->tx_usecs_irq = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_max_frames_irq = 1; - dst->tx_max_frames_irq = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_STATS_BLOCK_USECS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.stats_block_usecs = 1; - dst->stats_block_usecs = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.use_adaptive_rx = 1; - dst->use_adaptive_rx = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.use_adaptive_tx = 1; - dst->use_adaptive_tx = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_COALESCE_PKT_RATE_LOW) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.pkt_rate_low = 1; - dst->pkt_rate_low = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_RX_USECS_LOW) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_usecs_low = 1; - dst->rx_usecs_low = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_max_frames_low = 1; - dst->rx_max_frames_low = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_TX_USECS_LOW) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_usecs_low = 1; - dst->tx_usecs_low = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_max_frames_low = 1; - dst->tx_max_frames_low = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_PKT_RATE_HIGH) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.pkt_rate_high = 1; - dst->pkt_rate_high = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_RX_USECS_HIGH) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_usecs_high = 1; - dst->rx_usecs_high = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_max_frames_high = 1; - dst->rx_max_frames_high = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_TX_USECS_HIGH) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_usecs_high = 1; - dst->tx_usecs_high = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_max_frames_high = 1; - dst->tx_max_frames_high = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rate_sample_interval = 1; - dst->rate_sample_interval = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_USE_CQE_MODE_TX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.use_cqe_mode_tx = 1; - dst->use_cqe_mode_tx = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_COALESCE_USE_CQE_MODE_RX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.use_cqe_mode_rx = 1; - dst->use_cqe_mode_rx = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_COALESCE_TX_AGGR_MAX_BYTES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_aggr_max_bytes = 1; - dst->tx_aggr_max_bytes = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_TX_AGGR_MAX_FRAMES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_aggr_max_frames = 1; - dst->tx_aggr_max_frames = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_TX_AGGR_TIME_USECS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_aggr_time_usecs = 1; - dst->tx_aggr_time_usecs = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_coalesce_get_rsp * -ethtool_coalesce_get(struct ynl_sock *ys, struct ethtool_coalesce_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_coalesce_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_COALESCE_GET, 1); - ys->req_policy = ðtool_coalesce_nest; - yrs.yarg.rsp_policy = ðtool_coalesce_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_COALESCE_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_coalesce_get_rsp_parse; - yrs.rsp_cmd = 20; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_coalesce_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_COALESCE_GET - dump */ -void ethtool_coalesce_get_list_free(struct ethtool_coalesce_get_list *rsp) -{ - struct ethtool_coalesce_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - free(rsp); - } -} - -struct ethtool_coalesce_get_list * -ethtool_coalesce_get_dump(struct ynl_sock *ys, - struct ethtool_coalesce_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_coalesce_get_list); - yds.cb = ethtool_coalesce_get_rsp_parse; - yds.rsp_cmd = 20; - yds.rsp_policy = ðtool_coalesce_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_COALESCE_GET, 1); - ys->req_policy = ðtool_coalesce_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_COALESCE_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_coalesce_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_COALESCE_GET - notify */ -void ethtool_coalesce_get_ntf_free(struct ethtool_coalesce_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - free(rsp); -} - -/* ============== ETHTOOL_MSG_COALESCE_SET ============== */ -/* ETHTOOL_MSG_COALESCE_SET - do */ -void ethtool_coalesce_set_req_free(struct ethtool_coalesce_set_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -int ethtool_coalesce_set(struct ynl_sock *ys, - struct ethtool_coalesce_set_req *req) -{ - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_COALESCE_SET, 1); - ys->req_policy = ðtool_coalesce_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_COALESCE_HEADER, &req->header); - if (req->_present.rx_usecs) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_RX_USECS, req->rx_usecs); - if (req->_present.rx_max_frames) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_RX_MAX_FRAMES, req->rx_max_frames); - if (req->_present.rx_usecs_irq) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_RX_USECS_IRQ, req->rx_usecs_irq); - if (req->_present.rx_max_frames_irq) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ, req->rx_max_frames_irq); - if (req->_present.tx_usecs) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_USECS, req->tx_usecs); - if (req->_present.tx_max_frames) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_MAX_FRAMES, req->tx_max_frames); - if (req->_present.tx_usecs_irq) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_USECS_IRQ, req->tx_usecs_irq); - if (req->_present.tx_max_frames_irq) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ, req->tx_max_frames_irq); - if (req->_present.stats_block_usecs) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_STATS_BLOCK_USECS, req->stats_block_usecs); - if (req->_present.use_adaptive_rx) - mnl_attr_put_u8(nlh, ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX, req->use_adaptive_rx); - if (req->_present.use_adaptive_tx) - mnl_attr_put_u8(nlh, ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX, req->use_adaptive_tx); - if (req->_present.pkt_rate_low) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_PKT_RATE_LOW, req->pkt_rate_low); - if (req->_present.rx_usecs_low) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_RX_USECS_LOW, req->rx_usecs_low); - if (req->_present.rx_max_frames_low) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW, req->rx_max_frames_low); - if (req->_present.tx_usecs_low) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_USECS_LOW, req->tx_usecs_low); - if (req->_present.tx_max_frames_low) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW, req->tx_max_frames_low); - if (req->_present.pkt_rate_high) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_PKT_RATE_HIGH, req->pkt_rate_high); - if (req->_present.rx_usecs_high) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_RX_USECS_HIGH, req->rx_usecs_high); - if (req->_present.rx_max_frames_high) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH, req->rx_max_frames_high); - if (req->_present.tx_usecs_high) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_USECS_HIGH, req->tx_usecs_high); - if (req->_present.tx_max_frames_high) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH, req->tx_max_frames_high); - if (req->_present.rate_sample_interval) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL, req->rate_sample_interval); - if (req->_present.use_cqe_mode_tx) - mnl_attr_put_u8(nlh, ETHTOOL_A_COALESCE_USE_CQE_MODE_TX, req->use_cqe_mode_tx); - if (req->_present.use_cqe_mode_rx) - mnl_attr_put_u8(nlh, ETHTOOL_A_COALESCE_USE_CQE_MODE_RX, req->use_cqe_mode_rx); - if (req->_present.tx_aggr_max_bytes) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_AGGR_MAX_BYTES, req->tx_aggr_max_bytes); - if (req->_present.tx_aggr_max_frames) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_AGGR_MAX_FRAMES, req->tx_aggr_max_frames); - if (req->_present.tx_aggr_time_usecs) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_AGGR_TIME_USECS, req->tx_aggr_time_usecs); - - err = ynl_exec(ys, nlh, NULL); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_PAUSE_GET ============== */ -/* ETHTOOL_MSG_PAUSE_GET - do */ -void ethtool_pause_get_req_free(struct ethtool_pause_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_pause_get_rsp_free(struct ethtool_pause_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - ethtool_pause_stat_free(&rsp->stats); - free(rsp); -} - -int ethtool_pause_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_pause_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_PAUSE_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_PAUSE_AUTONEG) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.autoneg = 1; - dst->autoneg = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_PAUSE_RX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx = 1; - dst->rx = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_PAUSE_TX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx = 1; - dst->tx = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_PAUSE_STATS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.stats = 1; - - parg.rsp_policy = ðtool_pause_stat_nest; - parg.data = &dst->stats; - if (ethtool_pause_stat_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_PAUSE_STATS_SRC) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.stats_src = 1; - dst->stats_src = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_pause_get_rsp * -ethtool_pause_get(struct ynl_sock *ys, struct ethtool_pause_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_pause_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_PAUSE_GET, 1); - ys->req_policy = ðtool_pause_nest; - yrs.yarg.rsp_policy = ðtool_pause_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PAUSE_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_pause_get_rsp_parse; - yrs.rsp_cmd = 22; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_pause_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_PAUSE_GET - dump */ -void ethtool_pause_get_list_free(struct ethtool_pause_get_list *rsp) -{ - struct ethtool_pause_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - ethtool_pause_stat_free(&rsp->obj.stats); - free(rsp); - } -} - -struct ethtool_pause_get_list * -ethtool_pause_get_dump(struct ynl_sock *ys, - struct ethtool_pause_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_pause_get_list); - yds.cb = ethtool_pause_get_rsp_parse; - yds.rsp_cmd = 22; - yds.rsp_policy = ðtool_pause_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_PAUSE_GET, 1); - ys->req_policy = ðtool_pause_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PAUSE_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_pause_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_PAUSE_GET - notify */ -void ethtool_pause_get_ntf_free(struct ethtool_pause_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - ethtool_pause_stat_free(&rsp->obj.stats); - free(rsp); -} - -/* ============== ETHTOOL_MSG_PAUSE_SET ============== */ -/* ETHTOOL_MSG_PAUSE_SET - do */ -void ethtool_pause_set_req_free(struct ethtool_pause_set_req *req) -{ - ethtool_header_free(&req->header); - ethtool_pause_stat_free(&req->stats); - free(req); -} - -int ethtool_pause_set(struct ynl_sock *ys, struct ethtool_pause_set_req *req) -{ - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_PAUSE_SET, 1); - ys->req_policy = ðtool_pause_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PAUSE_HEADER, &req->header); - if (req->_present.autoneg) - mnl_attr_put_u8(nlh, ETHTOOL_A_PAUSE_AUTONEG, req->autoneg); - if (req->_present.rx) - mnl_attr_put_u8(nlh, ETHTOOL_A_PAUSE_RX, req->rx); - if (req->_present.tx) - mnl_attr_put_u8(nlh, ETHTOOL_A_PAUSE_TX, req->tx); - if (req->_present.stats) - ethtool_pause_stat_put(nlh, ETHTOOL_A_PAUSE_STATS, &req->stats); - if (req->_present.stats_src) - mnl_attr_put_u32(nlh, ETHTOOL_A_PAUSE_STATS_SRC, req->stats_src); - - err = ynl_exec(ys, nlh, NULL); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_EEE_GET ============== */ -/* ETHTOOL_MSG_EEE_GET - do */ -void ethtool_eee_get_req_free(struct ethtool_eee_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_eee_get_rsp_free(struct ethtool_eee_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - ethtool_bitset_free(&rsp->modes_ours); - ethtool_bitset_free(&rsp->modes_peer); - free(rsp); -} - -int ethtool_eee_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct ethtool_eee_get_rsp *dst; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_EEE_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_EEE_MODES_OURS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.modes_ours = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->modes_ours; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_EEE_MODES_PEER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.modes_peer = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->modes_peer; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_EEE_ACTIVE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.active = 1; - dst->active = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_EEE_ENABLED) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.enabled = 1; - dst->enabled = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_EEE_TX_LPI_ENABLED) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_lpi_enabled = 1; - dst->tx_lpi_enabled = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_EEE_TX_LPI_TIMER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_lpi_timer = 1; - dst->tx_lpi_timer = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_eee_get_rsp * -ethtool_eee_get(struct ynl_sock *ys, struct ethtool_eee_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_eee_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_EEE_GET, 1); - ys->req_policy = ðtool_eee_nest; - yrs.yarg.rsp_policy = ðtool_eee_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_EEE_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_eee_get_rsp_parse; - yrs.rsp_cmd = 24; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_eee_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_EEE_GET - dump */ -void ethtool_eee_get_list_free(struct ethtool_eee_get_list *rsp) -{ - struct ethtool_eee_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.modes_ours); - ethtool_bitset_free(&rsp->obj.modes_peer); - free(rsp); - } -} - -struct ethtool_eee_get_list * -ethtool_eee_get_dump(struct ynl_sock *ys, struct ethtool_eee_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_eee_get_list); - yds.cb = ethtool_eee_get_rsp_parse; - yds.rsp_cmd = 24; - yds.rsp_policy = ðtool_eee_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_EEE_GET, 1); - ys->req_policy = ðtool_eee_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_EEE_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_eee_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_EEE_GET - notify */ -void ethtool_eee_get_ntf_free(struct ethtool_eee_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.modes_ours); - ethtool_bitset_free(&rsp->obj.modes_peer); - free(rsp); -} - -/* ============== ETHTOOL_MSG_EEE_SET ============== */ -/* ETHTOOL_MSG_EEE_SET - do */ -void ethtool_eee_set_req_free(struct ethtool_eee_set_req *req) -{ - ethtool_header_free(&req->header); - ethtool_bitset_free(&req->modes_ours); - ethtool_bitset_free(&req->modes_peer); - free(req); -} - -int ethtool_eee_set(struct ynl_sock *ys, struct ethtool_eee_set_req *req) -{ - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_EEE_SET, 1); - ys->req_policy = ðtool_eee_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_EEE_HEADER, &req->header); - if (req->_present.modes_ours) - ethtool_bitset_put(nlh, ETHTOOL_A_EEE_MODES_OURS, &req->modes_ours); - if (req->_present.modes_peer) - ethtool_bitset_put(nlh, ETHTOOL_A_EEE_MODES_PEER, &req->modes_peer); - if (req->_present.active) - mnl_attr_put_u8(nlh, ETHTOOL_A_EEE_ACTIVE, req->active); - if (req->_present.enabled) - mnl_attr_put_u8(nlh, ETHTOOL_A_EEE_ENABLED, req->enabled); - if (req->_present.tx_lpi_enabled) - mnl_attr_put_u8(nlh, ETHTOOL_A_EEE_TX_LPI_ENABLED, req->tx_lpi_enabled); - if (req->_present.tx_lpi_timer) - mnl_attr_put_u32(nlh, ETHTOOL_A_EEE_TX_LPI_TIMER, req->tx_lpi_timer); - - err = ynl_exec(ys, nlh, NULL); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_TSINFO_GET ============== */ -/* ETHTOOL_MSG_TSINFO_GET - do */ -void ethtool_tsinfo_get_req_free(struct ethtool_tsinfo_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_tsinfo_get_rsp_free(struct ethtool_tsinfo_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - ethtool_bitset_free(&rsp->timestamping); - ethtool_bitset_free(&rsp->tx_types); - ethtool_bitset_free(&rsp->rx_filters); - free(rsp); -} - -int ethtool_tsinfo_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_tsinfo_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_TSINFO_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_TSINFO_TIMESTAMPING) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.timestamping = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->timestamping; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_TSINFO_TX_TYPES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_types = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->tx_types; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_TSINFO_RX_FILTERS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_filters = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->rx_filters; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_TSINFO_PHC_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.phc_index = 1; - dst->phc_index = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_tsinfo_get_rsp * -ethtool_tsinfo_get(struct ynl_sock *ys, struct ethtool_tsinfo_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_tsinfo_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_TSINFO_GET, 1); - ys->req_policy = ðtool_tsinfo_nest; - yrs.yarg.rsp_policy = ðtool_tsinfo_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_TSINFO_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_tsinfo_get_rsp_parse; - yrs.rsp_cmd = 26; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_tsinfo_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_TSINFO_GET - dump */ -void ethtool_tsinfo_get_list_free(struct ethtool_tsinfo_get_list *rsp) -{ - struct ethtool_tsinfo_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.timestamping); - ethtool_bitset_free(&rsp->obj.tx_types); - ethtool_bitset_free(&rsp->obj.rx_filters); - free(rsp); - } -} - -struct ethtool_tsinfo_get_list * -ethtool_tsinfo_get_dump(struct ynl_sock *ys, - struct ethtool_tsinfo_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_tsinfo_get_list); - yds.cb = ethtool_tsinfo_get_rsp_parse; - yds.rsp_cmd = 26; - yds.rsp_policy = ðtool_tsinfo_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_TSINFO_GET, 1); - ys->req_policy = ðtool_tsinfo_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_TSINFO_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_tsinfo_get_list_free(yds.first); - return NULL; -} - -/* ============== ETHTOOL_MSG_CABLE_TEST_ACT ============== */ -/* ETHTOOL_MSG_CABLE_TEST_ACT - do */ -void ethtool_cable_test_act_req_free(struct ethtool_cable_test_act_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -int ethtool_cable_test_act(struct ynl_sock *ys, - struct ethtool_cable_test_act_req *req) -{ - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_CABLE_TEST_ACT, 1); - ys->req_policy = ðtool_cable_test_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_CABLE_TEST_HEADER, &req->header); - - err = ynl_exec(ys, nlh, NULL); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_CABLE_TEST_TDR_ACT ============== */ -/* ETHTOOL_MSG_CABLE_TEST_TDR_ACT - do */ -void -ethtool_cable_test_tdr_act_req_free(struct ethtool_cable_test_tdr_act_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -int ethtool_cable_test_tdr_act(struct ynl_sock *ys, - struct ethtool_cable_test_tdr_act_req *req) -{ - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_CABLE_TEST_TDR_ACT, 1); - ys->req_policy = ðtool_cable_test_tdr_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_CABLE_TEST_TDR_HEADER, &req->header); - - err = ynl_exec(ys, nlh, NULL); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_TUNNEL_INFO_GET ============== */ -/* ETHTOOL_MSG_TUNNEL_INFO_GET - do */ -void ethtool_tunnel_info_get_req_free(struct ethtool_tunnel_info_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_tunnel_info_get_rsp_free(struct ethtool_tunnel_info_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - ethtool_tunnel_udp_free(&rsp->udp_ports); - free(rsp); -} - -int ethtool_tunnel_info_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_tunnel_info_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_TUNNEL_INFO_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_TUNNEL_INFO_UDP_PORTS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.udp_ports = 1; - - parg.rsp_policy = ðtool_tunnel_udp_nest; - parg.data = &dst->udp_ports; - if (ethtool_tunnel_udp_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return MNL_CB_OK; -} - -struct ethtool_tunnel_info_get_rsp * -ethtool_tunnel_info_get(struct ynl_sock *ys, - struct ethtool_tunnel_info_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_tunnel_info_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_TUNNEL_INFO_GET, 1); - ys->req_policy = ðtool_tunnel_info_nest; - yrs.yarg.rsp_policy = ðtool_tunnel_info_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_TUNNEL_INFO_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_tunnel_info_get_rsp_parse; - yrs.rsp_cmd = 29; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_tunnel_info_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_TUNNEL_INFO_GET - dump */ -void -ethtool_tunnel_info_get_list_free(struct ethtool_tunnel_info_get_list *rsp) -{ - struct ethtool_tunnel_info_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - ethtool_tunnel_udp_free(&rsp->obj.udp_ports); - free(rsp); - } -} - -struct ethtool_tunnel_info_get_list * -ethtool_tunnel_info_get_dump(struct ynl_sock *ys, - struct ethtool_tunnel_info_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_tunnel_info_get_list); - yds.cb = ethtool_tunnel_info_get_rsp_parse; - yds.rsp_cmd = 29; - yds.rsp_policy = ðtool_tunnel_info_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_TUNNEL_INFO_GET, 1); - ys->req_policy = ðtool_tunnel_info_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_TUNNEL_INFO_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_tunnel_info_get_list_free(yds.first); - return NULL; -} - -/* ============== ETHTOOL_MSG_FEC_GET ============== */ -/* ETHTOOL_MSG_FEC_GET - do */ -void ethtool_fec_get_req_free(struct ethtool_fec_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_fec_get_rsp_free(struct ethtool_fec_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - ethtool_bitset_free(&rsp->modes); - ethtool_fec_stat_free(&rsp->stats); - free(rsp); -} - -int ethtool_fec_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct ethtool_fec_get_rsp *dst; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_FEC_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_FEC_MODES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.modes = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->modes; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_FEC_AUTO) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.auto_ = 1; - dst->auto_ = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_FEC_ACTIVE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.active = 1; - dst->active = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_FEC_STATS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.stats = 1; - - parg.rsp_policy = ðtool_fec_stat_nest; - parg.data = &dst->stats; - if (ethtool_fec_stat_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return MNL_CB_OK; -} - -struct ethtool_fec_get_rsp * -ethtool_fec_get(struct ynl_sock *ys, struct ethtool_fec_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_fec_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_FEC_GET, 1); - ys->req_policy = ðtool_fec_nest; - yrs.yarg.rsp_policy = ðtool_fec_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_FEC_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_fec_get_rsp_parse; - yrs.rsp_cmd = 30; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_fec_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_FEC_GET - dump */ -void ethtool_fec_get_list_free(struct ethtool_fec_get_list *rsp) -{ - struct ethtool_fec_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.modes); - ethtool_fec_stat_free(&rsp->obj.stats); - free(rsp); - } -} - -struct ethtool_fec_get_list * -ethtool_fec_get_dump(struct ynl_sock *ys, struct ethtool_fec_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_fec_get_list); - yds.cb = ethtool_fec_get_rsp_parse; - yds.rsp_cmd = 30; - yds.rsp_policy = ðtool_fec_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_FEC_GET, 1); - ys->req_policy = ðtool_fec_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_FEC_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_fec_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_FEC_GET - notify */ -void ethtool_fec_get_ntf_free(struct ethtool_fec_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.modes); - ethtool_fec_stat_free(&rsp->obj.stats); - free(rsp); -} - -/* ============== ETHTOOL_MSG_FEC_SET ============== */ -/* ETHTOOL_MSG_FEC_SET - do */ -void ethtool_fec_set_req_free(struct ethtool_fec_set_req *req) -{ - ethtool_header_free(&req->header); - ethtool_bitset_free(&req->modes); - ethtool_fec_stat_free(&req->stats); - free(req); -} - -int ethtool_fec_set(struct ynl_sock *ys, struct ethtool_fec_set_req *req) -{ - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_FEC_SET, 1); - ys->req_policy = ðtool_fec_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_FEC_HEADER, &req->header); - if (req->_present.modes) - ethtool_bitset_put(nlh, ETHTOOL_A_FEC_MODES, &req->modes); - if (req->_present.auto_) - mnl_attr_put_u8(nlh, ETHTOOL_A_FEC_AUTO, req->auto_); - if (req->_present.active) - mnl_attr_put_u32(nlh, ETHTOOL_A_FEC_ACTIVE, req->active); - if (req->_present.stats) - ethtool_fec_stat_put(nlh, ETHTOOL_A_FEC_STATS, &req->stats); - - err = ynl_exec(ys, nlh, NULL); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_MODULE_EEPROM_GET ============== */ -/* ETHTOOL_MSG_MODULE_EEPROM_GET - do */ -void -ethtool_module_eeprom_get_req_free(struct ethtool_module_eeprom_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void -ethtool_module_eeprom_get_rsp_free(struct ethtool_module_eeprom_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - free(rsp->data); - free(rsp); -} - -int ethtool_module_eeprom_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_module_eeprom_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_MODULE_EEPROM_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_MODULE_EEPROM_OFFSET) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.offset = 1; - dst->offset = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_MODULE_EEPROM_LENGTH) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.length = 1; - dst->length = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_MODULE_EEPROM_PAGE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.page = 1; - dst->page = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_MODULE_EEPROM_BANK) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.bank = 1; - dst->bank = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_MODULE_EEPROM_I2C_ADDRESS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.i2c_address = 1; - dst->i2c_address = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_MODULE_EEPROM_DATA) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = mnl_attr_get_payload_len(attr); - dst->_present.data_len = len; - dst->data = malloc(len); - memcpy(dst->data, mnl_attr_get_payload(attr), len); - } - } - - return MNL_CB_OK; -} - -struct ethtool_module_eeprom_get_rsp * -ethtool_module_eeprom_get(struct ynl_sock *ys, - struct ethtool_module_eeprom_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_module_eeprom_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_MODULE_EEPROM_GET, 1); - ys->req_policy = ðtool_module_eeprom_nest; - yrs.yarg.rsp_policy = ðtool_module_eeprom_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_MODULE_EEPROM_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_module_eeprom_get_rsp_parse; - yrs.rsp_cmd = 32; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_module_eeprom_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_MODULE_EEPROM_GET - dump */ -void -ethtool_module_eeprom_get_list_free(struct ethtool_module_eeprom_get_list *rsp) -{ - struct ethtool_module_eeprom_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - free(rsp->obj.data); - free(rsp); - } -} - -struct ethtool_module_eeprom_get_list * -ethtool_module_eeprom_get_dump(struct ynl_sock *ys, - struct ethtool_module_eeprom_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_module_eeprom_get_list); - yds.cb = ethtool_module_eeprom_get_rsp_parse; - yds.rsp_cmd = 32; - yds.rsp_policy = ðtool_module_eeprom_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_MODULE_EEPROM_GET, 1); - ys->req_policy = ðtool_module_eeprom_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_MODULE_EEPROM_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_module_eeprom_get_list_free(yds.first); - return NULL; -} - -/* ============== ETHTOOL_MSG_PHC_VCLOCKS_GET ============== */ -/* ETHTOOL_MSG_PHC_VCLOCKS_GET - do */ -void ethtool_phc_vclocks_get_req_free(struct ethtool_phc_vclocks_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_phc_vclocks_get_rsp_free(struct ethtool_phc_vclocks_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - free(rsp); -} - -int ethtool_phc_vclocks_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_phc_vclocks_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_PHC_VCLOCKS_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_PHC_VCLOCKS_NUM) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.num = 1; - dst->num = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_phc_vclocks_get_rsp * -ethtool_phc_vclocks_get(struct ynl_sock *ys, - struct ethtool_phc_vclocks_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_phc_vclocks_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_PHC_VCLOCKS_GET, 1); - ys->req_policy = ðtool_phc_vclocks_nest; - yrs.yarg.rsp_policy = ðtool_phc_vclocks_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PHC_VCLOCKS_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_phc_vclocks_get_rsp_parse; - yrs.rsp_cmd = 34; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_phc_vclocks_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_PHC_VCLOCKS_GET - dump */ -void -ethtool_phc_vclocks_get_list_free(struct ethtool_phc_vclocks_get_list *rsp) -{ - struct ethtool_phc_vclocks_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - free(rsp); - } -} - -struct ethtool_phc_vclocks_get_list * -ethtool_phc_vclocks_get_dump(struct ynl_sock *ys, - struct ethtool_phc_vclocks_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_phc_vclocks_get_list); - yds.cb = ethtool_phc_vclocks_get_rsp_parse; - yds.rsp_cmd = 34; - yds.rsp_policy = ðtool_phc_vclocks_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_PHC_VCLOCKS_GET, 1); - ys->req_policy = ðtool_phc_vclocks_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PHC_VCLOCKS_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_phc_vclocks_get_list_free(yds.first); - return NULL; -} - -/* ============== ETHTOOL_MSG_MODULE_GET ============== */ -/* ETHTOOL_MSG_MODULE_GET - do */ -void ethtool_module_get_req_free(struct ethtool_module_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_module_get_rsp_free(struct ethtool_module_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - free(rsp); -} - -int ethtool_module_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_module_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_MODULE_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_MODULE_POWER_MODE_POLICY) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.power_mode_policy = 1; - dst->power_mode_policy = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_MODULE_POWER_MODE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.power_mode = 1; - dst->power_mode = mnl_attr_get_u8(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_module_get_rsp * -ethtool_module_get(struct ynl_sock *ys, struct ethtool_module_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_module_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_MODULE_GET, 1); - ys->req_policy = ðtool_module_nest; - yrs.yarg.rsp_policy = ðtool_module_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_MODULE_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_module_get_rsp_parse; - yrs.rsp_cmd = 35; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_module_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_MODULE_GET - dump */ -void ethtool_module_get_list_free(struct ethtool_module_get_list *rsp) -{ - struct ethtool_module_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - free(rsp); - } -} - -struct ethtool_module_get_list * -ethtool_module_get_dump(struct ynl_sock *ys, - struct ethtool_module_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_module_get_list); - yds.cb = ethtool_module_get_rsp_parse; - yds.rsp_cmd = 35; - yds.rsp_policy = ðtool_module_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_MODULE_GET, 1); - ys->req_policy = ðtool_module_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_MODULE_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_module_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_MODULE_GET - notify */ -void ethtool_module_get_ntf_free(struct ethtool_module_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - free(rsp); -} - -/* ============== ETHTOOL_MSG_MODULE_SET ============== */ -/* ETHTOOL_MSG_MODULE_SET - do */ -void ethtool_module_set_req_free(struct ethtool_module_set_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -int ethtool_module_set(struct ynl_sock *ys, struct ethtool_module_set_req *req) -{ - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_MODULE_SET, 1); - ys->req_policy = ðtool_module_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_MODULE_HEADER, &req->header); - if (req->_present.power_mode_policy) - mnl_attr_put_u8(nlh, ETHTOOL_A_MODULE_POWER_MODE_POLICY, req->power_mode_policy); - if (req->_present.power_mode) - mnl_attr_put_u8(nlh, ETHTOOL_A_MODULE_POWER_MODE, req->power_mode); - - err = ynl_exec(ys, nlh, NULL); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_PSE_GET ============== */ -/* ETHTOOL_MSG_PSE_GET - do */ -void ethtool_pse_get_req_free(struct ethtool_pse_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_pse_get_rsp_free(struct ethtool_pse_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - free(rsp); -} - -int ethtool_pse_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct ethtool_pse_get_rsp *dst; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_PSE_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_PODL_PSE_ADMIN_STATE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.admin_state = 1; - dst->admin_state = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_PODL_PSE_ADMIN_CONTROL) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.admin_control = 1; - dst->admin_control = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_PODL_PSE_PW_D_STATUS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.pw_d_status = 1; - dst->pw_d_status = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_pse_get_rsp * -ethtool_pse_get(struct ynl_sock *ys, struct ethtool_pse_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_pse_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_PSE_GET, 1); - ys->req_policy = ðtool_pse_nest; - yrs.yarg.rsp_policy = ðtool_pse_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PSE_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_pse_get_rsp_parse; - yrs.rsp_cmd = 37; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_pse_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_PSE_GET - dump */ -void ethtool_pse_get_list_free(struct ethtool_pse_get_list *rsp) -{ - struct ethtool_pse_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - free(rsp); - } -} - -struct ethtool_pse_get_list * -ethtool_pse_get_dump(struct ynl_sock *ys, struct ethtool_pse_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_pse_get_list); - yds.cb = ethtool_pse_get_rsp_parse; - yds.rsp_cmd = 37; - yds.rsp_policy = ðtool_pse_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_PSE_GET, 1); - ys->req_policy = ðtool_pse_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PSE_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_pse_get_list_free(yds.first); - return NULL; -} - -/* ============== ETHTOOL_MSG_PSE_SET ============== */ -/* ETHTOOL_MSG_PSE_SET - do */ -void ethtool_pse_set_req_free(struct ethtool_pse_set_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -int ethtool_pse_set(struct ynl_sock *ys, struct ethtool_pse_set_req *req) -{ - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_PSE_SET, 1); - ys->req_policy = ðtool_pse_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PSE_HEADER, &req->header); - if (req->_present.admin_state) - mnl_attr_put_u32(nlh, ETHTOOL_A_PODL_PSE_ADMIN_STATE, req->admin_state); - if (req->_present.admin_control) - mnl_attr_put_u32(nlh, ETHTOOL_A_PODL_PSE_ADMIN_CONTROL, req->admin_control); - if (req->_present.pw_d_status) - mnl_attr_put_u32(nlh, ETHTOOL_A_PODL_PSE_PW_D_STATUS, req->pw_d_status); - - err = ynl_exec(ys, nlh, NULL); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_RSS_GET ============== */ -/* ETHTOOL_MSG_RSS_GET - do */ -void ethtool_rss_get_req_free(struct ethtool_rss_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_rss_get_rsp_free(struct ethtool_rss_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - free(rsp->indir); - free(rsp->hkey); - free(rsp); -} - -int ethtool_rss_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct ethtool_rss_get_rsp *dst; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_RSS_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_RSS_CONTEXT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.context = 1; - dst->context = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_RSS_HFUNC) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.hfunc = 1; - dst->hfunc = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_RSS_INDIR) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = mnl_attr_get_payload_len(attr); - dst->_present.indir_len = len; - dst->indir = malloc(len); - memcpy(dst->indir, mnl_attr_get_payload(attr), len); - } else if (type == ETHTOOL_A_RSS_HKEY) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = mnl_attr_get_payload_len(attr); - dst->_present.hkey_len = len; - dst->hkey = malloc(len); - memcpy(dst->hkey, mnl_attr_get_payload(attr), len); - } - } - - return MNL_CB_OK; -} - -struct ethtool_rss_get_rsp * -ethtool_rss_get(struct ynl_sock *ys, struct ethtool_rss_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_rss_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_RSS_GET, 1); - ys->req_policy = ðtool_rss_nest; - yrs.yarg.rsp_policy = ðtool_rss_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_RSS_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_rss_get_rsp_parse; - yrs.rsp_cmd = ETHTOOL_MSG_RSS_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_rss_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_RSS_GET - dump */ -void ethtool_rss_get_list_free(struct ethtool_rss_get_list *rsp) -{ - struct ethtool_rss_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - free(rsp->obj.indir); - free(rsp->obj.hkey); - free(rsp); - } -} - -struct ethtool_rss_get_list * -ethtool_rss_get_dump(struct ynl_sock *ys, struct ethtool_rss_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_rss_get_list); - yds.cb = ethtool_rss_get_rsp_parse; - yds.rsp_cmd = ETHTOOL_MSG_RSS_GET; - yds.rsp_policy = ðtool_rss_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_RSS_GET, 1); - ys->req_policy = ðtool_rss_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_RSS_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_rss_get_list_free(yds.first); - return NULL; -} - -/* ============== ETHTOOL_MSG_PLCA_GET_CFG ============== */ -/* ETHTOOL_MSG_PLCA_GET_CFG - do */ -void ethtool_plca_get_cfg_req_free(struct ethtool_plca_get_cfg_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_plca_get_cfg_rsp_free(struct ethtool_plca_get_cfg_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - free(rsp); -} - -int ethtool_plca_get_cfg_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_plca_get_cfg_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_PLCA_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_PLCA_VERSION) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.version = 1; - dst->version = mnl_attr_get_u16(attr); - } else if (type == ETHTOOL_A_PLCA_ENABLED) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.enabled = 1; - dst->enabled = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_PLCA_STATUS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.status = 1; - dst->status = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_PLCA_NODE_CNT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.node_cnt = 1; - dst->node_cnt = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_PLCA_NODE_ID) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.node_id = 1; - dst->node_id = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_PLCA_TO_TMR) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.to_tmr = 1; - dst->to_tmr = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_PLCA_BURST_CNT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.burst_cnt = 1; - dst->burst_cnt = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_PLCA_BURST_TMR) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.burst_tmr = 1; - dst->burst_tmr = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_plca_get_cfg_rsp * -ethtool_plca_get_cfg(struct ynl_sock *ys, struct ethtool_plca_get_cfg_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_plca_get_cfg_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_PLCA_GET_CFG, 1); - ys->req_policy = ðtool_plca_nest; - yrs.yarg.rsp_policy = ðtool_plca_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PLCA_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_plca_get_cfg_rsp_parse; - yrs.rsp_cmd = ETHTOOL_MSG_PLCA_GET_CFG; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_plca_get_cfg_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_PLCA_GET_CFG - dump */ -void ethtool_plca_get_cfg_list_free(struct ethtool_plca_get_cfg_list *rsp) -{ - struct ethtool_plca_get_cfg_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - free(rsp); - } -} - -struct ethtool_plca_get_cfg_list * -ethtool_plca_get_cfg_dump(struct ynl_sock *ys, - struct ethtool_plca_get_cfg_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_plca_get_cfg_list); - yds.cb = ethtool_plca_get_cfg_rsp_parse; - yds.rsp_cmd = ETHTOOL_MSG_PLCA_GET_CFG; - yds.rsp_policy = ðtool_plca_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_PLCA_GET_CFG, 1); - ys->req_policy = ðtool_plca_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PLCA_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_plca_get_cfg_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_PLCA_GET_CFG - notify */ -void ethtool_plca_get_cfg_ntf_free(struct ethtool_plca_get_cfg_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - free(rsp); -} - -/* ============== ETHTOOL_MSG_PLCA_SET_CFG ============== */ -/* ETHTOOL_MSG_PLCA_SET_CFG - do */ -void ethtool_plca_set_cfg_req_free(struct ethtool_plca_set_cfg_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -int ethtool_plca_set_cfg(struct ynl_sock *ys, - struct ethtool_plca_set_cfg_req *req) -{ - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_PLCA_SET_CFG, 1); - ys->req_policy = ðtool_plca_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PLCA_HEADER, &req->header); - if (req->_present.version) - mnl_attr_put_u16(nlh, ETHTOOL_A_PLCA_VERSION, req->version); - if (req->_present.enabled) - mnl_attr_put_u8(nlh, ETHTOOL_A_PLCA_ENABLED, req->enabled); - if (req->_present.status) - mnl_attr_put_u8(nlh, ETHTOOL_A_PLCA_STATUS, req->status); - if (req->_present.node_cnt) - mnl_attr_put_u32(nlh, ETHTOOL_A_PLCA_NODE_CNT, req->node_cnt); - if (req->_present.node_id) - mnl_attr_put_u32(nlh, ETHTOOL_A_PLCA_NODE_ID, req->node_id); - if (req->_present.to_tmr) - mnl_attr_put_u32(nlh, ETHTOOL_A_PLCA_TO_TMR, req->to_tmr); - if (req->_present.burst_cnt) - mnl_attr_put_u32(nlh, ETHTOOL_A_PLCA_BURST_CNT, req->burst_cnt); - if (req->_present.burst_tmr) - mnl_attr_put_u32(nlh, ETHTOOL_A_PLCA_BURST_TMR, req->burst_tmr); - - err = ynl_exec(ys, nlh, NULL); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_PLCA_GET_STATUS ============== */ -/* ETHTOOL_MSG_PLCA_GET_STATUS - do */ -void ethtool_plca_get_status_req_free(struct ethtool_plca_get_status_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_plca_get_status_rsp_free(struct ethtool_plca_get_status_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - free(rsp); -} - -int ethtool_plca_get_status_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_plca_get_status_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_PLCA_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_PLCA_VERSION) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.version = 1; - dst->version = mnl_attr_get_u16(attr); - } else if (type == ETHTOOL_A_PLCA_ENABLED) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.enabled = 1; - dst->enabled = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_PLCA_STATUS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.status = 1; - dst->status = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_PLCA_NODE_CNT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.node_cnt = 1; - dst->node_cnt = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_PLCA_NODE_ID) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.node_id = 1; - dst->node_id = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_PLCA_TO_TMR) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.to_tmr = 1; - dst->to_tmr = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_PLCA_BURST_CNT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.burst_cnt = 1; - dst->burst_cnt = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_PLCA_BURST_TMR) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.burst_tmr = 1; - dst->burst_tmr = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_plca_get_status_rsp * -ethtool_plca_get_status(struct ynl_sock *ys, - struct ethtool_plca_get_status_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_plca_get_status_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_PLCA_GET_STATUS, 1); - ys->req_policy = ðtool_plca_nest; - yrs.yarg.rsp_policy = ðtool_plca_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PLCA_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_plca_get_status_rsp_parse; - yrs.rsp_cmd = 40; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_plca_get_status_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_PLCA_GET_STATUS - dump */ -void -ethtool_plca_get_status_list_free(struct ethtool_plca_get_status_list *rsp) -{ - struct ethtool_plca_get_status_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - free(rsp); - } -} - -struct ethtool_plca_get_status_list * -ethtool_plca_get_status_dump(struct ynl_sock *ys, - struct ethtool_plca_get_status_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_plca_get_status_list); - yds.cb = ethtool_plca_get_status_rsp_parse; - yds.rsp_cmd = 40; - yds.rsp_policy = ðtool_plca_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_PLCA_GET_STATUS, 1); - ys->req_policy = ðtool_plca_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PLCA_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_plca_get_status_list_free(yds.first); - return NULL; -} - -/* ============== ETHTOOL_MSG_MM_GET ============== */ -/* ETHTOOL_MSG_MM_GET - do */ -void ethtool_mm_get_req_free(struct ethtool_mm_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_mm_get_rsp_free(struct ethtool_mm_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - ethtool_mm_stat_free(&rsp->stats); - free(rsp); -} - -int ethtool_mm_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct ethtool_mm_get_rsp *dst; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_MM_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_MM_PMAC_ENABLED) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.pmac_enabled = 1; - dst->pmac_enabled = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_MM_TX_ENABLED) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_enabled = 1; - dst->tx_enabled = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_MM_TX_ACTIVE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_active = 1; - dst->tx_active = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_MM_TX_MIN_FRAG_SIZE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_min_frag_size = 1; - dst->tx_min_frag_size = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_MM_RX_MIN_FRAG_SIZE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_min_frag_size = 1; - dst->rx_min_frag_size = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_MM_VERIFY_ENABLED) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.verify_enabled = 1; - dst->verify_enabled = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_MM_VERIFY_TIME) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.verify_time = 1; - dst->verify_time = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_MM_MAX_VERIFY_TIME) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.max_verify_time = 1; - dst->max_verify_time = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_MM_STATS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.stats = 1; - - parg.rsp_policy = ðtool_mm_stat_nest; - parg.data = &dst->stats; - if (ethtool_mm_stat_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return MNL_CB_OK; -} - -struct ethtool_mm_get_rsp * -ethtool_mm_get(struct ynl_sock *ys, struct ethtool_mm_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_mm_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_MM_GET, 1); - ys->req_policy = ðtool_mm_nest; - yrs.yarg.rsp_policy = ðtool_mm_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_MM_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_mm_get_rsp_parse; - yrs.rsp_cmd = ETHTOOL_MSG_MM_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_mm_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_MM_GET - dump */ -void ethtool_mm_get_list_free(struct ethtool_mm_get_list *rsp) -{ - struct ethtool_mm_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - ethtool_mm_stat_free(&rsp->obj.stats); - free(rsp); - } -} - -struct ethtool_mm_get_list * -ethtool_mm_get_dump(struct ynl_sock *ys, struct ethtool_mm_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_mm_get_list); - yds.cb = ethtool_mm_get_rsp_parse; - yds.rsp_cmd = ETHTOOL_MSG_MM_GET; - yds.rsp_policy = ðtool_mm_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_MM_GET, 1); - ys->req_policy = ðtool_mm_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_MM_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_mm_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_MM_GET - notify */ -void ethtool_mm_get_ntf_free(struct ethtool_mm_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - ethtool_mm_stat_free(&rsp->obj.stats); - free(rsp); -} - -/* ============== ETHTOOL_MSG_MM_SET ============== */ -/* ETHTOOL_MSG_MM_SET - do */ -void ethtool_mm_set_req_free(struct ethtool_mm_set_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -int ethtool_mm_set(struct ynl_sock *ys, struct ethtool_mm_set_req *req) -{ - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_MM_SET, 1); - ys->req_policy = ðtool_mm_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_MM_HEADER, &req->header); - if (req->_present.verify_enabled) - mnl_attr_put_u8(nlh, ETHTOOL_A_MM_VERIFY_ENABLED, req->verify_enabled); - if (req->_present.verify_time) - mnl_attr_put_u32(nlh, ETHTOOL_A_MM_VERIFY_TIME, req->verify_time); - if (req->_present.tx_enabled) - mnl_attr_put_u8(nlh, ETHTOOL_A_MM_TX_ENABLED, req->tx_enabled); - if (req->_present.pmac_enabled) - mnl_attr_put_u8(nlh, ETHTOOL_A_MM_PMAC_ENABLED, req->pmac_enabled); - if (req->_present.tx_min_frag_size) - mnl_attr_put_u32(nlh, ETHTOOL_A_MM_TX_MIN_FRAG_SIZE, req->tx_min_frag_size); - - err = ynl_exec(ys, nlh, NULL); - if (err < 0) - return -1; - - return 0; -} - -/* ETHTOOL_MSG_CABLE_TEST_NTF - event */ -int ethtool_cable_test_ntf_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_cable_test_ntf_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_CABLE_TEST_NTF_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_CABLE_TEST_NTF_STATUS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.status = 1; - dst->status = mnl_attr_get_u8(attr); - } - } - - return MNL_CB_OK; -} - -void ethtool_cable_test_ntf_free(struct ethtool_cable_test_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - free(rsp); -} - -/* ETHTOOL_MSG_CABLE_TEST_TDR_NTF - event */ -int ethtool_cable_test_tdr_ntf_rsp_parse(const struct nlmsghdr *nlh, - void *data) -{ - struct ethtool_cable_test_tdr_ntf_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_CABLE_TEST_TDR_NTF_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_CABLE_TEST_TDR_NTF_STATUS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.status = 1; - dst->status = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_CABLE_TEST_TDR_NTF_NEST) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.nest = 1; - - parg.rsp_policy = ðtool_cable_nest_nest; - parg.data = &dst->nest; - if (ethtool_cable_nest_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return MNL_CB_OK; -} - -void ethtool_cable_test_tdr_ntf_free(struct ethtool_cable_test_tdr_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - ethtool_cable_nest_free(&rsp->obj.nest); - free(rsp); -} - -static const struct ynl_ntf_info ethtool_ntf_info[] = { - [ETHTOOL_MSG_LINKINFO_NTF] = { - .alloc_sz = sizeof(struct ethtool_linkinfo_get_ntf), - .cb = ethtool_linkinfo_get_rsp_parse, - .policy = ðtool_linkinfo_nest, - .free = (void *)ethtool_linkinfo_get_ntf_free, - }, - [ETHTOOL_MSG_LINKMODES_NTF] = { - .alloc_sz = sizeof(struct ethtool_linkmodes_get_ntf), - .cb = ethtool_linkmodes_get_rsp_parse, - .policy = ðtool_linkmodes_nest, - .free = (void *)ethtool_linkmodes_get_ntf_free, - }, - [ETHTOOL_MSG_DEBUG_NTF] = { - .alloc_sz = sizeof(struct ethtool_debug_get_ntf), - .cb = ethtool_debug_get_rsp_parse, - .policy = ðtool_debug_nest, - .free = (void *)ethtool_debug_get_ntf_free, - }, - [ETHTOOL_MSG_WOL_NTF] = { - .alloc_sz = sizeof(struct ethtool_wol_get_ntf), - .cb = ethtool_wol_get_rsp_parse, - .policy = ðtool_wol_nest, - .free = (void *)ethtool_wol_get_ntf_free, - }, - [ETHTOOL_MSG_FEATURES_NTF] = { - .alloc_sz = sizeof(struct ethtool_features_get_ntf), - .cb = ethtool_features_get_rsp_parse, - .policy = ðtool_features_nest, - .free = (void *)ethtool_features_get_ntf_free, - }, - [ETHTOOL_MSG_PRIVFLAGS_NTF] = { - .alloc_sz = sizeof(struct ethtool_privflags_get_ntf), - .cb = ethtool_privflags_get_rsp_parse, - .policy = ðtool_privflags_nest, - .free = (void *)ethtool_privflags_get_ntf_free, - }, - [ETHTOOL_MSG_RINGS_NTF] = { - .alloc_sz = sizeof(struct ethtool_rings_get_ntf), - .cb = ethtool_rings_get_rsp_parse, - .policy = ðtool_rings_nest, - .free = (void *)ethtool_rings_get_ntf_free, - }, - [ETHTOOL_MSG_CHANNELS_NTF] = { - .alloc_sz = sizeof(struct ethtool_channels_get_ntf), - .cb = ethtool_channels_get_rsp_parse, - .policy = ðtool_channels_nest, - .free = (void *)ethtool_channels_get_ntf_free, - }, - [ETHTOOL_MSG_COALESCE_NTF] = { - .alloc_sz = sizeof(struct ethtool_coalesce_get_ntf), - .cb = ethtool_coalesce_get_rsp_parse, - .policy = ðtool_coalesce_nest, - .free = (void *)ethtool_coalesce_get_ntf_free, - }, - [ETHTOOL_MSG_PAUSE_NTF] = { - .alloc_sz = sizeof(struct ethtool_pause_get_ntf), - .cb = ethtool_pause_get_rsp_parse, - .policy = ðtool_pause_nest, - .free = (void *)ethtool_pause_get_ntf_free, - }, - [ETHTOOL_MSG_EEE_NTF] = { - .alloc_sz = sizeof(struct ethtool_eee_get_ntf), - .cb = ethtool_eee_get_rsp_parse, - .policy = ðtool_eee_nest, - .free = (void *)ethtool_eee_get_ntf_free, - }, - [ETHTOOL_MSG_CABLE_TEST_NTF] = { - .alloc_sz = sizeof(struct ethtool_cable_test_ntf), - .cb = ethtool_cable_test_ntf_rsp_parse, - .policy = ðtool_cable_test_ntf_nest, - .free = (void *)ethtool_cable_test_ntf_free, - }, - [ETHTOOL_MSG_CABLE_TEST_TDR_NTF] = { - .alloc_sz = sizeof(struct ethtool_cable_test_tdr_ntf), - .cb = ethtool_cable_test_tdr_ntf_rsp_parse, - .policy = ðtool_cable_test_tdr_ntf_nest, - .free = (void *)ethtool_cable_test_tdr_ntf_free, - }, - [ETHTOOL_MSG_FEC_NTF] = { - .alloc_sz = sizeof(struct ethtool_fec_get_ntf), - .cb = ethtool_fec_get_rsp_parse, - .policy = ðtool_fec_nest, - .free = (void *)ethtool_fec_get_ntf_free, - }, - [ETHTOOL_MSG_MODULE_NTF] = { - .alloc_sz = sizeof(struct ethtool_module_get_ntf), - .cb = ethtool_module_get_rsp_parse, - .policy = ðtool_module_nest, - .free = (void *)ethtool_module_get_ntf_free, - }, - [ETHTOOL_MSG_PLCA_NTF] = { - .alloc_sz = sizeof(struct ethtool_plca_get_cfg_ntf), - .cb = ethtool_plca_get_cfg_rsp_parse, - .policy = ðtool_plca_nest, - .free = (void *)ethtool_plca_get_cfg_ntf_free, - }, - [ETHTOOL_MSG_MM_NTF] = { - .alloc_sz = sizeof(struct ethtool_mm_get_ntf), - .cb = ethtool_mm_get_rsp_parse, - .policy = ðtool_mm_nest, - .free = (void *)ethtool_mm_get_ntf_free, - }, -}; - -const struct ynl_family ynl_ethtool_family = { - .name = "ethtool", - .ntf_info = ethtool_ntf_info, - .ntf_info_size = MNL_ARRAY_SIZE(ethtool_ntf_info), -}; diff --git a/tools/net/ynl/generated/ethtool-user.h b/tools/net/ynl/generated/ethtool-user.h deleted file mode 100644 index ddc1a5209992..000000000000 --- a/tools/net/ynl/generated/ethtool-user.h +++ /dev/null @@ -1,5535 +0,0 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ -/* Do not edit directly, auto-generated from: */ -/* Documentation/netlink/specs/ethtool.yaml */ -/* YNL-GEN user header */ -/* YNL-ARG --user-header linux/ethtool_netlink.h --exclude-op stats-get */ - -#ifndef _LINUX_ETHTOOL_GEN_H -#define _LINUX_ETHTOOL_GEN_H - -#include <stdlib.h> -#include <string.h> -#include <linux/types.h> -#include <linux/ethtool.h> - -struct ynl_sock; - -extern const struct ynl_family ynl_ethtool_family; - -/* Enums */ -const char *ethtool_op_str(int op); -const char *ethtool_udp_tunnel_type_str(int value); -const char *ethtool_stringset_str(enum ethtool_stringset value); - -/* Common nested types */ -struct ethtool_header { - struct { - __u32 dev_index:1; - __u32 dev_name_len; - __u32 flags:1; - } _present; - - __u32 dev_index; - char *dev_name; - __u32 flags; -}; - -struct ethtool_pause_stat { - struct { - __u32 tx_frames:1; - __u32 rx_frames:1; - } _present; - - __u64 tx_frames; - __u64 rx_frames; -}; - -struct ethtool_cable_test_tdr_cfg { - struct { - __u32 first:1; - __u32 last:1; - __u32 step:1; - __u32 pair:1; - } _present; - - __u32 first; - __u32 last; - __u32 step; - __u8 pair; -}; - -struct ethtool_fec_stat { - struct { - __u32 corrected_len; - __u32 uncorr_len; - __u32 corr_bits_len; - } _present; - - void *corrected; - void *uncorr; - void *corr_bits; -}; - -struct ethtool_mm_stat { - struct { - __u32 reassembly_errors:1; - __u32 smd_errors:1; - __u32 reassembly_ok:1; - __u32 rx_frag_count:1; - __u32 tx_frag_count:1; - __u32 hold_count:1; - } _present; - - __u64 reassembly_errors; - __u64 smd_errors; - __u64 reassembly_ok; - __u64 rx_frag_count; - __u64 tx_frag_count; - __u64 hold_count; -}; - -struct ethtool_cable_result { - struct { - __u32 pair:1; - __u32 code:1; - } _present; - - __u8 pair; - __u8 code; -}; - -struct ethtool_cable_fault_length { - struct { - __u32 pair:1; - __u32 cm:1; - } _present; - - __u8 pair; - __u32 cm; -}; - -struct ethtool_bitset_bit { - struct { - __u32 index:1; - __u32 name_len; - __u32 value:1; - } _present; - - __u32 index; - char *name; -}; - -struct ethtool_tunnel_udp_entry { - struct { - __u32 port:1; - __u32 type:1; - } _present; - - __u16 port /* big-endian */; - __u32 type; -}; - -struct ethtool_string { - struct { - __u32 index:1; - __u32 value_len; - } _present; - - __u32 index; - char *value; -}; - -struct ethtool_cable_nest { - struct { - __u32 result:1; - __u32 fault_length:1; - } _present; - - struct ethtool_cable_result result; - struct ethtool_cable_fault_length fault_length; -}; - -struct ethtool_bitset_bits { - unsigned int n_bit; - struct ethtool_bitset_bit *bit; -}; - -struct ethtool_strings { - unsigned int n_string; - struct ethtool_string *string; -}; - -struct ethtool_bitset { - struct { - __u32 nomask:1; - __u32 size:1; - __u32 bits:1; - } _present; - - __u32 size; - struct ethtool_bitset_bits bits; -}; - -struct ethtool_stringset_ { - struct { - __u32 id:1; - __u32 count:1; - } _present; - - __u32 id; - __u32 count; - unsigned int n_strings; - struct ethtool_strings *strings; -}; - -struct ethtool_tunnel_udp_table { - struct { - __u32 size:1; - __u32 types:1; - } _present; - - __u32 size; - struct ethtool_bitset types; - unsigned int n_entry; - struct ethtool_tunnel_udp_entry *entry; -}; - -struct ethtool_stringsets { - unsigned int n_stringset; - struct ethtool_stringset_ *stringset; -}; - -struct ethtool_tunnel_udp { - struct { - __u32 table:1; - } _present; - - struct ethtool_tunnel_udp_table table; -}; - -/* ============== ETHTOOL_MSG_STRSET_GET ============== */ -/* ETHTOOL_MSG_STRSET_GET - do */ -struct ethtool_strset_get_req { - struct { - __u32 header:1; - __u32 stringsets:1; - __u32 counts_only:1; - } _present; - - struct ethtool_header header; - struct ethtool_stringsets stringsets; -}; - -static inline struct ethtool_strset_get_req *ethtool_strset_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_strset_get_req)); -} -void ethtool_strset_get_req_free(struct ethtool_strset_get_req *req); - -static inline void -ethtool_strset_get_req_set_header_dev_index(struct ethtool_strset_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_strset_get_req_set_header_dev_name(struct ethtool_strset_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_strset_get_req_set_header_flags(struct ethtool_strset_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -__ethtool_strset_get_req_set_stringsets_stringset(struct ethtool_strset_get_req *req, - struct ethtool_stringset_ *stringset, - unsigned int n_stringset) -{ - free(req->stringsets.stringset); - req->stringsets.stringset = stringset; - req->stringsets.n_stringset = n_stringset; -} -static inline void -ethtool_strset_get_req_set_counts_only(struct ethtool_strset_get_req *req) -{ - req->_present.counts_only = 1; -} - -struct ethtool_strset_get_rsp { - struct { - __u32 header:1; - __u32 stringsets:1; - } _present; - - struct ethtool_header header; - struct ethtool_stringsets stringsets; -}; - -void ethtool_strset_get_rsp_free(struct ethtool_strset_get_rsp *rsp); - -/* - * Get string set from the kernel. - */ -struct ethtool_strset_get_rsp * -ethtool_strset_get(struct ynl_sock *ys, struct ethtool_strset_get_req *req); - -/* ETHTOOL_MSG_STRSET_GET - dump */ -struct ethtool_strset_get_req_dump { - struct { - __u32 header:1; - __u32 stringsets:1; - __u32 counts_only:1; - } _present; - - struct ethtool_header header; - struct ethtool_stringsets stringsets; -}; - -static inline struct ethtool_strset_get_req_dump * -ethtool_strset_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_strset_get_req_dump)); -} -void ethtool_strset_get_req_dump_free(struct ethtool_strset_get_req_dump *req); - -static inline void -ethtool_strset_get_req_dump_set_header_dev_index(struct ethtool_strset_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_strset_get_req_dump_set_header_dev_name(struct ethtool_strset_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_strset_get_req_dump_set_header_flags(struct ethtool_strset_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -__ethtool_strset_get_req_dump_set_stringsets_stringset(struct ethtool_strset_get_req_dump *req, - struct ethtool_stringset_ *stringset, - unsigned int n_stringset) -{ - free(req->stringsets.stringset); - req->stringsets.stringset = stringset; - req->stringsets.n_stringset = n_stringset; -} -static inline void -ethtool_strset_get_req_dump_set_counts_only(struct ethtool_strset_get_req_dump *req) -{ - req->_present.counts_only = 1; -} - -struct ethtool_strset_get_list { - struct ethtool_strset_get_list *next; - struct ethtool_strset_get_rsp obj __attribute__ ((aligned (8))); -}; - -void ethtool_strset_get_list_free(struct ethtool_strset_get_list *rsp); - -struct ethtool_strset_get_list * -ethtool_strset_get_dump(struct ynl_sock *ys, - struct ethtool_strset_get_req_dump *req); - -/* ============== ETHTOOL_MSG_LINKINFO_GET ============== */ -/* ETHTOOL_MSG_LINKINFO_GET - do */ -struct ethtool_linkinfo_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_linkinfo_get_req * -ethtool_linkinfo_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_linkinfo_get_req)); -} -void ethtool_linkinfo_get_req_free(struct ethtool_linkinfo_get_req *req); - -static inline void -ethtool_linkinfo_get_req_set_header_dev_index(struct ethtool_linkinfo_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_linkinfo_get_req_set_header_dev_name(struct ethtool_linkinfo_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_linkinfo_get_req_set_header_flags(struct ethtool_linkinfo_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_linkinfo_get_rsp { - struct { - __u32 header:1; - __u32 port:1; - __u32 phyaddr:1; - __u32 tp_mdix:1; - __u32 tp_mdix_ctrl:1; - __u32 transceiver:1; - } _present; - - struct ethtool_header header; - __u8 port; - __u8 phyaddr; - __u8 tp_mdix; - __u8 tp_mdix_ctrl; - __u8 transceiver; -}; - -void ethtool_linkinfo_get_rsp_free(struct ethtool_linkinfo_get_rsp *rsp); - -/* - * Get link info. - */ -struct ethtool_linkinfo_get_rsp * -ethtool_linkinfo_get(struct ynl_sock *ys, struct ethtool_linkinfo_get_req *req); - -/* ETHTOOL_MSG_LINKINFO_GET - dump */ -struct ethtool_linkinfo_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_linkinfo_get_req_dump * -ethtool_linkinfo_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_linkinfo_get_req_dump)); -} -void -ethtool_linkinfo_get_req_dump_free(struct ethtool_linkinfo_get_req_dump *req); - -static inline void -ethtool_linkinfo_get_req_dump_set_header_dev_index(struct ethtool_linkinfo_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_linkinfo_get_req_dump_set_header_dev_name(struct ethtool_linkinfo_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_linkinfo_get_req_dump_set_header_flags(struct ethtool_linkinfo_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_linkinfo_get_list { - struct ethtool_linkinfo_get_list *next; - struct ethtool_linkinfo_get_rsp obj __attribute__ ((aligned (8))); -}; - -void ethtool_linkinfo_get_list_free(struct ethtool_linkinfo_get_list *rsp); - -struct ethtool_linkinfo_get_list * -ethtool_linkinfo_get_dump(struct ynl_sock *ys, - struct ethtool_linkinfo_get_req_dump *req); - -/* ETHTOOL_MSG_LINKINFO_GET - notify */ -struct ethtool_linkinfo_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_linkinfo_get_ntf *ntf); - struct ethtool_linkinfo_get_rsp obj __attribute__ ((aligned (8))); -}; - -void ethtool_linkinfo_get_ntf_free(struct ethtool_linkinfo_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_LINKINFO_SET ============== */ -/* ETHTOOL_MSG_LINKINFO_SET - do */ -struct ethtool_linkinfo_set_req { - struct { - __u32 header:1; - __u32 port:1; - __u32 phyaddr:1; - __u32 tp_mdix:1; - __u32 tp_mdix_ctrl:1; - __u32 transceiver:1; - } _present; - - struct ethtool_header header; - __u8 port; - __u8 phyaddr; - __u8 tp_mdix; - __u8 tp_mdix_ctrl; - __u8 transceiver; -}; - -static inline struct ethtool_linkinfo_set_req * -ethtool_linkinfo_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_linkinfo_set_req)); -} -void ethtool_linkinfo_set_req_free(struct ethtool_linkinfo_set_req *req); - -static inline void -ethtool_linkinfo_set_req_set_header_dev_index(struct ethtool_linkinfo_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_linkinfo_set_req_set_header_dev_name(struct ethtool_linkinfo_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_linkinfo_set_req_set_header_flags(struct ethtool_linkinfo_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_linkinfo_set_req_set_port(struct ethtool_linkinfo_set_req *req, - __u8 port) -{ - req->_present.port = 1; - req->port = port; -} -static inline void -ethtool_linkinfo_set_req_set_phyaddr(struct ethtool_linkinfo_set_req *req, - __u8 phyaddr) -{ - req->_present.phyaddr = 1; - req->phyaddr = phyaddr; -} -static inline void -ethtool_linkinfo_set_req_set_tp_mdix(struct ethtool_linkinfo_set_req *req, - __u8 tp_mdix) -{ - req->_present.tp_mdix = 1; - req->tp_mdix = tp_mdix; -} -static inline void -ethtool_linkinfo_set_req_set_tp_mdix_ctrl(struct ethtool_linkinfo_set_req *req, - __u8 tp_mdix_ctrl) -{ - req->_present.tp_mdix_ctrl = 1; - req->tp_mdix_ctrl = tp_mdix_ctrl; -} -static inline void -ethtool_linkinfo_set_req_set_transceiver(struct ethtool_linkinfo_set_req *req, - __u8 transceiver) -{ - req->_present.transceiver = 1; - req->transceiver = transceiver; -} - -/* - * Set link info. - */ -int ethtool_linkinfo_set(struct ynl_sock *ys, - struct ethtool_linkinfo_set_req *req); - -/* ============== ETHTOOL_MSG_LINKMODES_GET ============== */ -/* ETHTOOL_MSG_LINKMODES_GET - do */ -struct ethtool_linkmodes_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_linkmodes_get_req * -ethtool_linkmodes_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_linkmodes_get_req)); -} -void ethtool_linkmodes_get_req_free(struct ethtool_linkmodes_get_req *req); - -static inline void -ethtool_linkmodes_get_req_set_header_dev_index(struct ethtool_linkmodes_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_linkmodes_get_req_set_header_dev_name(struct ethtool_linkmodes_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_linkmodes_get_req_set_header_flags(struct ethtool_linkmodes_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_linkmodes_get_rsp { - struct { - __u32 header:1; - __u32 autoneg:1; - __u32 ours:1; - __u32 peer:1; - __u32 speed:1; - __u32 duplex:1; - __u32 master_slave_cfg:1; - __u32 master_slave_state:1; - __u32 lanes:1; - __u32 rate_matching:1; - } _present; - - struct ethtool_header header; - __u8 autoneg; - struct ethtool_bitset ours; - struct ethtool_bitset peer; - __u32 speed; - __u8 duplex; - __u8 master_slave_cfg; - __u8 master_slave_state; - __u32 lanes; - __u8 rate_matching; -}; - -void ethtool_linkmodes_get_rsp_free(struct ethtool_linkmodes_get_rsp *rsp); - -/* - * Get link modes. - */ -struct ethtool_linkmodes_get_rsp * -ethtool_linkmodes_get(struct ynl_sock *ys, - struct ethtool_linkmodes_get_req *req); - -/* ETHTOOL_MSG_LINKMODES_GET - dump */ -struct ethtool_linkmodes_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_linkmodes_get_req_dump * -ethtool_linkmodes_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_linkmodes_get_req_dump)); -} -void -ethtool_linkmodes_get_req_dump_free(struct ethtool_linkmodes_get_req_dump *req); - -static inline void -ethtool_linkmodes_get_req_dump_set_header_dev_index(struct ethtool_linkmodes_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_linkmodes_get_req_dump_set_header_dev_name(struct ethtool_linkmodes_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_linkmodes_get_req_dump_set_header_flags(struct ethtool_linkmodes_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_linkmodes_get_list { - struct ethtool_linkmodes_get_list *next; - struct ethtool_linkmodes_get_rsp obj __attribute__ ((aligned (8))); -}; - -void ethtool_linkmodes_get_list_free(struct ethtool_linkmodes_get_list *rsp); - -struct ethtool_linkmodes_get_list * -ethtool_linkmodes_get_dump(struct ynl_sock *ys, - struct ethtool_linkmodes_get_req_dump *req); - -/* ETHTOOL_MSG_LINKMODES_GET - notify */ -struct ethtool_linkmodes_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_linkmodes_get_ntf *ntf); - struct ethtool_linkmodes_get_rsp obj __attribute__ ((aligned (8))); -}; - -void ethtool_linkmodes_get_ntf_free(struct ethtool_linkmodes_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_LINKMODES_SET ============== */ -/* ETHTOOL_MSG_LINKMODES_SET - do */ -struct ethtool_linkmodes_set_req { - struct { - __u32 header:1; - __u32 autoneg:1; - __u32 ours:1; - __u32 peer:1; - __u32 speed:1; - __u32 duplex:1; - __u32 master_slave_cfg:1; - __u32 master_slave_state:1; - __u32 lanes:1; - __u32 rate_matching:1; - } _present; - - struct ethtool_header header; - __u8 autoneg; - struct ethtool_bitset ours; - struct ethtool_bitset peer; - __u32 speed; - __u8 duplex; - __u8 master_slave_cfg; - __u8 master_slave_state; - __u32 lanes; - __u8 rate_matching; -}; - -static inline struct ethtool_linkmodes_set_req * -ethtool_linkmodes_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_linkmodes_set_req)); -} -void ethtool_linkmodes_set_req_free(struct ethtool_linkmodes_set_req *req); - -static inline void -ethtool_linkmodes_set_req_set_header_dev_index(struct ethtool_linkmodes_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_linkmodes_set_req_set_header_dev_name(struct ethtool_linkmodes_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_linkmodes_set_req_set_header_flags(struct ethtool_linkmodes_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_linkmodes_set_req_set_autoneg(struct ethtool_linkmodes_set_req *req, - __u8 autoneg) -{ - req->_present.autoneg = 1; - req->autoneg = autoneg; -} -static inline void -ethtool_linkmodes_set_req_set_ours_nomask(struct ethtool_linkmodes_set_req *req) -{ - req->_present.ours = 1; - req->ours._present.nomask = 1; -} -static inline void -ethtool_linkmodes_set_req_set_ours_size(struct ethtool_linkmodes_set_req *req, - __u32 size) -{ - req->_present.ours = 1; - req->ours._present.size = 1; - req->ours.size = size; -} -static inline void -__ethtool_linkmodes_set_req_set_ours_bits_bit(struct ethtool_linkmodes_set_req *req, - struct ethtool_bitset_bit *bit, - unsigned int n_bit) -{ - free(req->ours.bits.bit); - req->ours.bits.bit = bit; - req->ours.bits.n_bit = n_bit; -} -static inline void -ethtool_linkmodes_set_req_set_peer_nomask(struct ethtool_linkmodes_set_req *req) -{ - req->_present.peer = 1; - req->peer._present.nomask = 1; -} -static inline void -ethtool_linkmodes_set_req_set_peer_size(struct ethtool_linkmodes_set_req *req, - __u32 size) -{ - req->_present.peer = 1; - req->peer._present.size = 1; - req->peer.size = size; -} -static inline void -__ethtool_linkmodes_set_req_set_peer_bits_bit(struct ethtool_linkmodes_set_req *req, - struct ethtool_bitset_bit *bit, - unsigned int n_bit) -{ - free(req->peer.bits.bit); - req->peer.bits.bit = bit; - req->peer.bits.n_bit = n_bit; -} -static inline void -ethtool_linkmodes_set_req_set_speed(struct ethtool_linkmodes_set_req *req, - __u32 speed) -{ - req->_present.speed = 1; - req->speed = speed; -} -static inline void -ethtool_linkmodes_set_req_set_duplex(struct ethtool_linkmodes_set_req *req, - __u8 duplex) -{ - req->_present.duplex = 1; - req->duplex = duplex; -} -static inline void -ethtool_linkmodes_set_req_set_master_slave_cfg(struct ethtool_linkmodes_set_req *req, - __u8 master_slave_cfg) -{ - req->_present.master_slave_cfg = 1; - req->master_slave_cfg = master_slave_cfg; -} -static inline void -ethtool_linkmodes_set_req_set_master_slave_state(struct ethtool_linkmodes_set_req *req, - __u8 master_slave_state) -{ - req->_present.master_slave_state = 1; - req->master_slave_state = master_slave_state; -} -static inline void -ethtool_linkmodes_set_req_set_lanes(struct ethtool_linkmodes_set_req *req, - __u32 lanes) -{ - req->_present.lanes = 1; - req->lanes = lanes; -} -static inline void -ethtool_linkmodes_set_req_set_rate_matching(struct ethtool_linkmodes_set_req *req, - __u8 rate_matching) -{ - req->_present.rate_matching = 1; - req->rate_matching = rate_matching; -} - -/* - * Set link modes. - */ -int ethtool_linkmodes_set(struct ynl_sock *ys, - struct ethtool_linkmodes_set_req *req); - -/* ============== ETHTOOL_MSG_LINKSTATE_GET ============== */ -/* ETHTOOL_MSG_LINKSTATE_GET - do */ -struct ethtool_linkstate_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_linkstate_get_req * -ethtool_linkstate_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_linkstate_get_req)); -} -void ethtool_linkstate_get_req_free(struct ethtool_linkstate_get_req *req); - -static inline void -ethtool_linkstate_get_req_set_header_dev_index(struct ethtool_linkstate_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_linkstate_get_req_set_header_dev_name(struct ethtool_linkstate_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_linkstate_get_req_set_header_flags(struct ethtool_linkstate_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_linkstate_get_rsp { - struct { - __u32 header:1; - __u32 link:1; - __u32 sqi:1; - __u32 sqi_max:1; - __u32 ext_state:1; - __u32 ext_substate:1; - __u32 ext_down_cnt:1; - } _present; - - struct ethtool_header header; - __u8 link; - __u32 sqi; - __u32 sqi_max; - __u8 ext_state; - __u8 ext_substate; - __u32 ext_down_cnt; -}; - -void ethtool_linkstate_get_rsp_free(struct ethtool_linkstate_get_rsp *rsp); - -/* - * Get link state. - */ -struct ethtool_linkstate_get_rsp * -ethtool_linkstate_get(struct ynl_sock *ys, - struct ethtool_linkstate_get_req *req); - -/* ETHTOOL_MSG_LINKSTATE_GET - dump */ -struct ethtool_linkstate_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_linkstate_get_req_dump * -ethtool_linkstate_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_linkstate_get_req_dump)); -} -void -ethtool_linkstate_get_req_dump_free(struct ethtool_linkstate_get_req_dump *req); - -static inline void -ethtool_linkstate_get_req_dump_set_header_dev_index(struct ethtool_linkstate_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_linkstate_get_req_dump_set_header_dev_name(struct ethtool_linkstate_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_linkstate_get_req_dump_set_header_flags(struct ethtool_linkstate_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_linkstate_get_list { - struct ethtool_linkstate_get_list *next; - struct ethtool_linkstate_get_rsp obj __attribute__ ((aligned (8))); -}; - -void ethtool_linkstate_get_list_free(struct ethtool_linkstate_get_list *rsp); - -struct ethtool_linkstate_get_list * -ethtool_linkstate_get_dump(struct ynl_sock *ys, - struct ethtool_linkstate_get_req_dump *req); - -/* ============== ETHTOOL_MSG_DEBUG_GET ============== */ -/* ETHTOOL_MSG_DEBUG_GET - do */ -struct ethtool_debug_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_debug_get_req *ethtool_debug_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_debug_get_req)); -} -void ethtool_debug_get_req_free(struct ethtool_debug_get_req *req); - -static inline void -ethtool_debug_get_req_set_header_dev_index(struct ethtool_debug_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_debug_get_req_set_header_dev_name(struct ethtool_debug_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_debug_get_req_set_header_flags(struct ethtool_debug_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_debug_get_rsp { - struct { - __u32 header:1; - __u32 msgmask:1; - } _present; - - struct ethtool_header header; - struct ethtool_bitset msgmask; -}; - -void ethtool_debug_get_rsp_free(struct ethtool_debug_get_rsp *rsp); - -/* - * Get debug message mask. - */ -struct ethtool_debug_get_rsp * -ethtool_debug_get(struct ynl_sock *ys, struct ethtool_debug_get_req *req); - -/* ETHTOOL_MSG_DEBUG_GET - dump */ -struct ethtool_debug_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_debug_get_req_dump * -ethtool_debug_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_debug_get_req_dump)); -} -void ethtool_debug_get_req_dump_free(struct ethtool_debug_get_req_dump *req); - -static inline void -ethtool_debug_get_req_dump_set_header_dev_index(struct ethtool_debug_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_debug_get_req_dump_set_header_dev_name(struct ethtool_debug_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_debug_get_req_dump_set_header_flags(struct ethtool_debug_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_debug_get_list { - struct ethtool_debug_get_list *next; - struct ethtool_debug_get_rsp obj __attribute__ ((aligned (8))); -}; - -void ethtool_debug_get_list_free(struct ethtool_debug_get_list *rsp); - -struct ethtool_debug_get_list * -ethtool_debug_get_dump(struct ynl_sock *ys, - struct ethtool_debug_get_req_dump *req); - -/* ETHTOOL_MSG_DEBUG_GET - notify */ -struct ethtool_debug_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_debug_get_ntf *ntf); - struct ethtool_debug_get_rsp obj __attribute__ ((aligned (8))); -}; - -void ethtool_debug_get_ntf_free(struct ethtool_debug_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_DEBUG_SET ============== */ -/* ETHTOOL_MSG_DEBUG_SET - do */ -struct ethtool_debug_set_req { - struct { - __u32 header:1; - __u32 msgmask:1; - } _present; - - struct ethtool_header header; - struct ethtool_bitset msgmask; -}; - -static inline struct ethtool_debug_set_req *ethtool_debug_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_debug_set_req)); -} -void ethtool_debug_set_req_free(struct ethtool_debug_set_req *req); - -static inline void -ethtool_debug_set_req_set_header_dev_index(struct ethtool_debug_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_debug_set_req_set_header_dev_name(struct ethtool_debug_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_debug_set_req_set_header_flags(struct ethtool_debug_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_debug_set_req_set_msgmask_nomask(struct ethtool_debug_set_req *req) -{ - req->_present.msgmask = 1; - req->msgmask._present.nomask = 1; -} -static inline void -ethtool_debug_set_req_set_msgmask_size(struct ethtool_debug_set_req *req, - __u32 size) -{ - req->_present.msgmask = 1; - req->msgmask._present.size = 1; - req->msgmask.size = size; -} -static inline void -__ethtool_debug_set_req_set_msgmask_bits_bit(struct ethtool_debug_set_req *req, - struct ethtool_bitset_bit *bit, - unsigned int n_bit) -{ - free(req->msgmask.bits.bit); - req->msgmask.bits.bit = bit; - req->msgmask.bits.n_bit = n_bit; -} - -/* - * Set debug message mask. - */ -int ethtool_debug_set(struct ynl_sock *ys, struct ethtool_debug_set_req *req); - -/* ============== ETHTOOL_MSG_WOL_GET ============== */ -/* ETHTOOL_MSG_WOL_GET - do */ -struct ethtool_wol_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_wol_get_req *ethtool_wol_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_wol_get_req)); -} -void ethtool_wol_get_req_free(struct ethtool_wol_get_req *req); - -static inline void -ethtool_wol_get_req_set_header_dev_index(struct ethtool_wol_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_wol_get_req_set_header_dev_name(struct ethtool_wol_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_wol_get_req_set_header_flags(struct ethtool_wol_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_wol_get_rsp { - struct { - __u32 header:1; - __u32 modes:1; - __u32 sopass_len; - } _present; - - struct ethtool_header header; - struct ethtool_bitset modes; - void *sopass; -}; - -void ethtool_wol_get_rsp_free(struct ethtool_wol_get_rsp *rsp); - -/* - * Get WOL params. - */ -struct ethtool_wol_get_rsp * -ethtool_wol_get(struct ynl_sock *ys, struct ethtool_wol_get_req *req); - -/* ETHTOOL_MSG_WOL_GET - dump */ -struct ethtool_wol_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_wol_get_req_dump * -ethtool_wol_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_wol_get_req_dump)); -} -void ethtool_wol_get_req_dump_free(struct ethtool_wol_get_req_dump *req); - -static inline void -ethtool_wol_get_req_dump_set_header_dev_index(struct ethtool_wol_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_wol_get_req_dump_set_header_dev_name(struct ethtool_wol_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_wol_get_req_dump_set_header_flags(struct ethtool_wol_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_wol_get_list { - struct ethtool_wol_get_list *next; - struct ethtool_wol_get_rsp obj __attribute__ ((aligned (8))); -}; - -void ethtool_wol_get_list_free(struct ethtool_wol_get_list *rsp); - -struct ethtool_wol_get_list * -ethtool_wol_get_dump(struct ynl_sock *ys, struct ethtool_wol_get_req_dump *req); - -/* ETHTOOL_MSG_WOL_GET - notify */ -struct ethtool_wol_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_wol_get_ntf *ntf); - struct ethtool_wol_get_rsp obj __attribute__ ((aligned (8))); -}; - -void ethtool_wol_get_ntf_free(struct ethtool_wol_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_WOL_SET ============== */ -/* ETHTOOL_MSG_WOL_SET - do */ -struct ethtool_wol_set_req { - struct { - __u32 header:1; - __u32 modes:1; - __u32 sopass_len; - } _present; - - struct ethtool_header header; - struct ethtool_bitset modes; - void *sopass; -}; - -static inline struct ethtool_wol_set_req *ethtool_wol_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_wol_set_req)); -} -void ethtool_wol_set_req_free(struct ethtool_wol_set_req *req); - -static inline void -ethtool_wol_set_req_set_header_dev_index(struct ethtool_wol_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_wol_set_req_set_header_dev_name(struct ethtool_wol_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_wol_set_req_set_header_flags(struct ethtool_wol_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_wol_set_req_set_modes_nomask(struct ethtool_wol_set_req *req) -{ - req->_present.modes = 1; - req->modes._present.nomask = 1; -} -static inline void -ethtool_wol_set_req_set_modes_size(struct ethtool_wol_set_req *req, __u32 size) -{ - req->_present.modes = 1; - req->modes._present.size = 1; - req->modes.size = size; -} -static inline void -__ethtool_wol_set_req_set_modes_bits_bit(struct ethtool_wol_set_req *req, - struct ethtool_bitset_bit *bit, - unsigned int n_bit) -{ - free(req->modes.bits.bit); - req->modes.bits.bit = bit; - req->modes.bits.n_bit = n_bit; -} -static inline void -ethtool_wol_set_req_set_sopass(struct ethtool_wol_set_req *req, - const void *sopass, size_t len) -{ - free(req->sopass); - req->_present.sopass_len = len; - req->sopass = malloc(req->_present.sopass_len); - memcpy(req->sopass, sopass, req->_present.sopass_len); -} - -/* - * Set WOL params. - */ -int ethtool_wol_set(struct ynl_sock *ys, struct ethtool_wol_set_req *req); - -/* ============== ETHTOOL_MSG_FEATURES_GET ============== */ -/* ETHTOOL_MSG_FEATURES_GET - do */ -struct ethtool_features_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_features_get_req * -ethtool_features_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_features_get_req)); -} -void ethtool_features_get_req_free(struct ethtool_features_get_req *req); - -static inline void -ethtool_features_get_req_set_header_dev_index(struct ethtool_features_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_features_get_req_set_header_dev_name(struct ethtool_features_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_features_get_req_set_header_flags(struct ethtool_features_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_features_get_rsp { - struct { - __u32 header:1; - __u32 hw:1; - __u32 wanted:1; - __u32 active:1; - __u32 nochange:1; - } _present; - - struct ethtool_header header; - struct ethtool_bitset hw; - struct ethtool_bitset wanted; - struct ethtool_bitset active; - struct ethtool_bitset nochange; -}; - -void ethtool_features_get_rsp_free(struct ethtool_features_get_rsp *rsp); - -/* - * Get features. - */ -struct ethtool_features_get_rsp * -ethtool_features_get(struct ynl_sock *ys, struct ethtool_features_get_req *req); - -/* ETHTOOL_MSG_FEATURES_GET - dump */ -struct ethtool_features_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_features_get_req_dump * -ethtool_features_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_features_get_req_dump)); -} -void -ethtool_features_get_req_dump_free(struct ethtool_features_get_req_dump *req); - -static inline void -ethtool_features_get_req_dump_set_header_dev_index(struct ethtool_features_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_features_get_req_dump_set_header_dev_name(struct ethtool_features_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_features_get_req_dump_set_header_flags(struct ethtool_features_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_features_get_list { - struct ethtool_features_get_list *next; - struct ethtool_features_get_rsp obj __attribute__ ((aligned (8))); -}; - -void ethtool_features_get_list_free(struct ethtool_features_get_list *rsp); - -struct ethtool_features_get_list * -ethtool_features_get_dump(struct ynl_sock *ys, - struct ethtool_features_get_req_dump *req); - -/* ETHTOOL_MSG_FEATURES_GET - notify */ -struct ethtool_features_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_features_get_ntf *ntf); - struct ethtool_features_get_rsp obj __attribute__ ((aligned (8))); -}; - -void ethtool_features_get_ntf_free(struct ethtool_features_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_FEATURES_SET ============== */ -/* ETHTOOL_MSG_FEATURES_SET - do */ -struct ethtool_features_set_req { - struct { - __u32 header:1; - __u32 hw:1; - __u32 wanted:1; - __u32 active:1; - __u32 nochange:1; - } _present; - - struct ethtool_header header; - struct ethtool_bitset hw; - struct ethtool_bitset wanted; - struct ethtool_bitset active; - struct ethtool_bitset nochange; -}; - -static inline struct ethtool_features_set_req * -ethtool_features_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_features_set_req)); -} -void ethtool_features_set_req_free(struct ethtool_features_set_req *req); - -static inline void -ethtool_features_set_req_set_header_dev_index(struct ethtool_features_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_features_set_req_set_header_dev_name(struct ethtool_features_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_features_set_req_set_header_flags(struct ethtool_features_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_features_set_req_set_hw_nomask(struct ethtool_features_set_req *req) -{ - req->_present.hw = 1; - req->hw._present.nomask = 1; -} -static inline void -ethtool_features_set_req_set_hw_size(struct ethtool_features_set_req *req, - __u32 size) -{ - req->_present.hw = 1; - req->hw._present.size = 1; - req->hw.size = size; -} -static inline void -__ethtool_features_set_req_set_hw_bits_bit(struct ethtool_features_set_req *req, - struct ethtool_bitset_bit *bit, - unsigned int n_bit) -{ - free(req->hw.bits.bit); - req->hw.bits.bit = bit; - req->hw.bits.n_bit = n_bit; -} -static inline void -ethtool_features_set_req_set_wanted_nomask(struct ethtool_features_set_req *req) -{ - req->_present.wanted = 1; - req->wanted._present.nomask = 1; -} -static inline void -ethtool_features_set_req_set_wanted_size(struct ethtool_features_set_req *req, - __u32 size) -{ - req->_present.wanted = 1; - req->wanted._present.size = 1; - req->wanted.size = size; -} -static inline void -__ethtool_features_set_req_set_wanted_bits_bit(struct ethtool_features_set_req *req, - struct ethtool_bitset_bit *bit, - unsigned int n_bit) -{ - free(req->wanted.bits.bit); - req->wanted.bits.bit = bit; - req->wanted.bits.n_bit = n_bit; -} -static inline void -ethtool_features_set_req_set_active_nomask(struct ethtool_features_set_req *req) -{ - req->_present.active = 1; - req->active._present.nomask = 1; -} -static inline void -ethtool_features_set_req_set_active_size(struct ethtool_features_set_req *req, - __u32 size) -{ - req->_present.active = 1; - req->active._present.size = 1; - req->active.size = size; -} -static inline void -__ethtool_features_set_req_set_active_bits_bit(struct ethtool_features_set_req *req, - struct ethtool_bitset_bit *bit, - unsigned int n_bit) -{ - free(req->active.bits.bit); - req->active.bits.bit = bit; - req->active.bits.n_bit = n_bit; -} -static inline void -ethtool_features_set_req_set_nochange_nomask(struct ethtool_features_set_req *req) -{ - req->_present.nochange = 1; - req->nochange._present.nomask = 1; -} -static inline void -ethtool_features_set_req_set_nochange_size(struct ethtool_features_set_req *req, - __u32 size) -{ - req->_present.nochange = 1; - req->nochange._present.size = 1; - req->nochange.size = size; -} -static inline void -__ethtool_features_set_req_set_nochange_bits_bit(struct ethtool_features_set_req *req, - struct ethtool_bitset_bit *bit, - unsigned int n_bit) -{ - free(req->nochange.bits.bit); - req->nochange.bits.bit = bit; - req->nochange.bits.n_bit = n_bit; -} - -struct ethtool_features_set_rsp { - struct { - __u32 header:1; - __u32 hw:1; - __u32 wanted:1; - __u32 active:1; - __u32 nochange:1; - } _present; - - struct ethtool_header header; - struct ethtool_bitset hw; - struct ethtool_bitset wanted; - struct ethtool_bitset active; - struct ethtool_bitset nochange; -}; - -void ethtool_features_set_rsp_free(struct ethtool_features_set_rsp *rsp); - -/* - * Set features. - */ -struct ethtool_features_set_rsp * -ethtool_features_set(struct ynl_sock *ys, struct ethtool_features_set_req *req); - -/* ============== ETHTOOL_MSG_PRIVFLAGS_GET ============== */ -/* ETHTOOL_MSG_PRIVFLAGS_GET - do */ -struct ethtool_privflags_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_privflags_get_req * -ethtool_privflags_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_privflags_get_req)); -} -void ethtool_privflags_get_req_free(struct ethtool_privflags_get_req *req); - -static inline void -ethtool_privflags_get_req_set_header_dev_index(struct ethtool_privflags_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_privflags_get_req_set_header_dev_name(struct ethtool_privflags_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_privflags_get_req_set_header_flags(struct ethtool_privflags_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_privflags_get_rsp { - struct { - __u32 header:1; - __u32 flags:1; - } _present; - - struct ethtool_header header; - struct ethtool_bitset flags; -}; - -void ethtool_privflags_get_rsp_free(struct ethtool_privflags_get_rsp *rsp); - -/* - * Get device private flags. - */ -struct ethtool_privflags_get_rsp * -ethtool_privflags_get(struct ynl_sock *ys, - struct ethtool_privflags_get_req *req); - -/* ETHTOOL_MSG_PRIVFLAGS_GET - dump */ -struct ethtool_privflags_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_privflags_get_req_dump * -ethtool_privflags_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_privflags_get_req_dump)); -} -void -ethtool_privflags_get_req_dump_free(struct ethtool_privflags_get_req_dump *req); - -static inline void -ethtool_privflags_get_req_dump_set_header_dev_index(struct ethtool_privflags_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_privflags_get_req_dump_set_header_dev_name(struct ethtool_privflags_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_privflags_get_req_dump_set_header_flags(struct ethtool_privflags_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_privflags_get_list { - struct ethtool_privflags_get_list *next; - struct ethtool_privflags_get_rsp obj __attribute__ ((aligned (8))); -}; - -void ethtool_privflags_get_list_free(struct ethtool_privflags_get_list *rsp); - -struct ethtool_privflags_get_list * -ethtool_privflags_get_dump(struct ynl_sock *ys, - struct ethtool_privflags_get_req_dump *req); - -/* ETHTOOL_MSG_PRIVFLAGS_GET - notify */ -struct ethtool_privflags_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_privflags_get_ntf *ntf); - struct ethtool_privflags_get_rsp obj __attribute__ ((aligned (8))); -}; - -void ethtool_privflags_get_ntf_free(struct ethtool_privflags_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_PRIVFLAGS_SET ============== */ -/* ETHTOOL_MSG_PRIVFLAGS_SET - do */ -struct ethtool_privflags_set_req { - struct { - __u32 header:1; - __u32 flags:1; - } _present; - - struct ethtool_header header; - struct ethtool_bitset flags; -}; - -static inline struct ethtool_privflags_set_req * -ethtool_privflags_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_privflags_set_req)); -} -void ethtool_privflags_set_req_free(struct ethtool_privflags_set_req *req); - -static inline void -ethtool_privflags_set_req_set_header_dev_index(struct ethtool_privflags_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_privflags_set_req_set_header_dev_name(struct ethtool_privflags_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_privflags_set_req_set_header_flags(struct ethtool_privflags_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_privflags_set_req_set_flags_nomask(struct ethtool_privflags_set_req *req) -{ - req->_present.flags = 1; - req->flags._present.nomask = 1; -} -static inline void -ethtool_privflags_set_req_set_flags_size(struct ethtool_privflags_set_req *req, - __u32 size) -{ - req->_present.flags = 1; - req->flags._present.size = 1; - req->flags.size = size; -} -static inline void -__ethtool_privflags_set_req_set_flags_bits_bit(struct ethtool_privflags_set_req *req, - struct ethtool_bitset_bit *bit, - unsigned int n_bit) -{ - free(req->flags.bits.bit); - req->flags.bits.bit = bit; - req->flags.bits.n_bit = n_bit; -} - -/* - * Set device private flags. - */ -int ethtool_privflags_set(struct ynl_sock *ys, - struct ethtool_privflags_set_req *req); - -/* ============== ETHTOOL_MSG_RINGS_GET ============== */ -/* ETHTOOL_MSG_RINGS_GET - do */ -struct ethtool_rings_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_rings_get_req *ethtool_rings_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_rings_get_req)); -} -void ethtool_rings_get_req_free(struct ethtool_rings_get_req *req); - -static inline void -ethtool_rings_get_req_set_header_dev_index(struct ethtool_rings_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_rings_get_req_set_header_dev_name(struct ethtool_rings_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_rings_get_req_set_header_flags(struct ethtool_rings_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_rings_get_rsp { - struct { - __u32 header:1; - __u32 rx_max:1; - __u32 rx_mini_max:1; - __u32 rx_jumbo_max:1; - __u32 tx_max:1; - __u32 rx:1; - __u32 rx_mini:1; - __u32 rx_jumbo:1; - __u32 tx:1; - __u32 rx_buf_len:1; - __u32 tcp_data_split:1; - __u32 cqe_size:1; - __u32 tx_push:1; - __u32 rx_push:1; - __u32 tx_push_buf_len:1; - __u32 tx_push_buf_len_max:1; - } _present; - - struct ethtool_header header; - __u32 rx_max; - __u32 rx_mini_max; - __u32 rx_jumbo_max; - __u32 tx_max; - __u32 rx; - __u32 rx_mini; - __u32 rx_jumbo; - __u32 tx; - __u32 rx_buf_len; - __u8 tcp_data_split; - __u32 cqe_size; - __u8 tx_push; - __u8 rx_push; - __u32 tx_push_buf_len; - __u32 tx_push_buf_len_max; -}; - -void ethtool_rings_get_rsp_free(struct ethtool_rings_get_rsp *rsp); - -/* - * Get ring params. - */ -struct ethtool_rings_get_rsp * -ethtool_rings_get(struct ynl_sock *ys, struct ethtool_rings_get_req *req); - -/* ETHTOOL_MSG_RINGS_GET - dump */ -struct ethtool_rings_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_rings_get_req_dump * -ethtool_rings_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_rings_get_req_dump)); -} -void ethtool_rings_get_req_dump_free(struct ethtool_rings_get_req_dump *req); - -static inline void -ethtool_rings_get_req_dump_set_header_dev_index(struct ethtool_rings_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_rings_get_req_dump_set_header_dev_name(struct ethtool_rings_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_rings_get_req_dump_set_header_flags(struct ethtool_rings_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_rings_get_list { - struct ethtool_rings_get_list *next; - struct ethtool_rings_get_rsp obj __attribute__ ((aligned (8))); -}; - -void ethtool_rings_get_list_free(struct ethtool_rings_get_list *rsp); - -struct ethtool_rings_get_list * -ethtool_rings_get_dump(struct ynl_sock *ys, - struct ethtool_rings_get_req_dump *req); - -/* ETHTOOL_MSG_RINGS_GET - notify */ -struct ethtool_rings_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_rings_get_ntf *ntf); - struct ethtool_rings_get_rsp obj __attribute__ ((aligned (8))); -}; - -void ethtool_rings_get_ntf_free(struct ethtool_rings_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_RINGS_SET ============== */ -/* ETHTOOL_MSG_RINGS_SET - do */ -struct ethtool_rings_set_req { - struct { - __u32 header:1; - __u32 rx_max:1; - __u32 rx_mini_max:1; - __u32 rx_jumbo_max:1; - __u32 tx_max:1; - __u32 rx:1; - __u32 rx_mini:1; - __u32 rx_jumbo:1; - __u32 tx:1; - __u32 rx_buf_len:1; - __u32 tcp_data_split:1; - __u32 cqe_size:1; - __u32 tx_push:1; - __u32 rx_push:1; - __u32 tx_push_buf_len:1; - __u32 tx_push_buf_len_max:1; - } _present; - - struct ethtool_header header; - __u32 rx_max; - __u32 rx_mini_max; - __u32 rx_jumbo_max; - __u32 tx_max; - __u32 rx; - __u32 rx_mini; - __u32 rx_jumbo; - __u32 tx; - __u32 rx_buf_len; - __u8 tcp_data_split; - __u32 cqe_size; - __u8 tx_push; - __u8 rx_push; - __u32 tx_push_buf_len; - __u32 tx_push_buf_len_max; -}; - -static inline struct ethtool_rings_set_req *ethtool_rings_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_rings_set_req)); -} -void ethtool_rings_set_req_free(struct ethtool_rings_set_req *req); - -static inline void -ethtool_rings_set_req_set_header_dev_index(struct ethtool_rings_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_rings_set_req_set_header_dev_name(struct ethtool_rings_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_rings_set_req_set_header_flags(struct ethtool_rings_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_rings_set_req_set_rx_max(struct ethtool_rings_set_req *req, - __u32 rx_max) -{ - req->_present.rx_max = 1; - req->rx_max = rx_max; -} -static inline void -ethtool_rings_set_req_set_rx_mini_max(struct ethtool_rings_set_req *req, - __u32 rx_mini_max) -{ - req->_present.rx_mini_max = 1; - req->rx_mini_max = rx_mini_max; -} -static inline void -ethtool_rings_set_req_set_rx_jumbo_max(struct ethtool_rings_set_req *req, - __u32 rx_jumbo_max) -{ - req->_present.rx_jumbo_max = 1; - req->rx_jumbo_max = rx_jumbo_max; -} -static inline void -ethtool_rings_set_req_set_tx_max(struct ethtool_rings_set_req *req, - __u32 tx_max) -{ - req->_present.tx_max = 1; - req->tx_max = tx_max; -} -static inline void -ethtool_rings_set_req_set_rx(struct ethtool_rings_set_req *req, __u32 rx) -{ - req->_present.rx = 1; - req->rx = rx; -} -static inline void -ethtool_rings_set_req_set_rx_mini(struct ethtool_rings_set_req *req, - __u32 rx_mini) -{ - req->_present.rx_mini = 1; - req->rx_mini = rx_mini; -} -static inline void -ethtool_rings_set_req_set_rx_jumbo(struct ethtool_rings_set_req *req, - __u32 rx_jumbo) -{ - req->_present.rx_jumbo = 1; - req->rx_jumbo = rx_jumbo; -} -static inline void -ethtool_rings_set_req_set_tx(struct ethtool_rings_set_req *req, __u32 tx) -{ - req->_present.tx = 1; - req->tx = tx; -} -static inline void -ethtool_rings_set_req_set_rx_buf_len(struct ethtool_rings_set_req *req, - __u32 rx_buf_len) -{ - req->_present.rx_buf_len = 1; - req->rx_buf_len = rx_buf_len; -} -static inline void -ethtool_rings_set_req_set_tcp_data_split(struct ethtool_rings_set_req *req, - __u8 tcp_data_split) -{ - req->_present.tcp_data_split = 1; - req->tcp_data_split = tcp_data_split; -} -static inline void -ethtool_rings_set_req_set_cqe_size(struct ethtool_rings_set_req *req, - __u32 cqe_size) -{ - req->_present.cqe_size = 1; - req->cqe_size = cqe_size; -} -static inline void -ethtool_rings_set_req_set_tx_push(struct ethtool_rings_set_req *req, - __u8 tx_push) -{ - req->_present.tx_push = 1; - req->tx_push = tx_push; -} -static inline void -ethtool_rings_set_req_set_rx_push(struct ethtool_rings_set_req *req, - __u8 rx_push) -{ - req->_present.rx_push = 1; - req->rx_push = rx_push; -} -static inline void -ethtool_rings_set_req_set_tx_push_buf_len(struct ethtool_rings_set_req *req, - __u32 tx_push_buf_len) -{ - req->_present.tx_push_buf_len = 1; - req->tx_push_buf_len = tx_push_buf_len; -} -static inline void -ethtool_rings_set_req_set_tx_push_buf_len_max(struct ethtool_rings_set_req *req, - __u32 tx_push_buf_len_max) -{ - req->_present.tx_push_buf_len_max = 1; - req->tx_push_buf_len_max = tx_push_buf_len_max; -} - -/* - * Set ring params. - */ -int ethtool_rings_set(struct ynl_sock *ys, struct ethtool_rings_set_req *req); - -/* ============== ETHTOOL_MSG_CHANNELS_GET ============== */ -/* ETHTOOL_MSG_CHANNELS_GET - do */ -struct ethtool_channels_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_channels_get_req * -ethtool_channels_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_channels_get_req)); -} -void ethtool_channels_get_req_free(struct ethtool_channels_get_req *req); - -static inline void -ethtool_channels_get_req_set_header_dev_index(struct ethtool_channels_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_channels_get_req_set_header_dev_name(struct ethtool_channels_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_channels_get_req_set_header_flags(struct ethtool_channels_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_channels_get_rsp { - struct { - __u32 header:1; - __u32 rx_max:1; - __u32 tx_max:1; - __u32 other_max:1; - __u32 combined_max:1; - __u32 rx_count:1; - __u32 tx_count:1; - __u32 other_count:1; - __u32 combined_count:1; - } _present; - - struct ethtool_header header; - __u32 rx_max; - __u32 tx_max; - __u32 other_max; - __u32 combined_max; - __u32 rx_count; - __u32 tx_count; - __u32 other_count; - __u32 combined_count; -}; - -void ethtool_channels_get_rsp_free(struct ethtool_channels_get_rsp *rsp); - -/* - * Get channel params. - */ -struct ethtool_channels_get_rsp * -ethtool_channels_get(struct ynl_sock *ys, struct ethtool_channels_get_req *req); - -/* ETHTOOL_MSG_CHANNELS_GET - dump */ -struct ethtool_channels_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_channels_get_req_dump * -ethtool_channels_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_channels_get_req_dump)); -} -void -ethtool_channels_get_req_dump_free(struct ethtool_channels_get_req_dump *req); - -static inline void -ethtool_channels_get_req_dump_set_header_dev_index(struct ethtool_channels_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_channels_get_req_dump_set_header_dev_name(struct ethtool_channels_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_channels_get_req_dump_set_header_flags(struct ethtool_channels_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_channels_get_list { - struct ethtool_channels_get_list *next; - struct ethtool_channels_get_rsp obj __attribute__ ((aligned (8))); -}; - -void ethtool_channels_get_list_free(struct ethtool_channels_get_list *rsp); - -struct ethtool_channels_get_list * -ethtool_channels_get_dump(struct ynl_sock *ys, - struct ethtool_channels_get_req_dump *req); - -/* ETHTOOL_MSG_CHANNELS_GET - notify */ -struct ethtool_channels_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_channels_get_ntf *ntf); - struct ethtool_channels_get_rsp obj __attribute__ ((aligned (8))); -}; - -void ethtool_channels_get_ntf_free(struct ethtool_channels_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_CHANNELS_SET ============== */ -/* ETHTOOL_MSG_CHANNELS_SET - do */ -struct ethtool_channels_set_req { - struct { - __u32 header:1; - __u32 rx_max:1; - __u32 tx_max:1; - __u32 other_max:1; - __u32 combined_max:1; - __u32 rx_count:1; - __u32 tx_count:1; - __u32 other_count:1; - __u32 combined_count:1; - } _present; - - struct ethtool_header header; - __u32 rx_max; - __u32 tx_max; - __u32 other_max; - __u32 combined_max; - __u32 rx_count; - __u32 tx_count; - __u32 other_count; - __u32 combined_count; -}; - -static inline struct ethtool_channels_set_req * -ethtool_channels_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_channels_set_req)); -} -void ethtool_channels_set_req_free(struct ethtool_channels_set_req *req); - -static inline void -ethtool_channels_set_req_set_header_dev_index(struct ethtool_channels_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_channels_set_req_set_header_dev_name(struct ethtool_channels_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_channels_set_req_set_header_flags(struct ethtool_channels_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_channels_set_req_set_rx_max(struct ethtool_channels_set_req *req, - __u32 rx_max) -{ - req->_present.rx_max = 1; - req->rx_max = rx_max; -} -static inline void -ethtool_channels_set_req_set_tx_max(struct ethtool_channels_set_req *req, - __u32 tx_max) -{ - req->_present.tx_max = 1; - req->tx_max = tx_max; -} -static inline void -ethtool_channels_set_req_set_other_max(struct ethtool_channels_set_req *req, - __u32 other_max) -{ - req->_present.other_max = 1; - req->other_max = other_max; -} -static inline void -ethtool_channels_set_req_set_combined_max(struct ethtool_channels_set_req *req, - __u32 combined_max) -{ - req->_present.combined_max = 1; - req->combined_max = combined_max; -} -static inline void -ethtool_channels_set_req_set_rx_count(struct ethtool_channels_set_req *req, - __u32 rx_count) -{ - req->_present.rx_count = 1; - req->rx_count = rx_count; -} -static inline void -ethtool_channels_set_req_set_tx_count(struct ethtool_channels_set_req *req, - __u32 tx_count) -{ - req->_present.tx_count = 1; - req->tx_count = tx_count; -} -static inline void -ethtool_channels_set_req_set_other_count(struct ethtool_channels_set_req *req, - __u32 other_count) -{ - req->_present.other_count = 1; - req->other_count = other_count; -} -static inline void -ethtool_channels_set_req_set_combined_count(struct ethtool_channels_set_req *req, - __u32 combined_count) -{ - req->_present.combined_count = 1; - req->combined_count = combined_count; -} - -/* - * Set channel params. - */ -int ethtool_channels_set(struct ynl_sock *ys, - struct ethtool_channels_set_req *req); - -/* ============== ETHTOOL_MSG_COALESCE_GET ============== */ -/* ETHTOOL_MSG_COALESCE_GET - do */ -struct ethtool_coalesce_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_coalesce_get_req * -ethtool_coalesce_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_coalesce_get_req)); -} -void ethtool_coalesce_get_req_free(struct ethtool_coalesce_get_req *req); - -static inline void -ethtool_coalesce_get_req_set_header_dev_index(struct ethtool_coalesce_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_coalesce_get_req_set_header_dev_name(struct ethtool_coalesce_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_coalesce_get_req_set_header_flags(struct ethtool_coalesce_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_coalesce_get_rsp { - struct { - __u32 header:1; - __u32 rx_usecs:1; - __u32 rx_max_frames:1; - __u32 rx_usecs_irq:1; - __u32 rx_max_frames_irq:1; - __u32 tx_usecs:1; - __u32 tx_max_frames:1; - __u32 tx_usecs_irq:1; - __u32 tx_max_frames_irq:1; - __u32 stats_block_usecs:1; - __u32 use_adaptive_rx:1; - __u32 use_adaptive_tx:1; - __u32 pkt_rate_low:1; - __u32 rx_usecs_low:1; - __u32 rx_max_frames_low:1; - __u32 tx_usecs_low:1; - __u32 tx_max_frames_low:1; - __u32 pkt_rate_high:1; - __u32 rx_usecs_high:1; - __u32 rx_max_frames_high:1; - __u32 tx_usecs_high:1; - __u32 tx_max_frames_high:1; - __u32 rate_sample_interval:1; - __u32 use_cqe_mode_tx:1; - __u32 use_cqe_mode_rx:1; - __u32 tx_aggr_max_bytes:1; - __u32 tx_aggr_max_frames:1; - __u32 tx_aggr_time_usecs:1; - } _present; - - struct ethtool_header header; - __u32 rx_usecs; - __u32 rx_max_frames; - __u32 rx_usecs_irq; - __u32 rx_max_frames_irq; - __u32 tx_usecs; - __u32 tx_max_frames; - __u32 tx_usecs_irq; - __u32 tx_max_frames_irq; - __u32 stats_block_usecs; - __u8 use_adaptive_rx; - __u8 use_adaptive_tx; - __u32 pkt_rate_low; - __u32 rx_usecs_low; - __u32 rx_max_frames_low; - __u32 tx_usecs_low; - __u32 tx_max_frames_low; - __u32 pkt_rate_high; - __u32 rx_usecs_high; - __u32 rx_max_frames_high; - __u32 tx_usecs_high; - __u32 tx_max_frames_high; - __u32 rate_sample_interval; - __u8 use_cqe_mode_tx; - __u8 use_cqe_mode_rx; - __u32 tx_aggr_max_bytes; - __u32 tx_aggr_max_frames; - __u32 tx_aggr_time_usecs; -}; - -void ethtool_coalesce_get_rsp_free(struct ethtool_coalesce_get_rsp *rsp); - -/* - * Get coalesce params. - */ -struct ethtool_coalesce_get_rsp * -ethtool_coalesce_get(struct ynl_sock *ys, struct ethtool_coalesce_get_req *req); - -/* ETHTOOL_MSG_COALESCE_GET - dump */ -struct ethtool_coalesce_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_coalesce_get_req_dump * -ethtool_coalesce_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_coalesce_get_req_dump)); -} -void -ethtool_coalesce_get_req_dump_free(struct ethtool_coalesce_get_req_dump *req); - -static inline void -ethtool_coalesce_get_req_dump_set_header_dev_index(struct ethtool_coalesce_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_coalesce_get_req_dump_set_header_dev_name(struct ethtool_coalesce_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_coalesce_get_req_dump_set_header_flags(struct ethtool_coalesce_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_coalesce_get_list { - struct ethtool_coalesce_get_list *next; - struct ethtool_coalesce_get_rsp obj __attribute__ ((aligned (8))); -}; - -void ethtool_coalesce_get_list_free(struct ethtool_coalesce_get_list *rsp); - -struct ethtool_coalesce_get_list * -ethtool_coalesce_get_dump(struct ynl_sock *ys, - struct ethtool_coalesce_get_req_dump *req); - -/* ETHTOOL_MSG_COALESCE_GET - notify */ -struct ethtool_coalesce_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_coalesce_get_ntf *ntf); - struct ethtool_coalesce_get_rsp obj __attribute__ ((aligned (8))); -}; - -void ethtool_coalesce_get_ntf_free(struct ethtool_coalesce_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_COALESCE_SET ============== */ -/* ETHTOOL_MSG_COALESCE_SET - do */ -struct ethtool_coalesce_set_req { - struct { - __u32 header:1; - __u32 rx_usecs:1; - __u32 rx_max_frames:1; - __u32 rx_usecs_irq:1; - __u32 rx_max_frames_irq:1; - __u32 tx_usecs:1; - __u32 tx_max_frames:1; - __u32 tx_usecs_irq:1; - __u32 tx_max_frames_irq:1; - __u32 stats_block_usecs:1; - __u32 use_adaptive_rx:1; - __u32 use_adaptive_tx:1; - __u32 pkt_rate_low:1; - __u32 rx_usecs_low:1; - __u32 rx_max_frames_low:1; - __u32 tx_usecs_low:1; - __u32 tx_max_frames_low:1; - __u32 pkt_rate_high:1; - __u32 rx_usecs_high:1; - __u32 rx_max_frames_high:1; - __u32 tx_usecs_high:1; - __u32 tx_max_frames_high:1; - __u32 rate_sample_interval:1; - __u32 use_cqe_mode_tx:1; - __u32 use_cqe_mode_rx:1; - __u32 tx_aggr_max_bytes:1; - __u32 tx_aggr_max_frames:1; - __u32 tx_aggr_time_usecs:1; - } _present; - - struct ethtool_header header; - __u32 rx_usecs; - __u32 rx_max_frames; - __u32 rx_usecs_irq; - __u32 rx_max_frames_irq; - __u32 tx_usecs; - __u32 tx_max_frames; - __u32 tx_usecs_irq; - __u32 tx_max_frames_irq; - __u32 stats_block_usecs; - __u8 use_adaptive_rx; - __u8 use_adaptive_tx; - __u32 pkt_rate_low; - __u32 rx_usecs_low; - __u32 rx_max_frames_low; - __u32 tx_usecs_low; - __u32 tx_max_frames_low; - __u32 pkt_rate_high; - __u32 rx_usecs_high; - __u32 rx_max_frames_high; - __u32 tx_usecs_high; - __u32 tx_max_frames_high; - __u32 rate_sample_interval; - __u8 use_cqe_mode_tx; - __u8 use_cqe_mode_rx; - __u32 tx_aggr_max_bytes; - __u32 tx_aggr_max_frames; - __u32 tx_aggr_time_usecs; -}; - -static inline struct ethtool_coalesce_set_req * -ethtool_coalesce_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_coalesce_set_req)); -} -void ethtool_coalesce_set_req_free(struct ethtool_coalesce_set_req *req); - -static inline void -ethtool_coalesce_set_req_set_header_dev_index(struct ethtool_coalesce_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_coalesce_set_req_set_header_dev_name(struct ethtool_coalesce_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_coalesce_set_req_set_header_flags(struct ethtool_coalesce_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_coalesce_set_req_set_rx_usecs(struct ethtool_coalesce_set_req *req, - __u32 rx_usecs) -{ - req->_present.rx_usecs = 1; - req->rx_usecs = rx_usecs; -} -static inline void -ethtool_coalesce_set_req_set_rx_max_frames(struct ethtool_coalesce_set_req *req, - __u32 rx_max_frames) -{ - req->_present.rx_max_frames = 1; - req->rx_max_frames = rx_max_frames; -} -static inline void -ethtool_coalesce_set_req_set_rx_usecs_irq(struct ethtool_coalesce_set_req *req, - __u32 rx_usecs_irq) -{ - req->_present.rx_usecs_irq = 1; - req->rx_usecs_irq = rx_usecs_irq; -} -static inline void -ethtool_coalesce_set_req_set_rx_max_frames_irq(struct ethtool_coalesce_set_req *req, - __u32 rx_max_frames_irq) -{ - req->_present.rx_max_frames_irq = 1; - req->rx_max_frames_irq = rx_max_frames_irq; -} -static inline void -ethtool_coalesce_set_req_set_tx_usecs(struct ethtool_coalesce_set_req *req, - __u32 tx_usecs) -{ - req->_present.tx_usecs = 1; - req->tx_usecs = tx_usecs; -} -static inline void -ethtool_coalesce_set_req_set_tx_max_frames(struct ethtool_coalesce_set_req *req, - __u32 tx_max_frames) -{ - req->_present.tx_max_frames = 1; - req->tx_max_frames = tx_max_frames; -} -static inline void -ethtool_coalesce_set_req_set_tx_usecs_irq(struct ethtool_coalesce_set_req *req, - __u32 tx_usecs_irq) -{ - req->_present.tx_usecs_irq = 1; - req->tx_usecs_irq = tx_usecs_irq; -} -static inline void -ethtool_coalesce_set_req_set_tx_max_frames_irq(struct ethtool_coalesce_set_req *req, - __u32 tx_max_frames_irq) -{ - req->_present.tx_max_frames_irq = 1; - req->tx_max_frames_irq = tx_max_frames_irq; -} -static inline void -ethtool_coalesce_set_req_set_stats_block_usecs(struct ethtool_coalesce_set_req *req, - __u32 stats_block_usecs) -{ - req->_present.stats_block_usecs = 1; - req->stats_block_usecs = stats_block_usecs; -} -static inline void -ethtool_coalesce_set_req_set_use_adaptive_rx(struct ethtool_coalesce_set_req *req, - __u8 use_adaptive_rx) -{ - req->_present.use_adaptive_rx = 1; - req->use_adaptive_rx = use_adaptive_rx; -} -static inline void -ethtool_coalesce_set_req_set_use_adaptive_tx(struct ethtool_coalesce_set_req *req, - __u8 use_adaptive_tx) -{ - req->_present.use_adaptive_tx = 1; - req->use_adaptive_tx = use_adaptive_tx; -} -static inline void -ethtool_coalesce_set_req_set_pkt_rate_low(struct ethtool_coalesce_set_req *req, - __u32 pkt_rate_low) -{ - req->_present.pkt_rate_low = 1; - req->pkt_rate_low = pkt_rate_low; -} -static inline void -ethtool_coalesce_set_req_set_rx_usecs_low(struct ethtool_coalesce_set_req *req, - __u32 rx_usecs_low) -{ - req->_present.rx_usecs_low = 1; - req->rx_usecs_low = rx_usecs_low; -} -static inline void -ethtool_coalesce_set_req_set_rx_max_frames_low(struct ethtool_coalesce_set_req *req, - __u32 rx_max_frames_low) -{ - req->_present.rx_max_frames_low = 1; - req->rx_max_frames_low = rx_max_frames_low; -} -static inline void -ethtool_coalesce_set_req_set_tx_usecs_low(struct ethtool_coalesce_set_req *req, - __u32 tx_usecs_low) -{ - req->_present.tx_usecs_low = 1; - req->tx_usecs_low = tx_usecs_low; -} -static inline void -ethtool_coalesce_set_req_set_tx_max_frames_low(struct ethtool_coalesce_set_req *req, - __u32 tx_max_frames_low) -{ - req->_present.tx_max_frames_low = 1; - req->tx_max_frames_low = tx_max_frames_low; -} -static inline void -ethtool_coalesce_set_req_set_pkt_rate_high(struct ethtool_coalesce_set_req *req, - __u32 pkt_rate_high) -{ - req->_present.pkt_rate_high = 1; - req->pkt_rate_high = pkt_rate_high; -} -static inline void -ethtool_coalesce_set_req_set_rx_usecs_high(struct ethtool_coalesce_set_req *req, - __u32 rx_usecs_high) -{ - req->_present.rx_usecs_high = 1; - req->rx_usecs_high = rx_usecs_high; -} -static inline void -ethtool_coalesce_set_req_set_rx_max_frames_high(struct ethtool_coalesce_set_req *req, - __u32 rx_max_frames_high) -{ - req->_present.rx_max_frames_high = 1; - req->rx_max_frames_high = rx_max_frames_high; -} -static inline void -ethtool_coalesce_set_req_set_tx_usecs_high(struct ethtool_coalesce_set_req *req, - __u32 tx_usecs_high) -{ - req->_present.tx_usecs_high = 1; - req->tx_usecs_high = tx_usecs_high; -} -static inline void -ethtool_coalesce_set_req_set_tx_max_frames_high(struct ethtool_coalesce_set_req *req, - __u32 tx_max_frames_high) -{ - req->_present.tx_max_frames_high = 1; - req->tx_max_frames_high = tx_max_frames_high; -} -static inline void -ethtool_coalesce_set_req_set_rate_sample_interval(struct ethtool_coalesce_set_req *req, - __u32 rate_sample_interval) -{ - req->_present.rate_sample_interval = 1; - req->rate_sample_interval = rate_sample_interval; -} -static inline void -ethtool_coalesce_set_req_set_use_cqe_mode_tx(struct ethtool_coalesce_set_req *req, - __u8 use_cqe_mode_tx) -{ - req->_present.use_cqe_mode_tx = 1; - req->use_cqe_mode_tx = use_cqe_mode_tx; -} -static inline void -ethtool_coalesce_set_req_set_use_cqe_mode_rx(struct ethtool_coalesce_set_req *req, - __u8 use_cqe_mode_rx) -{ - req->_present.use_cqe_mode_rx = 1; - req->use_cqe_mode_rx = use_cqe_mode_rx; -} -static inline void -ethtool_coalesce_set_req_set_tx_aggr_max_bytes(struct ethtool_coalesce_set_req *req, - __u32 tx_aggr_max_bytes) -{ - req->_present.tx_aggr_max_bytes = 1; - req->tx_aggr_max_bytes = tx_aggr_max_bytes; -} -static inline void -ethtool_coalesce_set_req_set_tx_aggr_max_frames(struct ethtool_coalesce_set_req *req, - __u32 tx_aggr_max_frames) -{ - req->_present.tx_aggr_max_frames = 1; - req->tx_aggr_max_frames = tx_aggr_max_frames; -} -static inline void -ethtool_coalesce_set_req_set_tx_aggr_time_usecs(struct ethtool_coalesce_set_req *req, - __u32 tx_aggr_time_usecs) -{ - req->_present.tx_aggr_time_usecs = 1; - req->tx_aggr_time_usecs = tx_aggr_time_usecs; -} - -/* - * Set coalesce params. - */ -int ethtool_coalesce_set(struct ynl_sock *ys, - struct ethtool_coalesce_set_req *req); - -/* ============== ETHTOOL_MSG_PAUSE_GET ============== */ -/* ETHTOOL_MSG_PAUSE_GET - do */ -struct ethtool_pause_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_pause_get_req *ethtool_pause_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_pause_get_req)); -} -void ethtool_pause_get_req_free(struct ethtool_pause_get_req *req); - -static inline void -ethtool_pause_get_req_set_header_dev_index(struct ethtool_pause_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_pause_get_req_set_header_dev_name(struct ethtool_pause_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_pause_get_req_set_header_flags(struct ethtool_pause_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_pause_get_rsp { - struct { - __u32 header:1; - __u32 autoneg:1; - __u32 rx:1; - __u32 tx:1; - __u32 stats:1; - __u32 stats_src:1; - } _present; - - struct ethtool_header header; - __u8 autoneg; - __u8 rx; - __u8 tx; - struct ethtool_pause_stat stats; - __u32 stats_src; -}; - -void ethtool_pause_get_rsp_free(struct ethtool_pause_get_rsp *rsp); - -/* - * Get pause params. - */ -struct ethtool_pause_get_rsp * -ethtool_pause_get(struct ynl_sock *ys, struct ethtool_pause_get_req *req); - -/* ETHTOOL_MSG_PAUSE_GET - dump */ -struct ethtool_pause_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_pause_get_req_dump * -ethtool_pause_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_pause_get_req_dump)); -} -void ethtool_pause_get_req_dump_free(struct ethtool_pause_get_req_dump *req); - -static inline void -ethtool_pause_get_req_dump_set_header_dev_index(struct ethtool_pause_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_pause_get_req_dump_set_header_dev_name(struct ethtool_pause_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_pause_get_req_dump_set_header_flags(struct ethtool_pause_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_pause_get_list { - struct ethtool_pause_get_list *next; - struct ethtool_pause_get_rsp obj __attribute__ ((aligned (8))); -}; - -void ethtool_pause_get_list_free(struct ethtool_pause_get_list *rsp); - -struct ethtool_pause_get_list * -ethtool_pause_get_dump(struct ynl_sock *ys, - struct ethtool_pause_get_req_dump *req); - -/* ETHTOOL_MSG_PAUSE_GET - notify */ -struct ethtool_pause_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_pause_get_ntf *ntf); - struct ethtool_pause_get_rsp obj __attribute__ ((aligned (8))); -}; - -void ethtool_pause_get_ntf_free(struct ethtool_pause_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_PAUSE_SET ============== */ -/* ETHTOOL_MSG_PAUSE_SET - do */ -struct ethtool_pause_set_req { - struct { - __u32 header:1; - __u32 autoneg:1; - __u32 rx:1; - __u32 tx:1; - __u32 stats:1; - __u32 stats_src:1; - } _present; - - struct ethtool_header header; - __u8 autoneg; - __u8 rx; - __u8 tx; - struct ethtool_pause_stat stats; - __u32 stats_src; -}; - -static inline struct ethtool_pause_set_req *ethtool_pause_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_pause_set_req)); -} -void ethtool_pause_set_req_free(struct ethtool_pause_set_req *req); - -static inline void -ethtool_pause_set_req_set_header_dev_index(struct ethtool_pause_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_pause_set_req_set_header_dev_name(struct ethtool_pause_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_pause_set_req_set_header_flags(struct ethtool_pause_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_pause_set_req_set_autoneg(struct ethtool_pause_set_req *req, - __u8 autoneg) -{ - req->_present.autoneg = 1; - req->autoneg = autoneg; -} -static inline void -ethtool_pause_set_req_set_rx(struct ethtool_pause_set_req *req, __u8 rx) -{ - req->_present.rx = 1; - req->rx = rx; -} -static inline void -ethtool_pause_set_req_set_tx(struct ethtool_pause_set_req *req, __u8 tx) -{ - req->_present.tx = 1; - req->tx = tx; -} -static inline void -ethtool_pause_set_req_set_stats_tx_frames(struct ethtool_pause_set_req *req, - __u64 tx_frames) -{ - req->_present.stats = 1; - req->stats._present.tx_frames = 1; - req->stats.tx_frames = tx_frames; -} -static inline void -ethtool_pause_set_req_set_stats_rx_frames(struct ethtool_pause_set_req *req, - __u64 rx_frames) -{ - req->_present.stats = 1; - req->stats._present.rx_frames = 1; - req->stats.rx_frames = rx_frames; -} -static inline void -ethtool_pause_set_req_set_stats_src(struct ethtool_pause_set_req *req, - __u32 stats_src) -{ - req->_present.stats_src = 1; - req->stats_src = stats_src; -} - -/* - * Set pause params. - */ -int ethtool_pause_set(struct ynl_sock *ys, struct ethtool_pause_set_req *req); - -/* ============== ETHTOOL_MSG_EEE_GET ============== */ -/* ETHTOOL_MSG_EEE_GET - do */ -struct ethtool_eee_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_eee_get_req *ethtool_eee_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_eee_get_req)); -} -void ethtool_eee_get_req_free(struct ethtool_eee_get_req *req); - -static inline void -ethtool_eee_get_req_set_header_dev_index(struct ethtool_eee_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_eee_get_req_set_header_dev_name(struct ethtool_eee_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_eee_get_req_set_header_flags(struct ethtool_eee_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_eee_get_rsp { - struct { - __u32 header:1; - __u32 modes_ours:1; - __u32 modes_peer:1; - __u32 active:1; - __u32 enabled:1; - __u32 tx_lpi_enabled:1; - __u32 tx_lpi_timer:1; - } _present; - - struct ethtool_header header; - struct ethtool_bitset modes_ours; - struct ethtool_bitset modes_peer; - __u8 active; - __u8 enabled; - __u8 tx_lpi_enabled; - __u32 tx_lpi_timer; -}; - -void ethtool_eee_get_rsp_free(struct ethtool_eee_get_rsp *rsp); - -/* - * Get eee params. - */ -struct ethtool_eee_get_rsp * -ethtool_eee_get(struct ynl_sock *ys, struct ethtool_eee_get_req *req); - -/* ETHTOOL_MSG_EEE_GET - dump */ -struct ethtool_eee_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_eee_get_req_dump * -ethtool_eee_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_eee_get_req_dump)); -} -void ethtool_eee_get_req_dump_free(struct ethtool_eee_get_req_dump *req); - -static inline void -ethtool_eee_get_req_dump_set_header_dev_index(struct ethtool_eee_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_eee_get_req_dump_set_header_dev_name(struct ethtool_eee_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_eee_get_req_dump_set_header_flags(struct ethtool_eee_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_eee_get_list { - struct ethtool_eee_get_list *next; - struct ethtool_eee_get_rsp obj __attribute__ ((aligned (8))); -}; - -void ethtool_eee_get_list_free(struct ethtool_eee_get_list *rsp); - -struct ethtool_eee_get_list * -ethtool_eee_get_dump(struct ynl_sock *ys, struct ethtool_eee_get_req_dump *req); - -/* ETHTOOL_MSG_EEE_GET - notify */ -struct ethtool_eee_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_eee_get_ntf *ntf); - struct ethtool_eee_get_rsp obj __attribute__ ((aligned (8))); -}; - -void ethtool_eee_get_ntf_free(struct ethtool_eee_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_EEE_SET ============== */ -/* ETHTOOL_MSG_EEE_SET - do */ -struct ethtool_eee_set_req { - struct { - __u32 header:1; - __u32 modes_ours:1; - __u32 modes_peer:1; - __u32 active:1; - __u32 enabled:1; - __u32 tx_lpi_enabled:1; - __u32 tx_lpi_timer:1; - } _present; - - struct ethtool_header header; - struct ethtool_bitset modes_ours; - struct ethtool_bitset modes_peer; - __u8 active; - __u8 enabled; - __u8 tx_lpi_enabled; - __u32 tx_lpi_timer; -}; - -static inline struct ethtool_eee_set_req *ethtool_eee_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_eee_set_req)); -} -void ethtool_eee_set_req_free(struct ethtool_eee_set_req *req); - -static inline void -ethtool_eee_set_req_set_header_dev_index(struct ethtool_eee_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_eee_set_req_set_header_dev_name(struct ethtool_eee_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_eee_set_req_set_header_flags(struct ethtool_eee_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_eee_set_req_set_modes_ours_nomask(struct ethtool_eee_set_req *req) -{ - req->_present.modes_ours = 1; - req->modes_ours._present.nomask = 1; -} -static inline void -ethtool_eee_set_req_set_modes_ours_size(struct ethtool_eee_set_req *req, - __u32 size) -{ - req->_present.modes_ours = 1; - req->modes_ours._present.size = 1; - req->modes_ours.size = size; -} -static inline void -__ethtool_eee_set_req_set_modes_ours_bits_bit(struct ethtool_eee_set_req *req, - struct ethtool_bitset_bit *bit, - unsigned int n_bit) -{ - free(req->modes_ours.bits.bit); - req->modes_ours.bits.bit = bit; - req->modes_ours.bits.n_bit = n_bit; -} -static inline void -ethtool_eee_set_req_set_modes_peer_nomask(struct ethtool_eee_set_req *req) -{ - req->_present.modes_peer = 1; - req->modes_peer._present.nomask = 1; -} -static inline void -ethtool_eee_set_req_set_modes_peer_size(struct ethtool_eee_set_req *req, - __u32 size) -{ - req->_present.modes_peer = 1; - req->modes_peer._present.size = 1; - req->modes_peer.size = size; -} -static inline void -__ethtool_eee_set_req_set_modes_peer_bits_bit(struct ethtool_eee_set_req *req, - struct ethtool_bitset_bit *bit, - unsigned int n_bit) -{ - free(req->modes_peer.bits.bit); - req->modes_peer.bits.bit = bit; - req->modes_peer.bits.n_bit = n_bit; -} -static inline void -ethtool_eee_set_req_set_active(struct ethtool_eee_set_req *req, __u8 active) -{ - req->_present.active = 1; - req->active = active; -} -static inline void -ethtool_eee_set_req_set_enabled(struct ethtool_eee_set_req *req, __u8 enabled) -{ - req->_present.enabled = 1; - req->enabled = enabled; -} -static inline void -ethtool_eee_set_req_set_tx_lpi_enabled(struct ethtool_eee_set_req *req, - __u8 tx_lpi_enabled) -{ - req->_present.tx_lpi_enabled = 1; - req->tx_lpi_enabled = tx_lpi_enabled; -} -static inline void -ethtool_eee_set_req_set_tx_lpi_timer(struct ethtool_eee_set_req *req, - __u32 tx_lpi_timer) -{ - req->_present.tx_lpi_timer = 1; - req->tx_lpi_timer = tx_lpi_timer; -} - -/* - * Set eee params. - */ -int ethtool_eee_set(struct ynl_sock *ys, struct ethtool_eee_set_req *req); - -/* ============== ETHTOOL_MSG_TSINFO_GET ============== */ -/* ETHTOOL_MSG_TSINFO_GET - do */ -struct ethtool_tsinfo_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_tsinfo_get_req *ethtool_tsinfo_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_tsinfo_get_req)); -} -void ethtool_tsinfo_get_req_free(struct ethtool_tsinfo_get_req *req); - -static inline void -ethtool_tsinfo_get_req_set_header_dev_index(struct ethtool_tsinfo_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_tsinfo_get_req_set_header_dev_name(struct ethtool_tsinfo_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_tsinfo_get_req_set_header_flags(struct ethtool_tsinfo_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_tsinfo_get_rsp { - struct { - __u32 header:1; - __u32 timestamping:1; - __u32 tx_types:1; - __u32 rx_filters:1; - __u32 phc_index:1; - } _present; - - struct ethtool_header header; - struct ethtool_bitset timestamping; - struct ethtool_bitset tx_types; - struct ethtool_bitset rx_filters; - __u32 phc_index; -}; - -void ethtool_tsinfo_get_rsp_free(struct ethtool_tsinfo_get_rsp *rsp); - -/* - * Get tsinfo params. - */ -struct ethtool_tsinfo_get_rsp * -ethtool_tsinfo_get(struct ynl_sock *ys, struct ethtool_tsinfo_get_req *req); - -/* ETHTOOL_MSG_TSINFO_GET - dump */ -struct ethtool_tsinfo_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_tsinfo_get_req_dump * -ethtool_tsinfo_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_tsinfo_get_req_dump)); -} -void ethtool_tsinfo_get_req_dump_free(struct ethtool_tsinfo_get_req_dump *req); - -static inline void -ethtool_tsinfo_get_req_dump_set_header_dev_index(struct ethtool_tsinfo_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_tsinfo_get_req_dump_set_header_dev_name(struct ethtool_tsinfo_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_tsinfo_get_req_dump_set_header_flags(struct ethtool_tsinfo_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_tsinfo_get_list { - struct ethtool_tsinfo_get_list *next; - struct ethtool_tsinfo_get_rsp obj __attribute__ ((aligned (8))); -}; - -void ethtool_tsinfo_get_list_free(struct ethtool_tsinfo_get_list *rsp); - -struct ethtool_tsinfo_get_list * -ethtool_tsinfo_get_dump(struct ynl_sock *ys, - struct ethtool_tsinfo_get_req_dump *req); - -/* ============== ETHTOOL_MSG_CABLE_TEST_ACT ============== */ -/* ETHTOOL_MSG_CABLE_TEST_ACT - do */ -struct ethtool_cable_test_act_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_cable_test_act_req * -ethtool_cable_test_act_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_cable_test_act_req)); -} -void ethtool_cable_test_act_req_free(struct ethtool_cable_test_act_req *req); - -static inline void -ethtool_cable_test_act_req_set_header_dev_index(struct ethtool_cable_test_act_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_cable_test_act_req_set_header_dev_name(struct ethtool_cable_test_act_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_cable_test_act_req_set_header_flags(struct ethtool_cable_test_act_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -/* - * Cable test. - */ -int ethtool_cable_test_act(struct ynl_sock *ys, - struct ethtool_cable_test_act_req *req); - -/* ============== ETHTOOL_MSG_CABLE_TEST_TDR_ACT ============== */ -/* ETHTOOL_MSG_CABLE_TEST_TDR_ACT - do */ -struct ethtool_cable_test_tdr_act_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_cable_test_tdr_act_req * -ethtool_cable_test_tdr_act_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_cable_test_tdr_act_req)); -} -void -ethtool_cable_test_tdr_act_req_free(struct ethtool_cable_test_tdr_act_req *req); - -static inline void -ethtool_cable_test_tdr_act_req_set_header_dev_index(struct ethtool_cable_test_tdr_act_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_cable_test_tdr_act_req_set_header_dev_name(struct ethtool_cable_test_tdr_act_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_cable_test_tdr_act_req_set_header_flags(struct ethtool_cable_test_tdr_act_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -/* - * Cable test TDR. - */ -int ethtool_cable_test_tdr_act(struct ynl_sock *ys, - struct ethtool_cable_test_tdr_act_req *req); - -/* ============== ETHTOOL_MSG_TUNNEL_INFO_GET ============== */ -/* ETHTOOL_MSG_TUNNEL_INFO_GET - do */ -struct ethtool_tunnel_info_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_tunnel_info_get_req * -ethtool_tunnel_info_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_tunnel_info_get_req)); -} -void ethtool_tunnel_info_get_req_free(struct ethtool_tunnel_info_get_req *req); - -static inline void -ethtool_tunnel_info_get_req_set_header_dev_index(struct ethtool_tunnel_info_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_tunnel_info_get_req_set_header_dev_name(struct ethtool_tunnel_info_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_tunnel_info_get_req_set_header_flags(struct ethtool_tunnel_info_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_tunnel_info_get_rsp { - struct { - __u32 header:1; - __u32 udp_ports:1; - } _present; - - struct ethtool_header header; - struct ethtool_tunnel_udp udp_ports; -}; - -void ethtool_tunnel_info_get_rsp_free(struct ethtool_tunnel_info_get_rsp *rsp); - -/* - * Get tsinfo params. - */ -struct ethtool_tunnel_info_get_rsp * -ethtool_tunnel_info_get(struct ynl_sock *ys, - struct ethtool_tunnel_info_get_req *req); - -/* ETHTOOL_MSG_TUNNEL_INFO_GET - dump */ -struct ethtool_tunnel_info_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_tunnel_info_get_req_dump * -ethtool_tunnel_info_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_tunnel_info_get_req_dump)); -} -void -ethtool_tunnel_info_get_req_dump_free(struct ethtool_tunnel_info_get_req_dump *req); - -static inline void -ethtool_tunnel_info_get_req_dump_set_header_dev_index(struct ethtool_tunnel_info_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_tunnel_info_get_req_dump_set_header_dev_name(struct ethtool_tunnel_info_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_tunnel_info_get_req_dump_set_header_flags(struct ethtool_tunnel_info_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_tunnel_info_get_list { - struct ethtool_tunnel_info_get_list *next; - struct ethtool_tunnel_info_get_rsp obj __attribute__ ((aligned (8))); -}; - -void -ethtool_tunnel_info_get_list_free(struct ethtool_tunnel_info_get_list *rsp); - -struct ethtool_tunnel_info_get_list * -ethtool_tunnel_info_get_dump(struct ynl_sock *ys, - struct ethtool_tunnel_info_get_req_dump *req); - -/* ============== ETHTOOL_MSG_FEC_GET ============== */ -/* ETHTOOL_MSG_FEC_GET - do */ -struct ethtool_fec_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_fec_get_req *ethtool_fec_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_fec_get_req)); -} -void ethtool_fec_get_req_free(struct ethtool_fec_get_req *req); - -static inline void -ethtool_fec_get_req_set_header_dev_index(struct ethtool_fec_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_fec_get_req_set_header_dev_name(struct ethtool_fec_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_fec_get_req_set_header_flags(struct ethtool_fec_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_fec_get_rsp { - struct { - __u32 header:1; - __u32 modes:1; - __u32 auto_:1; - __u32 active:1; - __u32 stats:1; - } _present; - - struct ethtool_header header; - struct ethtool_bitset modes; - __u8 auto_; - __u32 active; - struct ethtool_fec_stat stats; -}; - -void ethtool_fec_get_rsp_free(struct ethtool_fec_get_rsp *rsp); - -/* - * Get FEC params. - */ -struct ethtool_fec_get_rsp * -ethtool_fec_get(struct ynl_sock *ys, struct ethtool_fec_get_req *req); - -/* ETHTOOL_MSG_FEC_GET - dump */ -struct ethtool_fec_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_fec_get_req_dump * -ethtool_fec_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_fec_get_req_dump)); -} -void ethtool_fec_get_req_dump_free(struct ethtool_fec_get_req_dump *req); - -static inline void -ethtool_fec_get_req_dump_set_header_dev_index(struct ethtool_fec_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_fec_get_req_dump_set_header_dev_name(struct ethtool_fec_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_fec_get_req_dump_set_header_flags(struct ethtool_fec_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_fec_get_list { - struct ethtool_fec_get_list *next; - struct ethtool_fec_get_rsp obj __attribute__ ((aligned (8))); -}; - -void ethtool_fec_get_list_free(struct ethtool_fec_get_list *rsp); - -struct ethtool_fec_get_list * -ethtool_fec_get_dump(struct ynl_sock *ys, struct ethtool_fec_get_req_dump *req); - -/* ETHTOOL_MSG_FEC_GET - notify */ -struct ethtool_fec_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_fec_get_ntf *ntf); - struct ethtool_fec_get_rsp obj __attribute__ ((aligned (8))); -}; - -void ethtool_fec_get_ntf_free(struct ethtool_fec_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_FEC_SET ============== */ -/* ETHTOOL_MSG_FEC_SET - do */ -struct ethtool_fec_set_req { - struct { - __u32 header:1; - __u32 modes:1; - __u32 auto_:1; - __u32 active:1; - __u32 stats:1; - } _present; - - struct ethtool_header header; - struct ethtool_bitset modes; - __u8 auto_; - __u32 active; - struct ethtool_fec_stat stats; -}; - -static inline struct ethtool_fec_set_req *ethtool_fec_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_fec_set_req)); -} -void ethtool_fec_set_req_free(struct ethtool_fec_set_req *req); - -static inline void -ethtool_fec_set_req_set_header_dev_index(struct ethtool_fec_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_fec_set_req_set_header_dev_name(struct ethtool_fec_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_fec_set_req_set_header_flags(struct ethtool_fec_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_fec_set_req_set_modes_nomask(struct ethtool_fec_set_req *req) -{ - req->_present.modes = 1; - req->modes._present.nomask = 1; -} -static inline void -ethtool_fec_set_req_set_modes_size(struct ethtool_fec_set_req *req, __u32 size) -{ - req->_present.modes = 1; - req->modes._present.size = 1; - req->modes.size = size; -} -static inline void -__ethtool_fec_set_req_set_modes_bits_bit(struct ethtool_fec_set_req *req, - struct ethtool_bitset_bit *bit, - unsigned int n_bit) -{ - free(req->modes.bits.bit); - req->modes.bits.bit = bit; - req->modes.bits.n_bit = n_bit; -} -static inline void -ethtool_fec_set_req_set_auto_(struct ethtool_fec_set_req *req, __u8 auto_) -{ - req->_present.auto_ = 1; - req->auto_ = auto_; -} -static inline void -ethtool_fec_set_req_set_active(struct ethtool_fec_set_req *req, __u32 active) -{ - req->_present.active = 1; - req->active = active; -} -static inline void -ethtool_fec_set_req_set_stats_corrected(struct ethtool_fec_set_req *req, - const void *corrected, size_t len) -{ - free(req->stats.corrected); - req->stats._present.corrected_len = len; - req->stats.corrected = malloc(req->stats._present.corrected_len); - memcpy(req->stats.corrected, corrected, req->stats._present.corrected_len); -} -static inline void -ethtool_fec_set_req_set_stats_uncorr(struct ethtool_fec_set_req *req, - const void *uncorr, size_t len) -{ - free(req->stats.uncorr); - req->stats._present.uncorr_len = len; - req->stats.uncorr = malloc(req->stats._present.uncorr_len); - memcpy(req->stats.uncorr, uncorr, req->stats._present.uncorr_len); -} -static inline void -ethtool_fec_set_req_set_stats_corr_bits(struct ethtool_fec_set_req *req, - const void *corr_bits, size_t len) -{ - free(req->stats.corr_bits); - req->stats._present.corr_bits_len = len; - req->stats.corr_bits = malloc(req->stats._present.corr_bits_len); - memcpy(req->stats.corr_bits, corr_bits, req->stats._present.corr_bits_len); -} - -/* - * Set FEC params. - */ -int ethtool_fec_set(struct ynl_sock *ys, struct ethtool_fec_set_req *req); - -/* ============== ETHTOOL_MSG_MODULE_EEPROM_GET ============== */ -/* ETHTOOL_MSG_MODULE_EEPROM_GET - do */ -struct ethtool_module_eeprom_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_module_eeprom_get_req * -ethtool_module_eeprom_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_module_eeprom_get_req)); -} -void -ethtool_module_eeprom_get_req_free(struct ethtool_module_eeprom_get_req *req); - -static inline void -ethtool_module_eeprom_get_req_set_header_dev_index(struct ethtool_module_eeprom_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_module_eeprom_get_req_set_header_dev_name(struct ethtool_module_eeprom_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_module_eeprom_get_req_set_header_flags(struct ethtool_module_eeprom_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_module_eeprom_get_rsp { - struct { - __u32 header:1; - __u32 offset:1; - __u32 length:1; - __u32 page:1; - __u32 bank:1; - __u32 i2c_address:1; - __u32 data_len; - } _present; - - struct ethtool_header header; - __u32 offset; - __u32 length; - __u8 page; - __u8 bank; - __u8 i2c_address; - void *data; -}; - -void -ethtool_module_eeprom_get_rsp_free(struct ethtool_module_eeprom_get_rsp *rsp); - -/* - * Get module EEPROM params. - */ -struct ethtool_module_eeprom_get_rsp * -ethtool_module_eeprom_get(struct ynl_sock *ys, - struct ethtool_module_eeprom_get_req *req); - -/* ETHTOOL_MSG_MODULE_EEPROM_GET - dump */ -struct ethtool_module_eeprom_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_module_eeprom_get_req_dump * -ethtool_module_eeprom_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_module_eeprom_get_req_dump)); -} -void -ethtool_module_eeprom_get_req_dump_free(struct ethtool_module_eeprom_get_req_dump *req); - -static inline void -ethtool_module_eeprom_get_req_dump_set_header_dev_index(struct ethtool_module_eeprom_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_module_eeprom_get_req_dump_set_header_dev_name(struct ethtool_module_eeprom_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_module_eeprom_get_req_dump_set_header_flags(struct ethtool_module_eeprom_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_module_eeprom_get_list { - struct ethtool_module_eeprom_get_list *next; - struct ethtool_module_eeprom_get_rsp obj __attribute__ ((aligned (8))); -}; - -void -ethtool_module_eeprom_get_list_free(struct ethtool_module_eeprom_get_list *rsp); - -struct ethtool_module_eeprom_get_list * -ethtool_module_eeprom_get_dump(struct ynl_sock *ys, - struct ethtool_module_eeprom_get_req_dump *req); - -/* ============== ETHTOOL_MSG_PHC_VCLOCKS_GET ============== */ -/* ETHTOOL_MSG_PHC_VCLOCKS_GET - do */ -struct ethtool_phc_vclocks_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_phc_vclocks_get_req * -ethtool_phc_vclocks_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_phc_vclocks_get_req)); -} -void ethtool_phc_vclocks_get_req_free(struct ethtool_phc_vclocks_get_req *req); - -static inline void -ethtool_phc_vclocks_get_req_set_header_dev_index(struct ethtool_phc_vclocks_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_phc_vclocks_get_req_set_header_dev_name(struct ethtool_phc_vclocks_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_phc_vclocks_get_req_set_header_flags(struct ethtool_phc_vclocks_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_phc_vclocks_get_rsp { - struct { - __u32 header:1; - __u32 num:1; - } _present; - - struct ethtool_header header; - __u32 num; -}; - -void ethtool_phc_vclocks_get_rsp_free(struct ethtool_phc_vclocks_get_rsp *rsp); - -/* - * Get PHC VCLOCKs. - */ -struct ethtool_phc_vclocks_get_rsp * -ethtool_phc_vclocks_get(struct ynl_sock *ys, - struct ethtool_phc_vclocks_get_req *req); - -/* ETHTOOL_MSG_PHC_VCLOCKS_GET - dump */ -struct ethtool_phc_vclocks_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_phc_vclocks_get_req_dump * -ethtool_phc_vclocks_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_phc_vclocks_get_req_dump)); -} -void -ethtool_phc_vclocks_get_req_dump_free(struct ethtool_phc_vclocks_get_req_dump *req); - -static inline void -ethtool_phc_vclocks_get_req_dump_set_header_dev_index(struct ethtool_phc_vclocks_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_phc_vclocks_get_req_dump_set_header_dev_name(struct ethtool_phc_vclocks_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_phc_vclocks_get_req_dump_set_header_flags(struct ethtool_phc_vclocks_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_phc_vclocks_get_list { - struct ethtool_phc_vclocks_get_list *next; - struct ethtool_phc_vclocks_get_rsp obj __attribute__ ((aligned (8))); -}; - -void -ethtool_phc_vclocks_get_list_free(struct ethtool_phc_vclocks_get_list *rsp); - -struct ethtool_phc_vclocks_get_list * -ethtool_phc_vclocks_get_dump(struct ynl_sock *ys, - struct ethtool_phc_vclocks_get_req_dump *req); - -/* ============== ETHTOOL_MSG_MODULE_GET ============== */ -/* ETHTOOL_MSG_MODULE_GET - do */ -struct ethtool_module_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_module_get_req *ethtool_module_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_module_get_req)); -} -void ethtool_module_get_req_free(struct ethtool_module_get_req *req); - -static inline void -ethtool_module_get_req_set_header_dev_index(struct ethtool_module_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_module_get_req_set_header_dev_name(struct ethtool_module_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_module_get_req_set_header_flags(struct ethtool_module_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_module_get_rsp { - struct { - __u32 header:1; - __u32 power_mode_policy:1; - __u32 power_mode:1; - } _present; - - struct ethtool_header header; - __u8 power_mode_policy; - __u8 power_mode; -}; - -void ethtool_module_get_rsp_free(struct ethtool_module_get_rsp *rsp); - -/* - * Get module params. - */ -struct ethtool_module_get_rsp * -ethtool_module_get(struct ynl_sock *ys, struct ethtool_module_get_req *req); - -/* ETHTOOL_MSG_MODULE_GET - dump */ -struct ethtool_module_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_module_get_req_dump * -ethtool_module_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_module_get_req_dump)); -} -void ethtool_module_get_req_dump_free(struct ethtool_module_get_req_dump *req); - -static inline void -ethtool_module_get_req_dump_set_header_dev_index(struct ethtool_module_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_module_get_req_dump_set_header_dev_name(struct ethtool_module_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_module_get_req_dump_set_header_flags(struct ethtool_module_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_module_get_list { - struct ethtool_module_get_list *next; - struct ethtool_module_get_rsp obj __attribute__ ((aligned (8))); -}; - -void ethtool_module_get_list_free(struct ethtool_module_get_list *rsp); - -struct ethtool_module_get_list * -ethtool_module_get_dump(struct ynl_sock *ys, - struct ethtool_module_get_req_dump *req); - -/* ETHTOOL_MSG_MODULE_GET - notify */ -struct ethtool_module_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_module_get_ntf *ntf); - struct ethtool_module_get_rsp obj __attribute__ ((aligned (8))); -}; - -void ethtool_module_get_ntf_free(struct ethtool_module_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_MODULE_SET ============== */ -/* ETHTOOL_MSG_MODULE_SET - do */ -struct ethtool_module_set_req { - struct { - __u32 header:1; - __u32 power_mode_policy:1; - __u32 power_mode:1; - } _present; - - struct ethtool_header header; - __u8 power_mode_policy; - __u8 power_mode; -}; - -static inline struct ethtool_module_set_req *ethtool_module_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_module_set_req)); -} -void ethtool_module_set_req_free(struct ethtool_module_set_req *req); - -static inline void -ethtool_module_set_req_set_header_dev_index(struct ethtool_module_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_module_set_req_set_header_dev_name(struct ethtool_module_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_module_set_req_set_header_flags(struct ethtool_module_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_module_set_req_set_power_mode_policy(struct ethtool_module_set_req *req, - __u8 power_mode_policy) -{ - req->_present.power_mode_policy = 1; - req->power_mode_policy = power_mode_policy; -} -static inline void -ethtool_module_set_req_set_power_mode(struct ethtool_module_set_req *req, - __u8 power_mode) -{ - req->_present.power_mode = 1; - req->power_mode = power_mode; -} - -/* - * Set module params. - */ -int ethtool_module_set(struct ynl_sock *ys, struct ethtool_module_set_req *req); - -/* ============== ETHTOOL_MSG_PSE_GET ============== */ -/* ETHTOOL_MSG_PSE_GET - do */ -struct ethtool_pse_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_pse_get_req *ethtool_pse_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_pse_get_req)); -} -void ethtool_pse_get_req_free(struct ethtool_pse_get_req *req); - -static inline void -ethtool_pse_get_req_set_header_dev_index(struct ethtool_pse_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_pse_get_req_set_header_dev_name(struct ethtool_pse_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_pse_get_req_set_header_flags(struct ethtool_pse_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_pse_get_rsp { - struct { - __u32 header:1; - __u32 admin_state:1; - __u32 admin_control:1; - __u32 pw_d_status:1; - } _present; - - struct ethtool_header header; - __u32 admin_state; - __u32 admin_control; - __u32 pw_d_status; -}; - -void ethtool_pse_get_rsp_free(struct ethtool_pse_get_rsp *rsp); - -/* - * Get Power Sourcing Equipment params. - */ -struct ethtool_pse_get_rsp * -ethtool_pse_get(struct ynl_sock *ys, struct ethtool_pse_get_req *req); - -/* ETHTOOL_MSG_PSE_GET - dump */ -struct ethtool_pse_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_pse_get_req_dump * -ethtool_pse_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_pse_get_req_dump)); -} -void ethtool_pse_get_req_dump_free(struct ethtool_pse_get_req_dump *req); - -static inline void -ethtool_pse_get_req_dump_set_header_dev_index(struct ethtool_pse_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_pse_get_req_dump_set_header_dev_name(struct ethtool_pse_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_pse_get_req_dump_set_header_flags(struct ethtool_pse_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_pse_get_list { - struct ethtool_pse_get_list *next; - struct ethtool_pse_get_rsp obj __attribute__ ((aligned (8))); -}; - -void ethtool_pse_get_list_free(struct ethtool_pse_get_list *rsp); - -struct ethtool_pse_get_list * -ethtool_pse_get_dump(struct ynl_sock *ys, struct ethtool_pse_get_req_dump *req); - -/* ============== ETHTOOL_MSG_PSE_SET ============== */ -/* ETHTOOL_MSG_PSE_SET - do */ -struct ethtool_pse_set_req { - struct { - __u32 header:1; - __u32 admin_state:1; - __u32 admin_control:1; - __u32 pw_d_status:1; - } _present; - - struct ethtool_header header; - __u32 admin_state; - __u32 admin_control; - __u32 pw_d_status; -}; - -static inline struct ethtool_pse_set_req *ethtool_pse_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_pse_set_req)); -} -void ethtool_pse_set_req_free(struct ethtool_pse_set_req *req); - -static inline void -ethtool_pse_set_req_set_header_dev_index(struct ethtool_pse_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_pse_set_req_set_header_dev_name(struct ethtool_pse_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_pse_set_req_set_header_flags(struct ethtool_pse_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_pse_set_req_set_admin_state(struct ethtool_pse_set_req *req, - __u32 admin_state) -{ - req->_present.admin_state = 1; - req->admin_state = admin_state; -} -static inline void -ethtool_pse_set_req_set_admin_control(struct ethtool_pse_set_req *req, - __u32 admin_control) -{ - req->_present.admin_control = 1; - req->admin_control = admin_control; -} -static inline void -ethtool_pse_set_req_set_pw_d_status(struct ethtool_pse_set_req *req, - __u32 pw_d_status) -{ - req->_present.pw_d_status = 1; - req->pw_d_status = pw_d_status; -} - -/* - * Set Power Sourcing Equipment params. - */ -int ethtool_pse_set(struct ynl_sock *ys, struct ethtool_pse_set_req *req); - -/* ============== ETHTOOL_MSG_RSS_GET ============== */ -/* ETHTOOL_MSG_RSS_GET - do */ -struct ethtool_rss_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_rss_get_req *ethtool_rss_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_rss_get_req)); -} -void ethtool_rss_get_req_free(struct ethtool_rss_get_req *req); - -static inline void -ethtool_rss_get_req_set_header_dev_index(struct ethtool_rss_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_rss_get_req_set_header_dev_name(struct ethtool_rss_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_rss_get_req_set_header_flags(struct ethtool_rss_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_rss_get_rsp { - struct { - __u32 header:1; - __u32 context:1; - __u32 hfunc:1; - __u32 indir_len; - __u32 hkey_len; - } _present; - - struct ethtool_header header; - __u32 context; - __u32 hfunc; - void *indir; - void *hkey; -}; - -void ethtool_rss_get_rsp_free(struct ethtool_rss_get_rsp *rsp); - -/* - * Get RSS params. - */ -struct ethtool_rss_get_rsp * -ethtool_rss_get(struct ynl_sock *ys, struct ethtool_rss_get_req *req); - -/* ETHTOOL_MSG_RSS_GET - dump */ -struct ethtool_rss_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_rss_get_req_dump * -ethtool_rss_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_rss_get_req_dump)); -} -void ethtool_rss_get_req_dump_free(struct ethtool_rss_get_req_dump *req); - -static inline void -ethtool_rss_get_req_dump_set_header_dev_index(struct ethtool_rss_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_rss_get_req_dump_set_header_dev_name(struct ethtool_rss_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_rss_get_req_dump_set_header_flags(struct ethtool_rss_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_rss_get_list { - struct ethtool_rss_get_list *next; - struct ethtool_rss_get_rsp obj __attribute__ ((aligned (8))); -}; - -void ethtool_rss_get_list_free(struct ethtool_rss_get_list *rsp); - -struct ethtool_rss_get_list * -ethtool_rss_get_dump(struct ynl_sock *ys, struct ethtool_rss_get_req_dump *req); - -/* ============== ETHTOOL_MSG_PLCA_GET_CFG ============== */ -/* ETHTOOL_MSG_PLCA_GET_CFG - do */ -struct ethtool_plca_get_cfg_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_plca_get_cfg_req * -ethtool_plca_get_cfg_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_plca_get_cfg_req)); -} -void ethtool_plca_get_cfg_req_free(struct ethtool_plca_get_cfg_req *req); - -static inline void -ethtool_plca_get_cfg_req_set_header_dev_index(struct ethtool_plca_get_cfg_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_plca_get_cfg_req_set_header_dev_name(struct ethtool_plca_get_cfg_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_plca_get_cfg_req_set_header_flags(struct ethtool_plca_get_cfg_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_plca_get_cfg_rsp { - struct { - __u32 header:1; - __u32 version:1; - __u32 enabled:1; - __u32 status:1; - __u32 node_cnt:1; - __u32 node_id:1; - __u32 to_tmr:1; - __u32 burst_cnt:1; - __u32 burst_tmr:1; - } _present; - - struct ethtool_header header; - __u16 version; - __u8 enabled; - __u8 status; - __u32 node_cnt; - __u32 node_id; - __u32 to_tmr; - __u32 burst_cnt; - __u32 burst_tmr; -}; - -void ethtool_plca_get_cfg_rsp_free(struct ethtool_plca_get_cfg_rsp *rsp); - -/* - * Get PLCA params. - */ -struct ethtool_plca_get_cfg_rsp * -ethtool_plca_get_cfg(struct ynl_sock *ys, struct ethtool_plca_get_cfg_req *req); - -/* ETHTOOL_MSG_PLCA_GET_CFG - dump */ -struct ethtool_plca_get_cfg_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_plca_get_cfg_req_dump * -ethtool_plca_get_cfg_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_plca_get_cfg_req_dump)); -} -void -ethtool_plca_get_cfg_req_dump_free(struct ethtool_plca_get_cfg_req_dump *req); - -static inline void -ethtool_plca_get_cfg_req_dump_set_header_dev_index(struct ethtool_plca_get_cfg_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_plca_get_cfg_req_dump_set_header_dev_name(struct ethtool_plca_get_cfg_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_plca_get_cfg_req_dump_set_header_flags(struct ethtool_plca_get_cfg_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_plca_get_cfg_list { - struct ethtool_plca_get_cfg_list *next; - struct ethtool_plca_get_cfg_rsp obj __attribute__ ((aligned (8))); -}; - -void ethtool_plca_get_cfg_list_free(struct ethtool_plca_get_cfg_list *rsp); - -struct ethtool_plca_get_cfg_list * -ethtool_plca_get_cfg_dump(struct ynl_sock *ys, - struct ethtool_plca_get_cfg_req_dump *req); - -/* ETHTOOL_MSG_PLCA_GET_CFG - notify */ -struct ethtool_plca_get_cfg_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_plca_get_cfg_ntf *ntf); - struct ethtool_plca_get_cfg_rsp obj __attribute__ ((aligned (8))); -}; - -void ethtool_plca_get_cfg_ntf_free(struct ethtool_plca_get_cfg_ntf *rsp); - -/* ============== ETHTOOL_MSG_PLCA_SET_CFG ============== */ -/* ETHTOOL_MSG_PLCA_SET_CFG - do */ -struct ethtool_plca_set_cfg_req { - struct { - __u32 header:1; - __u32 version:1; - __u32 enabled:1; - __u32 status:1; - __u32 node_cnt:1; - __u32 node_id:1; - __u32 to_tmr:1; - __u32 burst_cnt:1; - __u32 burst_tmr:1; - } _present; - - struct ethtool_header header; - __u16 version; - __u8 enabled; - __u8 status; - __u32 node_cnt; - __u32 node_id; - __u32 to_tmr; - __u32 burst_cnt; - __u32 burst_tmr; -}; - -static inline struct ethtool_plca_set_cfg_req * -ethtool_plca_set_cfg_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_plca_set_cfg_req)); -} -void ethtool_plca_set_cfg_req_free(struct ethtool_plca_set_cfg_req *req); - -static inline void -ethtool_plca_set_cfg_req_set_header_dev_index(struct ethtool_plca_set_cfg_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_plca_set_cfg_req_set_header_dev_name(struct ethtool_plca_set_cfg_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_plca_set_cfg_req_set_header_flags(struct ethtool_plca_set_cfg_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_plca_set_cfg_req_set_version(struct ethtool_plca_set_cfg_req *req, - __u16 version) -{ - req->_present.version = 1; - req->version = version; -} -static inline void -ethtool_plca_set_cfg_req_set_enabled(struct ethtool_plca_set_cfg_req *req, - __u8 enabled) -{ - req->_present.enabled = 1; - req->enabled = enabled; -} -static inline void -ethtool_plca_set_cfg_req_set_status(struct ethtool_plca_set_cfg_req *req, - __u8 status) -{ - req->_present.status = 1; - req->status = status; -} -static inline void -ethtool_plca_set_cfg_req_set_node_cnt(struct ethtool_plca_set_cfg_req *req, - __u32 node_cnt) -{ - req->_present.node_cnt = 1; - req->node_cnt = node_cnt; -} -static inline void -ethtool_plca_set_cfg_req_set_node_id(struct ethtool_plca_set_cfg_req *req, - __u32 node_id) -{ - req->_present.node_id = 1; - req->node_id = node_id; -} -static inline void -ethtool_plca_set_cfg_req_set_to_tmr(struct ethtool_plca_set_cfg_req *req, - __u32 to_tmr) -{ - req->_present.to_tmr = 1; - req->to_tmr = to_tmr; -} -static inline void -ethtool_plca_set_cfg_req_set_burst_cnt(struct ethtool_plca_set_cfg_req *req, - __u32 burst_cnt) -{ - req->_present.burst_cnt = 1; - req->burst_cnt = burst_cnt; -} -static inline void -ethtool_plca_set_cfg_req_set_burst_tmr(struct ethtool_plca_set_cfg_req *req, - __u32 burst_tmr) -{ - req->_present.burst_tmr = 1; - req->burst_tmr = burst_tmr; -} - -/* - * Set PLCA params. - */ -int ethtool_plca_set_cfg(struct ynl_sock *ys, - struct ethtool_plca_set_cfg_req *req); - -/* ============== ETHTOOL_MSG_PLCA_GET_STATUS ============== */ -/* ETHTOOL_MSG_PLCA_GET_STATUS - do */ -struct ethtool_plca_get_status_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_plca_get_status_req * -ethtool_plca_get_status_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_plca_get_status_req)); -} -void ethtool_plca_get_status_req_free(struct ethtool_plca_get_status_req *req); - -static inline void -ethtool_plca_get_status_req_set_header_dev_index(struct ethtool_plca_get_status_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_plca_get_status_req_set_header_dev_name(struct ethtool_plca_get_status_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_plca_get_status_req_set_header_flags(struct ethtool_plca_get_status_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_plca_get_status_rsp { - struct { - __u32 header:1; - __u32 version:1; - __u32 enabled:1; - __u32 status:1; - __u32 node_cnt:1; - __u32 node_id:1; - __u32 to_tmr:1; - __u32 burst_cnt:1; - __u32 burst_tmr:1; - } _present; - - struct ethtool_header header; - __u16 version; - __u8 enabled; - __u8 status; - __u32 node_cnt; - __u32 node_id; - __u32 to_tmr; - __u32 burst_cnt; - __u32 burst_tmr; -}; - -void ethtool_plca_get_status_rsp_free(struct ethtool_plca_get_status_rsp *rsp); - -/* - * Get PLCA status params. - */ -struct ethtool_plca_get_status_rsp * -ethtool_plca_get_status(struct ynl_sock *ys, - struct ethtool_plca_get_status_req *req); - -/* ETHTOOL_MSG_PLCA_GET_STATUS - dump */ -struct ethtool_plca_get_status_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_plca_get_status_req_dump * -ethtool_plca_get_status_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_plca_get_status_req_dump)); -} -void -ethtool_plca_get_status_req_dump_free(struct ethtool_plca_get_status_req_dump *req); - -static inline void -ethtool_plca_get_status_req_dump_set_header_dev_index(struct ethtool_plca_get_status_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_plca_get_status_req_dump_set_header_dev_name(struct ethtool_plca_get_status_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_plca_get_status_req_dump_set_header_flags(struct ethtool_plca_get_status_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_plca_get_status_list { - struct ethtool_plca_get_status_list *next; - struct ethtool_plca_get_status_rsp obj __attribute__ ((aligned (8))); -}; - -void -ethtool_plca_get_status_list_free(struct ethtool_plca_get_status_list *rsp); - -struct ethtool_plca_get_status_list * -ethtool_plca_get_status_dump(struct ynl_sock *ys, - struct ethtool_plca_get_status_req_dump *req); - -/* ============== ETHTOOL_MSG_MM_GET ============== */ -/* ETHTOOL_MSG_MM_GET - do */ -struct ethtool_mm_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_mm_get_req *ethtool_mm_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_mm_get_req)); -} -void ethtool_mm_get_req_free(struct ethtool_mm_get_req *req); - -static inline void -ethtool_mm_get_req_set_header_dev_index(struct ethtool_mm_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_mm_get_req_set_header_dev_name(struct ethtool_mm_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_mm_get_req_set_header_flags(struct ethtool_mm_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_mm_get_rsp { - struct { - __u32 header:1; - __u32 pmac_enabled:1; - __u32 tx_enabled:1; - __u32 tx_active:1; - __u32 tx_min_frag_size:1; - __u32 rx_min_frag_size:1; - __u32 verify_enabled:1; - __u32 verify_time:1; - __u32 max_verify_time:1; - __u32 stats:1; - } _present; - - struct ethtool_header header; - __u8 pmac_enabled; - __u8 tx_enabled; - __u8 tx_active; - __u32 tx_min_frag_size; - __u32 rx_min_frag_size; - __u8 verify_enabled; - __u32 verify_time; - __u32 max_verify_time; - struct ethtool_mm_stat stats; -}; - -void ethtool_mm_get_rsp_free(struct ethtool_mm_get_rsp *rsp); - -/* - * Get MAC Merge configuration and state - */ -struct ethtool_mm_get_rsp * -ethtool_mm_get(struct ynl_sock *ys, struct ethtool_mm_get_req *req); - -/* ETHTOOL_MSG_MM_GET - dump */ -struct ethtool_mm_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_mm_get_req_dump * -ethtool_mm_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_mm_get_req_dump)); -} -void ethtool_mm_get_req_dump_free(struct ethtool_mm_get_req_dump *req); - -static inline void -ethtool_mm_get_req_dump_set_header_dev_index(struct ethtool_mm_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_mm_get_req_dump_set_header_dev_name(struct ethtool_mm_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_mm_get_req_dump_set_header_flags(struct ethtool_mm_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_mm_get_list { - struct ethtool_mm_get_list *next; - struct ethtool_mm_get_rsp obj __attribute__ ((aligned (8))); -}; - -void ethtool_mm_get_list_free(struct ethtool_mm_get_list *rsp); - -struct ethtool_mm_get_list * -ethtool_mm_get_dump(struct ynl_sock *ys, struct ethtool_mm_get_req_dump *req); - -/* ETHTOOL_MSG_MM_GET - notify */ -struct ethtool_mm_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_mm_get_ntf *ntf); - struct ethtool_mm_get_rsp obj __attribute__ ((aligned (8))); -}; - -void ethtool_mm_get_ntf_free(struct ethtool_mm_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_MM_SET ============== */ -/* ETHTOOL_MSG_MM_SET - do */ -struct ethtool_mm_set_req { - struct { - __u32 header:1; - __u32 verify_enabled:1; - __u32 verify_time:1; - __u32 tx_enabled:1; - __u32 pmac_enabled:1; - __u32 tx_min_frag_size:1; - } _present; - - struct ethtool_header header; - __u8 verify_enabled; - __u32 verify_time; - __u8 tx_enabled; - __u8 pmac_enabled; - __u32 tx_min_frag_size; -}; - -static inline struct ethtool_mm_set_req *ethtool_mm_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_mm_set_req)); -} -void ethtool_mm_set_req_free(struct ethtool_mm_set_req *req); - -static inline void -ethtool_mm_set_req_set_header_dev_index(struct ethtool_mm_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_mm_set_req_set_header_dev_name(struct ethtool_mm_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_mm_set_req_set_header_flags(struct ethtool_mm_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_mm_set_req_set_verify_enabled(struct ethtool_mm_set_req *req, - __u8 verify_enabled) -{ - req->_present.verify_enabled = 1; - req->verify_enabled = verify_enabled; -} -static inline void -ethtool_mm_set_req_set_verify_time(struct ethtool_mm_set_req *req, - __u32 verify_time) -{ - req->_present.verify_time = 1; - req->verify_time = verify_time; -} -static inline void -ethtool_mm_set_req_set_tx_enabled(struct ethtool_mm_set_req *req, - __u8 tx_enabled) -{ - req->_present.tx_enabled = 1; - req->tx_enabled = tx_enabled; -} -static inline void -ethtool_mm_set_req_set_pmac_enabled(struct ethtool_mm_set_req *req, - __u8 pmac_enabled) -{ - req->_present.pmac_enabled = 1; - req->pmac_enabled = pmac_enabled; -} -static inline void -ethtool_mm_set_req_set_tx_min_frag_size(struct ethtool_mm_set_req *req, - __u32 tx_min_frag_size) -{ - req->_present.tx_min_frag_size = 1; - req->tx_min_frag_size = tx_min_frag_size; -} - -/* - * Set MAC Merge configuration - */ -int ethtool_mm_set(struct ynl_sock *ys, struct ethtool_mm_set_req *req); - -/* ETHTOOL_MSG_CABLE_TEST_NTF - event */ -struct ethtool_cable_test_ntf_rsp { - struct { - __u32 header:1; - __u32 status:1; - } _present; - - struct ethtool_header header; - __u8 status; -}; - -struct ethtool_cable_test_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_cable_test_ntf *ntf); - struct ethtool_cable_test_ntf_rsp obj __attribute__ ((aligned (8))); -}; - -void ethtool_cable_test_ntf_free(struct ethtool_cable_test_ntf *rsp); - -/* ETHTOOL_MSG_CABLE_TEST_TDR_NTF - event */ -struct ethtool_cable_test_tdr_ntf_rsp { - struct { - __u32 header:1; - __u32 status:1; - __u32 nest:1; - } _present; - - struct ethtool_header header; - __u8 status; - struct ethtool_cable_nest nest; -}; - -struct ethtool_cable_test_tdr_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_cable_test_tdr_ntf *ntf); - struct ethtool_cable_test_tdr_ntf_rsp obj __attribute__ ((aligned (8))); -}; - -void ethtool_cable_test_tdr_ntf_free(struct ethtool_cable_test_tdr_ntf *rsp); - -#endif /* _LINUX_ETHTOOL_GEN_H */ diff --git a/tools/net/ynl/generated/fou-user.c b/tools/net/ynl/generated/fou-user.c deleted file mode 100644 index 4271b5d43c58..000000000000 --- a/tools/net/ynl/generated/fou-user.c +++ /dev/null @@ -1,328 +0,0 @@ -// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) -/* Do not edit directly, auto-generated from: */ -/* Documentation/netlink/specs/fou.yaml */ -/* YNL-GEN user source */ - -#include <stdlib.h> -#include <string.h> -#include "fou-user.h" -#include "ynl.h" -#include <linux/fou.h> - -#include <libmnl/libmnl.h> -#include <linux/genetlink.h> - -/* Enums */ -static const char * const fou_op_strmap[] = { - [FOU_CMD_ADD] = "add", - [FOU_CMD_DEL] = "del", - [FOU_CMD_GET] = "get", -}; - -const char *fou_op_str(int op) -{ - if (op < 0 || op >= (int)MNL_ARRAY_SIZE(fou_op_strmap)) - return NULL; - return fou_op_strmap[op]; -} - -static const char * const fou_encap_type_strmap[] = { - [0] = "unspec", - [1] = "direct", - [2] = "gue", -}; - -const char *fou_encap_type_str(int value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(fou_encap_type_strmap)) - return NULL; - return fou_encap_type_strmap[value]; -} - -/* Policies */ -struct ynl_policy_attr fou_policy[FOU_ATTR_MAX + 1] = { - [FOU_ATTR_UNSPEC] = { .name = "unspec", .type = YNL_PT_REJECT, }, - [FOU_ATTR_PORT] = { .name = "port", .type = YNL_PT_U16, }, - [FOU_ATTR_AF] = { .name = "af", .type = YNL_PT_U8, }, - [FOU_ATTR_IPPROTO] = { .name = "ipproto", .type = YNL_PT_U8, }, - [FOU_ATTR_TYPE] = { .name = "type", .type = YNL_PT_U8, }, - [FOU_ATTR_REMCSUM_NOPARTIAL] = { .name = "remcsum_nopartial", .type = YNL_PT_FLAG, }, - [FOU_ATTR_LOCAL_V4] = { .name = "local_v4", .type = YNL_PT_U32, }, - [FOU_ATTR_LOCAL_V6] = { .name = "local_v6", .type = YNL_PT_BINARY,}, - [FOU_ATTR_PEER_V4] = { .name = "peer_v4", .type = YNL_PT_U32, }, - [FOU_ATTR_PEER_V6] = { .name = "peer_v6", .type = YNL_PT_BINARY,}, - [FOU_ATTR_PEER_PORT] = { .name = "peer_port", .type = YNL_PT_U16, }, - [FOU_ATTR_IFINDEX] = { .name = "ifindex", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest fou_nest = { - .max_attr = FOU_ATTR_MAX, - .table = fou_policy, -}; - -/* Common nested types */ -/* ============== FOU_CMD_ADD ============== */ -/* FOU_CMD_ADD - do */ -void fou_add_req_free(struct fou_add_req *req) -{ - free(req->local_v6); - free(req->peer_v6); - free(req); -} - -int fou_add(struct ynl_sock *ys, struct fou_add_req *req) -{ - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, FOU_CMD_ADD, 1); - ys->req_policy = &fou_nest; - - if (req->_present.port) - mnl_attr_put_u16(nlh, FOU_ATTR_PORT, req->port); - if (req->_present.ipproto) - mnl_attr_put_u8(nlh, FOU_ATTR_IPPROTO, req->ipproto); - if (req->_present.type) - mnl_attr_put_u8(nlh, FOU_ATTR_TYPE, req->type); - if (req->_present.remcsum_nopartial) - mnl_attr_put(nlh, FOU_ATTR_REMCSUM_NOPARTIAL, 0, NULL); - if (req->_present.local_v4) - mnl_attr_put_u32(nlh, FOU_ATTR_LOCAL_V4, req->local_v4); - if (req->_present.peer_v4) - mnl_attr_put_u32(nlh, FOU_ATTR_PEER_V4, req->peer_v4); - if (req->_present.local_v6_len) - mnl_attr_put(nlh, FOU_ATTR_LOCAL_V6, req->_present.local_v6_len, req->local_v6); - if (req->_present.peer_v6_len) - mnl_attr_put(nlh, FOU_ATTR_PEER_V6, req->_present.peer_v6_len, req->peer_v6); - if (req->_present.peer_port) - mnl_attr_put_u16(nlh, FOU_ATTR_PEER_PORT, req->peer_port); - if (req->_present.ifindex) - mnl_attr_put_u32(nlh, FOU_ATTR_IFINDEX, req->ifindex); - - err = ynl_exec(ys, nlh, NULL); - if (err < 0) - return -1; - - return 0; -} - -/* ============== FOU_CMD_DEL ============== */ -/* FOU_CMD_DEL - do */ -void fou_del_req_free(struct fou_del_req *req) -{ - free(req->local_v6); - free(req->peer_v6); - free(req); -} - -int fou_del(struct ynl_sock *ys, struct fou_del_req *req) -{ - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, FOU_CMD_DEL, 1); - ys->req_policy = &fou_nest; - - if (req->_present.af) - mnl_attr_put_u8(nlh, FOU_ATTR_AF, req->af); - if (req->_present.ifindex) - mnl_attr_put_u32(nlh, FOU_ATTR_IFINDEX, req->ifindex); - if (req->_present.port) - mnl_attr_put_u16(nlh, FOU_ATTR_PORT, req->port); - if (req->_present.peer_port) - mnl_attr_put_u16(nlh, FOU_ATTR_PEER_PORT, req->peer_port); - if (req->_present.local_v4) - mnl_attr_put_u32(nlh, FOU_ATTR_LOCAL_V4, req->local_v4); - if (req->_present.peer_v4) - mnl_attr_put_u32(nlh, FOU_ATTR_PEER_V4, req->peer_v4); - if (req->_present.local_v6_len) - mnl_attr_put(nlh, FOU_ATTR_LOCAL_V6, req->_present.local_v6_len, req->local_v6); - if (req->_present.peer_v6_len) - mnl_attr_put(nlh, FOU_ATTR_PEER_V6, req->_present.peer_v6_len, req->peer_v6); - - err = ynl_exec(ys, nlh, NULL); - if (err < 0) - return -1; - - return 0; -} - -/* ============== FOU_CMD_GET ============== */ -/* FOU_CMD_GET - do */ -void fou_get_req_free(struct fou_get_req *req) -{ - free(req->local_v6); - free(req->peer_v6); - free(req); -} - -void fou_get_rsp_free(struct fou_get_rsp *rsp) -{ - free(rsp->local_v6); - free(rsp->peer_v6); - free(rsp); -} - -int fou_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct fou_get_rsp *dst; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == FOU_ATTR_PORT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.port = 1; - dst->port = mnl_attr_get_u16(attr); - } else if (type == FOU_ATTR_IPPROTO) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.ipproto = 1; - dst->ipproto = mnl_attr_get_u8(attr); - } else if (type == FOU_ATTR_TYPE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.type = 1; - dst->type = mnl_attr_get_u8(attr); - } else if (type == FOU_ATTR_REMCSUM_NOPARTIAL) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.remcsum_nopartial = 1; - } else if (type == FOU_ATTR_LOCAL_V4) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.local_v4 = 1; - dst->local_v4 = mnl_attr_get_u32(attr); - } else if (type == FOU_ATTR_PEER_V4) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.peer_v4 = 1; - dst->peer_v4 = mnl_attr_get_u32(attr); - } else if (type == FOU_ATTR_LOCAL_V6) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = mnl_attr_get_payload_len(attr); - dst->_present.local_v6_len = len; - dst->local_v6 = malloc(len); - memcpy(dst->local_v6, mnl_attr_get_payload(attr), len); - } else if (type == FOU_ATTR_PEER_V6) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = mnl_attr_get_payload_len(attr); - dst->_present.peer_v6_len = len; - dst->peer_v6 = malloc(len); - memcpy(dst->peer_v6, mnl_attr_get_payload(attr), len); - } else if (type == FOU_ATTR_PEER_PORT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.peer_port = 1; - dst->peer_port = mnl_attr_get_u16(attr); - } else if (type == FOU_ATTR_IFINDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.ifindex = 1; - dst->ifindex = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct fou_get_rsp *fou_get(struct ynl_sock *ys, struct fou_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct fou_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, FOU_CMD_GET, 1); - ys->req_policy = &fou_nest; - yrs.yarg.rsp_policy = &fou_nest; - - if (req->_present.af) - mnl_attr_put_u8(nlh, FOU_ATTR_AF, req->af); - if (req->_present.ifindex) - mnl_attr_put_u32(nlh, FOU_ATTR_IFINDEX, req->ifindex); - if (req->_present.port) - mnl_attr_put_u16(nlh, FOU_ATTR_PORT, req->port); - if (req->_present.peer_port) - mnl_attr_put_u16(nlh, FOU_ATTR_PEER_PORT, req->peer_port); - if (req->_present.local_v4) - mnl_attr_put_u32(nlh, FOU_ATTR_LOCAL_V4, req->local_v4); - if (req->_present.peer_v4) - mnl_attr_put_u32(nlh, FOU_ATTR_PEER_V4, req->peer_v4); - if (req->_present.local_v6_len) - mnl_attr_put(nlh, FOU_ATTR_LOCAL_V6, req->_present.local_v6_len, req->local_v6); - if (req->_present.peer_v6_len) - mnl_attr_put(nlh, FOU_ATTR_PEER_V6, req->_present.peer_v6_len, req->peer_v6); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = fou_get_rsp_parse; - yrs.rsp_cmd = FOU_CMD_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - fou_get_rsp_free(rsp); - return NULL; -} - -/* FOU_CMD_GET - dump */ -void fou_get_list_free(struct fou_get_list *rsp) -{ - struct fou_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.local_v6); - free(rsp->obj.peer_v6); - free(rsp); - } -} - -struct fou_get_list *fou_get_dump(struct ynl_sock *ys) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct fou_get_list); - yds.cb = fou_get_rsp_parse; - yds.rsp_cmd = FOU_CMD_GET; - yds.rsp_policy = &fou_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, FOU_CMD_GET, 1); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - fou_get_list_free(yds.first); - return NULL; -} - -const struct ynl_family ynl_fou_family = { - .name = "fou", -}; diff --git a/tools/net/ynl/generated/fou-user.h b/tools/net/ynl/generated/fou-user.h deleted file mode 100644 index a8f860892540..000000000000 --- a/tools/net/ynl/generated/fou-user.h +++ /dev/null @@ -1,343 +0,0 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ -/* Do not edit directly, auto-generated from: */ -/* Documentation/netlink/specs/fou.yaml */ -/* YNL-GEN user header */ - -#ifndef _LINUX_FOU_GEN_H -#define _LINUX_FOU_GEN_H - -#include <stdlib.h> -#include <string.h> -#include <linux/types.h> -#include <linux/fou.h> - -struct ynl_sock; - -extern const struct ynl_family ynl_fou_family; - -/* Enums */ -const char *fou_op_str(int op); -const char *fou_encap_type_str(int value); - -/* Common nested types */ -/* ============== FOU_CMD_ADD ============== */ -/* FOU_CMD_ADD - do */ -struct fou_add_req { - struct { - __u32 port:1; - __u32 ipproto:1; - __u32 type:1; - __u32 remcsum_nopartial:1; - __u32 local_v4:1; - __u32 peer_v4:1; - __u32 local_v6_len; - __u32 peer_v6_len; - __u32 peer_port:1; - __u32 ifindex:1; - } _present; - - __u16 port /* big-endian */; - __u8 ipproto; - __u8 type; - __u32 local_v4; - __u32 peer_v4; - void *local_v6; - void *peer_v6; - __u16 peer_port /* big-endian */; - __s32 ifindex; -}; - -static inline struct fou_add_req *fou_add_req_alloc(void) -{ - return calloc(1, sizeof(struct fou_add_req)); -} -void fou_add_req_free(struct fou_add_req *req); - -static inline void -fou_add_req_set_port(struct fou_add_req *req, __u16 port /* big-endian */) -{ - req->_present.port = 1; - req->port = port; -} -static inline void -fou_add_req_set_ipproto(struct fou_add_req *req, __u8 ipproto) -{ - req->_present.ipproto = 1; - req->ipproto = ipproto; -} -static inline void fou_add_req_set_type(struct fou_add_req *req, __u8 type) -{ - req->_present.type = 1; - req->type = type; -} -static inline void fou_add_req_set_remcsum_nopartial(struct fou_add_req *req) -{ - req->_present.remcsum_nopartial = 1; -} -static inline void -fou_add_req_set_local_v4(struct fou_add_req *req, __u32 local_v4) -{ - req->_present.local_v4 = 1; - req->local_v4 = local_v4; -} -static inline void -fou_add_req_set_peer_v4(struct fou_add_req *req, __u32 peer_v4) -{ - req->_present.peer_v4 = 1; - req->peer_v4 = peer_v4; -} -static inline void -fou_add_req_set_local_v6(struct fou_add_req *req, const void *local_v6, - size_t len) -{ - free(req->local_v6); - req->_present.local_v6_len = len; - req->local_v6 = malloc(req->_present.local_v6_len); - memcpy(req->local_v6, local_v6, req->_present.local_v6_len); -} -static inline void -fou_add_req_set_peer_v6(struct fou_add_req *req, const void *peer_v6, - size_t len) -{ - free(req->peer_v6); - req->_present.peer_v6_len = len; - req->peer_v6 = malloc(req->_present.peer_v6_len); - memcpy(req->peer_v6, peer_v6, req->_present.peer_v6_len); -} -static inline void -fou_add_req_set_peer_port(struct fou_add_req *req, - __u16 peer_port /* big-endian */) -{ - req->_present.peer_port = 1; - req->peer_port = peer_port; -} -static inline void -fou_add_req_set_ifindex(struct fou_add_req *req, __s32 ifindex) -{ - req->_present.ifindex = 1; - req->ifindex = ifindex; -} - -/* - * Add port. - */ -int fou_add(struct ynl_sock *ys, struct fou_add_req *req); - -/* ============== FOU_CMD_DEL ============== */ -/* FOU_CMD_DEL - do */ -struct fou_del_req { - struct { - __u32 af:1; - __u32 ifindex:1; - __u32 port:1; - __u32 peer_port:1; - __u32 local_v4:1; - __u32 peer_v4:1; - __u32 local_v6_len; - __u32 peer_v6_len; - } _present; - - __u8 af; - __s32 ifindex; - __u16 port /* big-endian */; - __u16 peer_port /* big-endian */; - __u32 local_v4; - __u32 peer_v4; - void *local_v6; - void *peer_v6; -}; - -static inline struct fou_del_req *fou_del_req_alloc(void) -{ - return calloc(1, sizeof(struct fou_del_req)); -} -void fou_del_req_free(struct fou_del_req *req); - -static inline void fou_del_req_set_af(struct fou_del_req *req, __u8 af) -{ - req->_present.af = 1; - req->af = af; -} -static inline void -fou_del_req_set_ifindex(struct fou_del_req *req, __s32 ifindex) -{ - req->_present.ifindex = 1; - req->ifindex = ifindex; -} -static inline void -fou_del_req_set_port(struct fou_del_req *req, __u16 port /* big-endian */) -{ - req->_present.port = 1; - req->port = port; -} -static inline void -fou_del_req_set_peer_port(struct fou_del_req *req, - __u16 peer_port /* big-endian */) -{ - req->_present.peer_port = 1; - req->peer_port = peer_port; -} -static inline void -fou_del_req_set_local_v4(struct fou_del_req *req, __u32 local_v4) -{ - req->_present.local_v4 = 1; - req->local_v4 = local_v4; -} -static inline void -fou_del_req_set_peer_v4(struct fou_del_req *req, __u32 peer_v4) -{ - req->_present.peer_v4 = 1; - req->peer_v4 = peer_v4; -} -static inline void -fou_del_req_set_local_v6(struct fou_del_req *req, const void *local_v6, - size_t len) -{ - free(req->local_v6); - req->_present.local_v6_len = len; - req->local_v6 = malloc(req->_present.local_v6_len); - memcpy(req->local_v6, local_v6, req->_present.local_v6_len); -} -static inline void -fou_del_req_set_peer_v6(struct fou_del_req *req, const void *peer_v6, - size_t len) -{ - free(req->peer_v6); - req->_present.peer_v6_len = len; - req->peer_v6 = malloc(req->_present.peer_v6_len); - memcpy(req->peer_v6, peer_v6, req->_present.peer_v6_len); -} - -/* - * Delete port. - */ -int fou_del(struct ynl_sock *ys, struct fou_del_req *req); - -/* ============== FOU_CMD_GET ============== */ -/* FOU_CMD_GET - do */ -struct fou_get_req { - struct { - __u32 af:1; - __u32 ifindex:1; - __u32 port:1; - __u32 peer_port:1; - __u32 local_v4:1; - __u32 peer_v4:1; - __u32 local_v6_len; - __u32 peer_v6_len; - } _present; - - __u8 af; - __s32 ifindex; - __u16 port /* big-endian */; - __u16 peer_port /* big-endian */; - __u32 local_v4; - __u32 peer_v4; - void *local_v6; - void *peer_v6; -}; - -static inline struct fou_get_req *fou_get_req_alloc(void) -{ - return calloc(1, sizeof(struct fou_get_req)); -} -void fou_get_req_free(struct fou_get_req *req); - -static inline void fou_get_req_set_af(struct fou_get_req *req, __u8 af) -{ - req->_present.af = 1; - req->af = af; -} -static inline void -fou_get_req_set_ifindex(struct fou_get_req *req, __s32 ifindex) -{ - req->_present.ifindex = 1; - req->ifindex = ifindex; -} -static inline void -fou_get_req_set_port(struct fou_get_req *req, __u16 port /* big-endian */) -{ - req->_present.port = 1; - req->port = port; -} -static inline void -fou_get_req_set_peer_port(struct fou_get_req *req, - __u16 peer_port /* big-endian */) -{ - req->_present.peer_port = 1; - req->peer_port = peer_port; -} -static inline void -fou_get_req_set_local_v4(struct fou_get_req *req, __u32 local_v4) -{ - req->_present.local_v4 = 1; - req->local_v4 = local_v4; -} -static inline void -fou_get_req_set_peer_v4(struct fou_get_req *req, __u32 peer_v4) -{ - req->_present.peer_v4 = 1; - req->peer_v4 = peer_v4; -} -static inline void -fou_get_req_set_local_v6(struct fou_get_req *req, const void *local_v6, - size_t len) -{ - free(req->local_v6); - req->_present.local_v6_len = len; - req->local_v6 = malloc(req->_present.local_v6_len); - memcpy(req->local_v6, local_v6, req->_present.local_v6_len); -} -static inline void -fou_get_req_set_peer_v6(struct fou_get_req *req, const void *peer_v6, - size_t len) -{ - free(req->peer_v6); - req->_present.peer_v6_len = len; - req->peer_v6 = malloc(req->_present.peer_v6_len); - memcpy(req->peer_v6, peer_v6, req->_present.peer_v6_len); -} - -struct fou_get_rsp { - struct { - __u32 port:1; - __u32 ipproto:1; - __u32 type:1; - __u32 remcsum_nopartial:1; - __u32 local_v4:1; - __u32 peer_v4:1; - __u32 local_v6_len; - __u32 peer_v6_len; - __u32 peer_port:1; - __u32 ifindex:1; - } _present; - - __u16 port /* big-endian */; - __u8 ipproto; - __u8 type; - __u32 local_v4; - __u32 peer_v4; - void *local_v6; - void *peer_v6; - __u16 peer_port /* big-endian */; - __s32 ifindex; -}; - -void fou_get_rsp_free(struct fou_get_rsp *rsp); - -/* - * Get tunnel info. - */ -struct fou_get_rsp *fou_get(struct ynl_sock *ys, struct fou_get_req *req); - -/* FOU_CMD_GET - dump */ -struct fou_get_list { - struct fou_get_list *next; - struct fou_get_rsp obj __attribute__ ((aligned (8))); -}; - -void fou_get_list_free(struct fou_get_list *rsp); - -struct fou_get_list *fou_get_dump(struct ynl_sock *ys); - -#endif /* _LINUX_FOU_GEN_H */ diff --git a/tools/net/ynl/generated/handshake-user.c b/tools/net/ynl/generated/handshake-user.c deleted file mode 100644 index 7c67765daf90..000000000000 --- a/tools/net/ynl/generated/handshake-user.c +++ /dev/null @@ -1,331 +0,0 @@ -// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) -/* Do not edit directly, auto-generated from: */ -/* Documentation/netlink/specs/handshake.yaml */ -/* YNL-GEN user source */ - -#include <stdlib.h> -#include <string.h> -#include "handshake-user.h" -#include "ynl.h" -#include <linux/handshake.h> - -#include <libmnl/libmnl.h> -#include <linux/genetlink.h> - -/* Enums */ -static const char * const handshake_op_strmap[] = { - [HANDSHAKE_CMD_READY] = "ready", - [HANDSHAKE_CMD_ACCEPT] = "accept", - [HANDSHAKE_CMD_DONE] = "done", -}; - -const char *handshake_op_str(int op) -{ - if (op < 0 || op >= (int)MNL_ARRAY_SIZE(handshake_op_strmap)) - return NULL; - return handshake_op_strmap[op]; -} - -static const char * const handshake_handler_class_strmap[] = { - [0] = "none", - [1] = "tlshd", - [2] = "max", -}; - -const char *handshake_handler_class_str(enum handshake_handler_class value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(handshake_handler_class_strmap)) - return NULL; - return handshake_handler_class_strmap[value]; -} - -static const char * const handshake_msg_type_strmap[] = { - [0] = "unspec", - [1] = "clienthello", - [2] = "serverhello", -}; - -const char *handshake_msg_type_str(enum handshake_msg_type value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(handshake_msg_type_strmap)) - return NULL; - return handshake_msg_type_strmap[value]; -} - -static const char * const handshake_auth_strmap[] = { - [0] = "unspec", - [1] = "unauth", - [2] = "psk", - [3] = "x509", -}; - -const char *handshake_auth_str(enum handshake_auth value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(handshake_auth_strmap)) - return NULL; - return handshake_auth_strmap[value]; -} - -/* Policies */ -struct ynl_policy_attr handshake_x509_policy[HANDSHAKE_A_X509_MAX + 1] = { - [HANDSHAKE_A_X509_CERT] = { .name = "cert", .type = YNL_PT_U32, }, - [HANDSHAKE_A_X509_PRIVKEY] = { .name = "privkey", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest handshake_x509_nest = { - .max_attr = HANDSHAKE_A_X509_MAX, - .table = handshake_x509_policy, -}; - -struct ynl_policy_attr handshake_accept_policy[HANDSHAKE_A_ACCEPT_MAX + 1] = { - [HANDSHAKE_A_ACCEPT_SOCKFD] = { .name = "sockfd", .type = YNL_PT_U32, }, - [HANDSHAKE_A_ACCEPT_HANDLER_CLASS] = { .name = "handler-class", .type = YNL_PT_U32, }, - [HANDSHAKE_A_ACCEPT_MESSAGE_TYPE] = { .name = "message-type", .type = YNL_PT_U32, }, - [HANDSHAKE_A_ACCEPT_TIMEOUT] = { .name = "timeout", .type = YNL_PT_U32, }, - [HANDSHAKE_A_ACCEPT_AUTH_MODE] = { .name = "auth-mode", .type = YNL_PT_U32, }, - [HANDSHAKE_A_ACCEPT_PEER_IDENTITY] = { .name = "peer-identity", .type = YNL_PT_U32, }, - [HANDSHAKE_A_ACCEPT_CERTIFICATE] = { .name = "certificate", .type = YNL_PT_NEST, .nest = &handshake_x509_nest, }, - [HANDSHAKE_A_ACCEPT_PEERNAME] = { .name = "peername", .type = YNL_PT_NUL_STR, }, -}; - -struct ynl_policy_nest handshake_accept_nest = { - .max_attr = HANDSHAKE_A_ACCEPT_MAX, - .table = handshake_accept_policy, -}; - -struct ynl_policy_attr handshake_done_policy[HANDSHAKE_A_DONE_MAX + 1] = { - [HANDSHAKE_A_DONE_STATUS] = { .name = "status", .type = YNL_PT_U32, }, - [HANDSHAKE_A_DONE_SOCKFD] = { .name = "sockfd", .type = YNL_PT_U32, }, - [HANDSHAKE_A_DONE_REMOTE_AUTH] = { .name = "remote-auth", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest handshake_done_nest = { - .max_attr = HANDSHAKE_A_DONE_MAX, - .table = handshake_done_policy, -}; - -/* Common nested types */ -void handshake_x509_free(struct handshake_x509 *obj) -{ -} - -int handshake_x509_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct handshake_x509 *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == HANDSHAKE_A_X509_CERT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.cert = 1; - dst->cert = mnl_attr_get_u32(attr); - } else if (type == HANDSHAKE_A_X509_PRIVKEY) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.privkey = 1; - dst->privkey = mnl_attr_get_u32(attr); - } - } - - return 0; -} - -/* ============== HANDSHAKE_CMD_ACCEPT ============== */ -/* HANDSHAKE_CMD_ACCEPT - do */ -void handshake_accept_req_free(struct handshake_accept_req *req) -{ - free(req); -} - -void handshake_accept_rsp_free(struct handshake_accept_rsp *rsp) -{ - unsigned int i; - - free(rsp->peer_identity); - for (i = 0; i < rsp->n_certificate; i++) - handshake_x509_free(&rsp->certificate[i]); - free(rsp->certificate); - free(rsp->peername); - free(rsp); -} - -int handshake_accept_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct handshake_accept_rsp *dst; - unsigned int n_peer_identity = 0; - unsigned int n_certificate = 0; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - dst = yarg->data; - parg.ys = yarg->ys; - - if (dst->certificate) - return ynl_error_parse(yarg, "attribute already present (accept.certificate)"); - if (dst->peer_identity) - return ynl_error_parse(yarg, "attribute already present (accept.peer-identity)"); - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == HANDSHAKE_A_ACCEPT_SOCKFD) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.sockfd = 1; - dst->sockfd = mnl_attr_get_u32(attr); - } else if (type == HANDSHAKE_A_ACCEPT_MESSAGE_TYPE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.message_type = 1; - dst->message_type = mnl_attr_get_u32(attr); - } else if (type == HANDSHAKE_A_ACCEPT_TIMEOUT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.timeout = 1; - dst->timeout = mnl_attr_get_u32(attr); - } else if (type == HANDSHAKE_A_ACCEPT_AUTH_MODE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.auth_mode = 1; - dst->auth_mode = mnl_attr_get_u32(attr); - } else if (type == HANDSHAKE_A_ACCEPT_PEER_IDENTITY) { - n_peer_identity++; - } else if (type == HANDSHAKE_A_ACCEPT_CERTIFICATE) { - n_certificate++; - } else if (type == HANDSHAKE_A_ACCEPT_PEERNAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.peername_len = len; - dst->peername = malloc(len + 1); - memcpy(dst->peername, mnl_attr_get_str(attr), len); - dst->peername[len] = 0; - } - } - - if (n_certificate) { - dst->certificate = calloc(n_certificate, sizeof(*dst->certificate)); - dst->n_certificate = n_certificate; - i = 0; - parg.rsp_policy = &handshake_x509_nest; - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - if (mnl_attr_get_type(attr) == HANDSHAKE_A_ACCEPT_CERTIFICATE) { - parg.data = &dst->certificate[i]; - if (handshake_x509_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - if (n_peer_identity) { - dst->peer_identity = calloc(n_peer_identity, sizeof(*dst->peer_identity)); - dst->n_peer_identity = n_peer_identity; - i = 0; - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - if (mnl_attr_get_type(attr) == HANDSHAKE_A_ACCEPT_PEER_IDENTITY) { - dst->peer_identity[i] = mnl_attr_get_u32(attr); - i++; - } - } - } - - return MNL_CB_OK; -} - -struct handshake_accept_rsp * -handshake_accept(struct ynl_sock *ys, struct handshake_accept_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct handshake_accept_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, HANDSHAKE_CMD_ACCEPT, 1); - ys->req_policy = &handshake_accept_nest; - yrs.yarg.rsp_policy = &handshake_accept_nest; - - if (req->_present.handler_class) - mnl_attr_put_u32(nlh, HANDSHAKE_A_ACCEPT_HANDLER_CLASS, req->handler_class); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = handshake_accept_rsp_parse; - yrs.rsp_cmd = HANDSHAKE_CMD_ACCEPT; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - handshake_accept_rsp_free(rsp); - return NULL; -} - -/* HANDSHAKE_CMD_ACCEPT - notify */ -void handshake_accept_ntf_free(struct handshake_accept_ntf *rsp) -{ - unsigned int i; - - free(rsp->obj.peer_identity); - for (i = 0; i < rsp->obj.n_certificate; i++) - handshake_x509_free(&rsp->obj.certificate[i]); - free(rsp->obj.certificate); - free(rsp->obj.peername); - free(rsp); -} - -/* ============== HANDSHAKE_CMD_DONE ============== */ -/* HANDSHAKE_CMD_DONE - do */ -void handshake_done_req_free(struct handshake_done_req *req) -{ - free(req->remote_auth); - free(req); -} - -int handshake_done(struct ynl_sock *ys, struct handshake_done_req *req) -{ - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, HANDSHAKE_CMD_DONE, 1); - ys->req_policy = &handshake_done_nest; - - if (req->_present.status) - mnl_attr_put_u32(nlh, HANDSHAKE_A_DONE_STATUS, req->status); - if (req->_present.sockfd) - mnl_attr_put_u32(nlh, HANDSHAKE_A_DONE_SOCKFD, req->sockfd); - for (unsigned int i = 0; i < req->n_remote_auth; i++) - mnl_attr_put_u32(nlh, HANDSHAKE_A_DONE_REMOTE_AUTH, req->remote_auth[i]); - - err = ynl_exec(ys, nlh, NULL); - if (err < 0) - return -1; - - return 0; -} - -static const struct ynl_ntf_info handshake_ntf_info[] = { - [HANDSHAKE_CMD_READY] = { - .alloc_sz = sizeof(struct handshake_accept_ntf), - .cb = handshake_accept_rsp_parse, - .policy = &handshake_accept_nest, - .free = (void *)handshake_accept_ntf_free, - }, -}; - -const struct ynl_family ynl_handshake_family = { - .name = "handshake", - .ntf_info = handshake_ntf_info, - .ntf_info_size = MNL_ARRAY_SIZE(handshake_ntf_info), -}; diff --git a/tools/net/ynl/generated/handshake-user.h b/tools/net/ynl/generated/handshake-user.h deleted file mode 100644 index 47646bb91cea..000000000000 --- a/tools/net/ynl/generated/handshake-user.h +++ /dev/null @@ -1,145 +0,0 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ -/* Do not edit directly, auto-generated from: */ -/* Documentation/netlink/specs/handshake.yaml */ -/* YNL-GEN user header */ - -#ifndef _LINUX_HANDSHAKE_GEN_H -#define _LINUX_HANDSHAKE_GEN_H - -#include <stdlib.h> -#include <string.h> -#include <linux/types.h> -#include <linux/handshake.h> - -struct ynl_sock; - -extern const struct ynl_family ynl_handshake_family; - -/* Enums */ -const char *handshake_op_str(int op); -const char *handshake_handler_class_str(enum handshake_handler_class value); -const char *handshake_msg_type_str(enum handshake_msg_type value); -const char *handshake_auth_str(enum handshake_auth value); - -/* Common nested types */ -struct handshake_x509 { - struct { - __u32 cert:1; - __u32 privkey:1; - } _present; - - __u32 cert; - __u32 privkey; -}; - -/* ============== HANDSHAKE_CMD_ACCEPT ============== */ -/* HANDSHAKE_CMD_ACCEPT - do */ -struct handshake_accept_req { - struct { - __u32 handler_class:1; - } _present; - - enum handshake_handler_class handler_class; -}; - -static inline struct handshake_accept_req *handshake_accept_req_alloc(void) -{ - return calloc(1, sizeof(struct handshake_accept_req)); -} -void handshake_accept_req_free(struct handshake_accept_req *req); - -static inline void -handshake_accept_req_set_handler_class(struct handshake_accept_req *req, - enum handshake_handler_class handler_class) -{ - req->_present.handler_class = 1; - req->handler_class = handler_class; -} - -struct handshake_accept_rsp { - struct { - __u32 sockfd:1; - __u32 message_type:1; - __u32 timeout:1; - __u32 auth_mode:1; - __u32 peername_len; - } _present; - - __u32 sockfd; - enum handshake_msg_type message_type; - __u32 timeout; - enum handshake_auth auth_mode; - unsigned int n_peer_identity; - __u32 *peer_identity; - unsigned int n_certificate; - struct handshake_x509 *certificate; - char *peername; -}; - -void handshake_accept_rsp_free(struct handshake_accept_rsp *rsp); - -/* - * Handler retrieves next queued handshake request - */ -struct handshake_accept_rsp * -handshake_accept(struct ynl_sock *ys, struct handshake_accept_req *req); - -/* HANDSHAKE_CMD_ACCEPT - notify */ -struct handshake_accept_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct handshake_accept_ntf *ntf); - struct handshake_accept_rsp obj __attribute__ ((aligned (8))); -}; - -void handshake_accept_ntf_free(struct handshake_accept_ntf *rsp); - -/* ============== HANDSHAKE_CMD_DONE ============== */ -/* HANDSHAKE_CMD_DONE - do */ -struct handshake_done_req { - struct { - __u32 status:1; - __u32 sockfd:1; - } _present; - - __u32 status; - __u32 sockfd; - unsigned int n_remote_auth; - __u32 *remote_auth; -}; - -static inline struct handshake_done_req *handshake_done_req_alloc(void) -{ - return calloc(1, sizeof(struct handshake_done_req)); -} -void handshake_done_req_free(struct handshake_done_req *req); - -static inline void -handshake_done_req_set_status(struct handshake_done_req *req, __u32 status) -{ - req->_present.status = 1; - req->status = status; -} -static inline void -handshake_done_req_set_sockfd(struct handshake_done_req *req, __u32 sockfd) -{ - req->_present.sockfd = 1; - req->sockfd = sockfd; -} -static inline void -__handshake_done_req_set_remote_auth(struct handshake_done_req *req, - __u32 *remote_auth, - unsigned int n_remote_auth) -{ - free(req->remote_auth); - req->remote_auth = remote_auth; - req->n_remote_auth = n_remote_auth; -} - -/* - * Handler reports handshake completion - */ -int handshake_done(struct ynl_sock *ys, struct handshake_done_req *req); - -#endif /* _LINUX_HANDSHAKE_GEN_H */ diff --git a/tools/net/ynl/generated/netdev-user.c b/tools/net/ynl/generated/netdev-user.c deleted file mode 100644 index 68b408ca0f7f..000000000000 --- a/tools/net/ynl/generated/netdev-user.c +++ /dev/null @@ -1,206 +0,0 @@ -// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) -/* Do not edit directly, auto-generated from: */ -/* Documentation/netlink/specs/netdev.yaml */ -/* YNL-GEN user source */ - -#include <stdlib.h> -#include <string.h> -#include "netdev-user.h" -#include "ynl.h" -#include <linux/netdev.h> - -#include <libmnl/libmnl.h> -#include <linux/genetlink.h> - -/* Enums */ -static const char * const netdev_op_strmap[] = { - [NETDEV_CMD_DEV_GET] = "dev-get", - [NETDEV_CMD_DEV_ADD_NTF] = "dev-add-ntf", - [NETDEV_CMD_DEV_DEL_NTF] = "dev-del-ntf", - [NETDEV_CMD_DEV_CHANGE_NTF] = "dev-change-ntf", -}; - -const char *netdev_op_str(int op) -{ - if (op < 0 || op >= (int)MNL_ARRAY_SIZE(netdev_op_strmap)) - return NULL; - return netdev_op_strmap[op]; -} - -static const char * const netdev_xdp_act_strmap[] = { - [0] = "basic", - [1] = "redirect", - [2] = "ndo-xmit", - [3] = "xsk-zerocopy", - [4] = "hw-offload", - [5] = "rx-sg", - [6] = "ndo-xmit-sg", -}; - -const char *netdev_xdp_act_str(enum netdev_xdp_act value) -{ - value = ffs(value) - 1; - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(netdev_xdp_act_strmap)) - return NULL; - return netdev_xdp_act_strmap[value]; -} - -/* Policies */ -struct ynl_policy_attr netdev_dev_policy[NETDEV_A_DEV_MAX + 1] = { - [NETDEV_A_DEV_IFINDEX] = { .name = "ifindex", .type = YNL_PT_U32, }, - [NETDEV_A_DEV_PAD] = { .name = "pad", .type = YNL_PT_IGNORE, }, - [NETDEV_A_DEV_XDP_FEATURES] = { .name = "xdp-features", .type = YNL_PT_U64, }, - [NETDEV_A_DEV_XDP_ZC_MAX_SEGS] = { .name = "xdp-zc-max-segs", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest netdev_dev_nest = { - .max_attr = NETDEV_A_DEV_MAX, - .table = netdev_dev_policy, -}; - -/* Common nested types */ -/* ============== NETDEV_CMD_DEV_GET ============== */ -/* NETDEV_CMD_DEV_GET - do */ -void netdev_dev_get_req_free(struct netdev_dev_get_req *req) -{ - free(req); -} - -void netdev_dev_get_rsp_free(struct netdev_dev_get_rsp *rsp) -{ - free(rsp); -} - -int netdev_dev_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct netdev_dev_get_rsp *dst; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == NETDEV_A_DEV_IFINDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.ifindex = 1; - dst->ifindex = mnl_attr_get_u32(attr); - } else if (type == NETDEV_A_DEV_XDP_FEATURES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.xdp_features = 1; - dst->xdp_features = mnl_attr_get_u64(attr); - } else if (type == NETDEV_A_DEV_XDP_ZC_MAX_SEGS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.xdp_zc_max_segs = 1; - dst->xdp_zc_max_segs = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct netdev_dev_get_rsp * -netdev_dev_get(struct ynl_sock *ys, struct netdev_dev_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct netdev_dev_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, NETDEV_CMD_DEV_GET, 1); - ys->req_policy = &netdev_dev_nest; - yrs.yarg.rsp_policy = &netdev_dev_nest; - - if (req->_present.ifindex) - mnl_attr_put_u32(nlh, NETDEV_A_DEV_IFINDEX, req->ifindex); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = netdev_dev_get_rsp_parse; - yrs.rsp_cmd = NETDEV_CMD_DEV_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - netdev_dev_get_rsp_free(rsp); - return NULL; -} - -/* NETDEV_CMD_DEV_GET - dump */ -void netdev_dev_get_list_free(struct netdev_dev_get_list *rsp) -{ - struct netdev_dev_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp); - } -} - -struct netdev_dev_get_list *netdev_dev_get_dump(struct ynl_sock *ys) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct netdev_dev_get_list); - yds.cb = netdev_dev_get_rsp_parse; - yds.rsp_cmd = NETDEV_CMD_DEV_GET; - yds.rsp_policy = &netdev_dev_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, NETDEV_CMD_DEV_GET, 1); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - netdev_dev_get_list_free(yds.first); - return NULL; -} - -/* NETDEV_CMD_DEV_GET - notify */ -void netdev_dev_get_ntf_free(struct netdev_dev_get_ntf *rsp) -{ - free(rsp); -} - -static const struct ynl_ntf_info netdev_ntf_info[] = { - [NETDEV_CMD_DEV_ADD_NTF] = { - .alloc_sz = sizeof(struct netdev_dev_get_ntf), - .cb = netdev_dev_get_rsp_parse, - .policy = &netdev_dev_nest, - .free = (void *)netdev_dev_get_ntf_free, - }, - [NETDEV_CMD_DEV_DEL_NTF] = { - .alloc_sz = sizeof(struct netdev_dev_get_ntf), - .cb = netdev_dev_get_rsp_parse, - .policy = &netdev_dev_nest, - .free = (void *)netdev_dev_get_ntf_free, - }, - [NETDEV_CMD_DEV_CHANGE_NTF] = { - .alloc_sz = sizeof(struct netdev_dev_get_ntf), - .cb = netdev_dev_get_rsp_parse, - .policy = &netdev_dev_nest, - .free = (void *)netdev_dev_get_ntf_free, - }, -}; - -const struct ynl_family ynl_netdev_family = { - .name = "netdev", - .ntf_info = netdev_ntf_info, - .ntf_info_size = MNL_ARRAY_SIZE(netdev_ntf_info), -}; diff --git a/tools/net/ynl/generated/netdev-user.h b/tools/net/ynl/generated/netdev-user.h deleted file mode 100644 index 0952d3261f4d..000000000000 --- a/tools/net/ynl/generated/netdev-user.h +++ /dev/null @@ -1,87 +0,0 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ -/* Do not edit directly, auto-generated from: */ -/* Documentation/netlink/specs/netdev.yaml */ -/* YNL-GEN user header */ - -#ifndef _LINUX_NETDEV_GEN_H -#define _LINUX_NETDEV_GEN_H - -#include <stdlib.h> -#include <string.h> -#include <linux/types.h> -#include <linux/netdev.h> - -struct ynl_sock; - -extern const struct ynl_family ynl_netdev_family; - -/* Enums */ -const char *netdev_op_str(int op); -const char *netdev_xdp_act_str(enum netdev_xdp_act value); - -/* Common nested types */ -/* ============== NETDEV_CMD_DEV_GET ============== */ -/* NETDEV_CMD_DEV_GET - do */ -struct netdev_dev_get_req { - struct { - __u32 ifindex:1; - } _present; - - __u32 ifindex; -}; - -static inline struct netdev_dev_get_req *netdev_dev_get_req_alloc(void) -{ - return calloc(1, sizeof(struct netdev_dev_get_req)); -} -void netdev_dev_get_req_free(struct netdev_dev_get_req *req); - -static inline void -netdev_dev_get_req_set_ifindex(struct netdev_dev_get_req *req, __u32 ifindex) -{ - req->_present.ifindex = 1; - req->ifindex = ifindex; -} - -struct netdev_dev_get_rsp { - struct { - __u32 ifindex:1; - __u32 xdp_features:1; - __u32 xdp_zc_max_segs:1; - } _present; - - __u32 ifindex; - __u64 xdp_features; - __u32 xdp_zc_max_segs; -}; - -void netdev_dev_get_rsp_free(struct netdev_dev_get_rsp *rsp); - -/* - * Get / dump information about a netdev. - */ -struct netdev_dev_get_rsp * -netdev_dev_get(struct ynl_sock *ys, struct netdev_dev_get_req *req); - -/* NETDEV_CMD_DEV_GET - dump */ -struct netdev_dev_get_list { - struct netdev_dev_get_list *next; - struct netdev_dev_get_rsp obj __attribute__ ((aligned (8))); -}; - -void netdev_dev_get_list_free(struct netdev_dev_get_list *rsp); - -struct netdev_dev_get_list *netdev_dev_get_dump(struct ynl_sock *ys); - -/* NETDEV_CMD_DEV_GET - notify */ -struct netdev_dev_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct netdev_dev_get_ntf *ntf); - struct netdev_dev_get_rsp obj __attribute__ ((aligned (8))); -}; - -void netdev_dev_get_ntf_free(struct netdev_dev_get_ntf *rsp); - -#endif /* _LINUX_NETDEV_GEN_H */ diff --git a/tools/net/ynl/lib/.gitignore b/tools/net/ynl/lib/.gitignore index c18dd8d83cee..a4383358ec72 100644 --- a/tools/net/ynl/lib/.gitignore +++ b/tools/net/ynl/lib/.gitignore @@ -1 +1 @@ -__pycache__/ +*.d diff --git a/tools/net/ynl/lib/Makefile b/tools/net/ynl/lib/Makefile index d2e50fd0a52d..4b2b98704ff9 100644 --- a/tools/net/ynl/lib/Makefile +++ b/tools/net/ynl/lib/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 CC=gcc -CFLAGS=-std=gnu11 -O2 -W -Wall -Wextra -Wno-unused-parameter -Wshadow +CFLAGS += -std=gnu11 -O2 -W -Wall -Wextra -Wno-unused-parameter -Wshadow ifeq ("$(DEBUG)","1") CFLAGS += -g -fsanitize=address -fsanitize=leak -static-libasan endif @@ -14,15 +14,17 @@ include $(wildcard *.d) all: ynl.a ynl.a: $(OBJS) - ar rcs $@ $(OBJS) + @echo -e "\tAR $@" + @ar rcs $@ $(OBJS) + clean: rm -f *.o *.d *~ -hardclean: clean +distclean: clean rm -f *.a %.o: %.c $(COMPILE.c) -MMD -c -o $@ $< -.PHONY: all clean +.PHONY: all clean distclean .DEFAULT_GOAL=all diff --git a/tools/net/ynl/lib/__init__.py b/tools/net/ynl/lib/__init__.py deleted file mode 100644 index f7eaa07783e7..000000000000 --- a/tools/net/ynl/lib/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause - -from .nlspec import SpecAttr, SpecAttrSet, SpecEnumEntry, SpecEnumSet, \ - SpecFamily, SpecOperation -from .ynl import YnlFamily, Netlink - -__all__ = ["SpecAttr", "SpecAttrSet", "SpecEnumEntry", "SpecEnumSet", - "SpecFamily", "SpecOperation", "YnlFamily", "Netlink"] diff --git a/tools/net/ynl/lib/ynl-priv.h b/tools/net/ynl/lib/ynl-priv.h new file mode 100644 index 000000000000..ced7dce44efb --- /dev/null +++ b/tools/net/ynl/lib/ynl-priv.h @@ -0,0 +1,478 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +#ifndef __YNL_C_PRIV_H +#define __YNL_C_PRIV_H 1 + +#include <stdbool.h> +#include <stddef.h> +#include <linux/types.h> + +struct ynl_parse_arg; + +/* + * YNL internals / low level stuff + */ + +enum ynl_policy_type { + YNL_PT_REJECT = 1, + YNL_PT_IGNORE, + YNL_PT_NEST, + YNL_PT_FLAG, + YNL_PT_BINARY, + YNL_PT_U8, + YNL_PT_U16, + YNL_PT_U32, + YNL_PT_U64, + YNL_PT_UINT, + YNL_PT_NUL_STR, + YNL_PT_BITFIELD32, + YNL_PT_SUBMSG, +}; + +enum ynl_parse_result { + YNL_PARSE_CB_ERROR = -1, + YNL_PARSE_CB_STOP = 0, + YNL_PARSE_CB_OK = 1, +}; + +#define YNL_SOCKET_BUFFER_SIZE (1 << 17) + +#define YNL_ARRAY_SIZE(array) (sizeof(array) ? \ + sizeof(array) / sizeof(array[0]) : 0) + +typedef int (*ynl_parse_cb_t)(const struct nlmsghdr *nlh, + struct ynl_parse_arg *yarg); + +struct ynl_policy_attr { + enum ynl_policy_type type:8; + __u8 is_submsg:1; + __u8 is_selector:1; + __u16 selector_type; + unsigned int len; + const char *name; + const struct ynl_policy_nest *nest; +}; + +struct ynl_policy_nest { + unsigned int max_attr; + const struct ynl_policy_attr *table; +}; + +struct ynl_parse_arg { + struct ynl_sock *ys; + const struct ynl_policy_nest *rsp_policy; + void *data; +}; + +struct ynl_dump_list_type { + struct ynl_dump_list_type *next; + unsigned char data[] __attribute__((aligned(8))); +}; +extern struct ynl_dump_list_type *YNL_LIST_END; + +static inline bool ynl_dump_obj_is_last(void *obj) +{ + unsigned long uptr = (unsigned long)obj; + + uptr -= offsetof(struct ynl_dump_list_type, data); + return uptr == (unsigned long)YNL_LIST_END; +} + +static inline void *ynl_dump_obj_next(void *obj) +{ + unsigned long uptr = (unsigned long)obj; + struct ynl_dump_list_type *list; + + uptr -= offsetof(struct ynl_dump_list_type, data); + list = (struct ynl_dump_list_type *)uptr; + uptr = (unsigned long)list->next; + uptr += offsetof(struct ynl_dump_list_type, data); + + return (void *)uptr; +} + +struct ynl_ntf_base_type { + __u16 family; + __u8 cmd; + struct ynl_ntf_base_type *next; + void (*free)(struct ynl_ntf_base_type *ntf); + unsigned char data[] __attribute__((aligned(8))); +}; + +struct nlmsghdr *ynl_msg_start_req(struct ynl_sock *ys, __u32 id, __u16 flags); +struct nlmsghdr *ynl_msg_start_dump(struct ynl_sock *ys, __u32 id); + +struct nlmsghdr * +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_submsg_failed(struct ynl_parse_arg *yarg, const char *field_name, + const char *sel_name); + +/* YNL specific helpers used by the auto-generated code */ + +struct ynl_req_state { + struct ynl_parse_arg yarg; + ynl_parse_cb_t cb; + __u32 rsp_cmd; +}; + +struct ynl_dump_state { + struct ynl_parse_arg yarg; + void *first; + struct ynl_dump_list_type *last; + size_t alloc_sz; + ynl_parse_cb_t cb; + __u32 rsp_cmd; +}; + +struct ynl_ntf_info { + const struct ynl_policy_nest *policy; + ynl_parse_cb_t cb; + size_t alloc_sz; + void (*free)(struct ynl_ntf_base_type *ntf); +}; + +int ynl_exec(struct ynl_sock *ys, struct nlmsghdr *req_nlh, + struct ynl_req_state *yrs); +int ynl_exec_dump(struct ynl_sock *ys, struct nlmsghdr *req_nlh, + struct ynl_dump_state *yds); + +void ynl_error_unknown_notification(struct ynl_sock *ys, __u8 cmd); +int ynl_error_parse(struct ynl_parse_arg *yarg, const char *msg); + +/* Netlink message handling helpers */ + +#define YNL_MSG_OVERFLOW 1 + +static inline struct nlmsghdr *ynl_nlmsg_put_header(void *buf) +{ + struct nlmsghdr *nlh = (struct nlmsghdr *)buf; + + memset(nlh, 0, sizeof(*nlh)); + nlh->nlmsg_len = NLMSG_HDRLEN; + + return nlh; +} + +static inline unsigned int ynl_nlmsg_data_len(const struct nlmsghdr *nlh) +{ + return nlh->nlmsg_len - NLMSG_HDRLEN; +} + +static inline void *ynl_nlmsg_data(const struct nlmsghdr *nlh) +{ + return (unsigned char *)nlh + NLMSG_HDRLEN; +} + +static inline void * +ynl_nlmsg_data_offset(const struct nlmsghdr *nlh, unsigned int offset) +{ + return (unsigned char *)nlh + NLMSG_HDRLEN + offset; +} + +static inline void *ynl_nlmsg_end_addr(const struct nlmsghdr *nlh) +{ + return (char *)nlh + nlh->nlmsg_len; +} + +static inline void * +ynl_nlmsg_put_extra_header(struct nlmsghdr *nlh, unsigned int size) +{ + void *tail = ynl_nlmsg_end_addr(nlh); + + nlh->nlmsg_len += NLMSG_ALIGN(size); + return tail; +} + +/* Netlink attribute helpers */ + +static inline unsigned int ynl_attr_type(const struct nlattr *attr) +{ + return attr->nla_type & NLA_TYPE_MASK; +} + +static inline unsigned int ynl_attr_data_len(const struct nlattr *attr) +{ + return attr->nla_len - NLA_HDRLEN; +} + +static inline void *ynl_attr_data(const struct nlattr *attr) +{ + return (unsigned char *)attr + NLA_HDRLEN; +} + +static inline void *ynl_attr_data_end(const struct nlattr *attr) +{ + return (char *)ynl_attr_data(attr) + ynl_attr_data_len(attr); +} + +#define ynl_attr_for_each(attr, nlh, fixed_hdr_sz) \ + for ((attr) = ynl_attr_first(nlh, (nlh)->nlmsg_len, \ + NLMSG_HDRLEN + fixed_hdr_sz); attr; \ + (attr) = ynl_attr_next(ynl_nlmsg_end_addr(nlh), attr)) + +#define ynl_attr_for_each_nested_off(attr, outer, offset) \ + for ((attr) = ynl_attr_first(outer, outer->nla_len, \ + sizeof(struct nlattr) + offset); \ + attr; \ + (attr) = ynl_attr_next(ynl_attr_data_end(outer), attr)) + +#define ynl_attr_for_each_nested(attr, outer) \ + ynl_attr_for_each_nested_off(attr, outer, 0) + +#define ynl_attr_for_each_payload(start, len, attr) \ + for ((attr) = ynl_attr_first(start, len, 0); attr; \ + (attr) = ynl_attr_next(start + len, attr)) + +static inline struct nlattr * +ynl_attr_if_good(const void *end, struct nlattr *attr) +{ + if (attr + 1 > (const struct nlattr *)end) + return NULL; + if (ynl_attr_data_end(attr) > end) + return NULL; + return attr; +} + +static inline struct nlattr * +ynl_attr_next(const void *end, const struct nlattr *prev) +{ + struct nlattr *attr; + + attr = (struct nlattr *)((char *)prev + NLA_ALIGN(prev->nla_len)); + return ynl_attr_if_good(end, attr); +} + +static inline struct nlattr * +ynl_attr_first(const void *start, size_t len, size_t skip) +{ + struct nlattr *attr; + + attr = (struct nlattr *)((char *)start + NLMSG_ALIGN(skip)); + return ynl_attr_if_good((char *)start + len, attr); +} + +static inline bool +__ynl_attr_put_overflow(struct nlmsghdr *nlh, size_t size) +{ + bool o; + + /* ynl_msg_start() stashed buffer length in nlmsg_pid. */ + o = nlh->nlmsg_len + NLA_HDRLEN + NLMSG_ALIGN(size) > nlh->nlmsg_pid; + if (o) + /* YNL_MSG_OVERFLOW is < NLMSG_HDRLEN, all subsequent checks + * are guaranteed to fail. + */ + nlh->nlmsg_pid = YNL_MSG_OVERFLOW; + return o; +} + +static inline struct nlattr * +ynl_attr_nest_start(struct nlmsghdr *nlh, unsigned int attr_type) +{ + struct nlattr *attr; + + if (__ynl_attr_put_overflow(nlh, 0)) + return (struct nlattr *)ynl_nlmsg_end_addr(nlh) - 1; + + attr = (struct nlattr *)ynl_nlmsg_end_addr(nlh); + attr->nla_type = attr_type | NLA_F_NESTED; + nlh->nlmsg_len += NLA_HDRLEN; + + return attr; +} + +static inline void +ynl_attr_nest_end(struct nlmsghdr *nlh, struct nlattr *attr) +{ + attr->nla_len = (char *)ynl_nlmsg_end_addr(nlh) - (char *)attr; +} + +static inline void +ynl_attr_put(struct nlmsghdr *nlh, unsigned int attr_type, + const void *value, size_t size) +{ + struct nlattr *attr; + + if (__ynl_attr_put_overflow(nlh, size)) + return; + + attr = (struct nlattr *)ynl_nlmsg_end_addr(nlh); + attr->nla_type = attr_type; + attr->nla_len = NLA_HDRLEN + size; + + memcpy(ynl_attr_data(attr), value, size); + + nlh->nlmsg_len += NLMSG_ALIGN(attr->nla_len); +} + +static inline void +ynl_attr_put_str(struct nlmsghdr *nlh, unsigned int attr_type, const char *str) +{ + struct nlattr *attr; + size_t len; + + len = strlen(str) + 1; + if (__ynl_attr_put_overflow(nlh, len)) + return; + + attr = (struct nlattr *)ynl_nlmsg_end_addr(nlh); + attr->nla_type = attr_type; + + strcpy((char *)ynl_attr_data(attr), str); + attr->nla_len = NLA_HDRLEN + len; + + nlh->nlmsg_len += NLMSG_ALIGN(attr->nla_len); +} + +static inline const char *ynl_attr_get_str(const struct nlattr *attr) +{ + return (const char *)ynl_attr_data(attr); +} + +static inline __s8 ynl_attr_get_s8(const struct nlattr *attr) +{ + return *(__s8 *)ynl_attr_data(attr); +} + +static inline __s16 ynl_attr_get_s16(const struct nlattr *attr) +{ + return *(__s16 *)ynl_attr_data(attr); +} + +static inline __s32 ynl_attr_get_s32(const struct nlattr *attr) +{ + return *(__s32 *)ynl_attr_data(attr); +} + +static inline __s64 ynl_attr_get_s64(const struct nlattr *attr) +{ + __s64 tmp; + + memcpy(&tmp, (unsigned char *)(attr + 1), sizeof(tmp)); + return tmp; +} + +static inline __u8 ynl_attr_get_u8(const struct nlattr *attr) +{ + return *(__u8 *)ynl_attr_data(attr); +} + +static inline __u16 ynl_attr_get_u16(const struct nlattr *attr) +{ + return *(__u16 *)ynl_attr_data(attr); +} + +static inline __u32 ynl_attr_get_u32(const struct nlattr *attr) +{ + return *(__u32 *)ynl_attr_data(attr); +} + +static inline __u64 ynl_attr_get_u64(const struct nlattr *attr) +{ + __u64 tmp; + + memcpy(&tmp, (unsigned char *)(attr + 1), sizeof(tmp)); + return tmp; +} + +static inline void +ynl_attr_put_s8(struct nlmsghdr *nlh, unsigned int attr_type, __s8 value) +{ + ynl_attr_put(nlh, attr_type, &value, sizeof(value)); +} + +static inline void +ynl_attr_put_s16(struct nlmsghdr *nlh, unsigned int attr_type, __s16 value) +{ + ynl_attr_put(nlh, attr_type, &value, sizeof(value)); +} + +static inline void +ynl_attr_put_s32(struct nlmsghdr *nlh, unsigned int attr_type, __s32 value) +{ + ynl_attr_put(nlh, attr_type, &value, sizeof(value)); +} + +static inline void +ynl_attr_put_s64(struct nlmsghdr *nlh, unsigned int attr_type, __s64 value) +{ + ynl_attr_put(nlh, attr_type, &value, sizeof(value)); +} + +static inline void +ynl_attr_put_u8(struct nlmsghdr *nlh, unsigned int attr_type, __u8 value) +{ + ynl_attr_put(nlh, attr_type, &value, sizeof(value)); +} + +static inline void +ynl_attr_put_u16(struct nlmsghdr *nlh, unsigned int attr_type, __u16 value) +{ + ynl_attr_put(nlh, attr_type, &value, sizeof(value)); +} + +static inline void +ynl_attr_put_u32(struct nlmsghdr *nlh, unsigned int attr_type, __u32 value) +{ + ynl_attr_put(nlh, attr_type, &value, sizeof(value)); +} + +static inline void +ynl_attr_put_u64(struct nlmsghdr *nlh, unsigned int attr_type, __u64 value) +{ + ynl_attr_put(nlh, attr_type, &value, sizeof(value)); +} + +static inline __u64 ynl_attr_get_uint(const struct nlattr *attr) +{ + switch (ynl_attr_data_len(attr)) { + case 4: + return ynl_attr_get_u32(attr); + case 8: + return ynl_attr_get_u64(attr); + default: + return 0; + } +} + +static inline __s64 ynl_attr_get_sint(const struct nlattr *attr) +{ + switch (ynl_attr_data_len(attr)) { + case 4: + return ynl_attr_get_s32(attr); + case 8: + return ynl_attr_get_s64(attr); + default: + return 0; + } +} + +static inline void +ynl_attr_put_uint(struct nlmsghdr *nlh, __u16 type, __u64 data) +{ + if ((__u32)data == (__u64)data) + ynl_attr_put_u32(nlh, type, data); + else + ynl_attr_put_u64(nlh, type, data); +} + +static inline void +ynl_attr_put_sint(struct nlmsghdr *nlh, __u16 type, __s64 data) +{ + if ((__s32)data == (__s64)data) + ynl_attr_put_s32(nlh, type, 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 diff --git a/tools/net/ynl/lib/ynl.c b/tools/net/ynl/lib/ynl.c index 514e0d69e731..2bcd781111d7 100644 --- a/tools/net/ynl/lib/ynl.c +++ b/tools/net/ynl/lib/ynl.c @@ -3,10 +3,11 @@ #include <poll.h> #include <string.h> #include <stdlib.h> +#include <stdio.h> +#include <unistd.h> #include <linux/types.h> - -#include <libmnl/libmnl.h> #include <linux/genetlink.h> +#include <sys/socket.h> #include "ynl.h" @@ -44,8 +45,39 @@ #define perr(_ys, _msg) __yerr(&(_ys)->err, errno, _msg) /* -- Netlink boiler plate */ +static bool +ynl_err_walk_is_sel(const struct ynl_policy_nest *policy, + const struct nlattr *attr) +{ + unsigned int type = ynl_attr_type(attr); + + return policy && type <= policy->max_attr && + policy->table[type].is_selector; +} + +static const struct ynl_policy_nest * +ynl_err_walk_sel_policy(const struct ynl_policy_attr *policy_attr, + const struct nlattr *selector) +{ + const struct ynl_policy_nest *policy = policy_attr->nest; + const char *sel; + unsigned int i; + + if (!policy_attr->is_submsg) + return policy; + + sel = ynl_attr_get_str(selector); + for (i = 0; i <= policy->max_attr; i++) { + if (!strcmp(sel, policy->table[i].name)) + return policy->table[i].nest; + } + + return NULL; +} + static int -ynl_err_walk_report_one(struct ynl_policy_nest *policy, unsigned int type, +ynl_err_walk_report_one(const struct ynl_policy_nest *policy, + const struct nlattr *selector, unsigned int type, char *str, int str_sz, int *n) { if (!policy) { @@ -66,17 +98,44 @@ ynl_err_walk_report_one(struct ynl_policy_nest *policy, unsigned int type, return 1; } - if (*n < str_sz) - *n += snprintf(str, str_sz - *n, - ".%s", policy->table[type].name); + if (*n < str_sz) { + int sz; + + sz = snprintf(str, str_sz - *n, + ".%s", policy->table[type].name); + *n += sz; + str += sz; + } + + if (policy->table[type].is_submsg) { + if (!selector) { + if (*n < str_sz) + *n += snprintf(str, str_sz, "(!selector)"); + return 1; + } + + if (ynl_attr_type(selector) != + policy->table[type].selector_type) { + if (*n < str_sz) + *n += snprintf(str, str_sz, "(!=selector)"); + return 1; + } + + if (*n < str_sz) + *n += snprintf(str, str_sz - *n, "(%s)", + ynl_attr_get_str(selector)); + } + return 0; } static int ynl_err_walk(struct ynl_sock *ys, void *start, void *end, unsigned int off, - struct ynl_policy_nest *policy, char *str, int str_sz, - struct ynl_policy_nest **nest_pol) + const struct ynl_policy_nest *policy, char *str, int str_sz, + const struct ynl_policy_nest **nest_pol) { + const struct ynl_policy_nest *next_pol; + const struct nlattr *selector = NULL; unsigned int astart_off, aend_off; const struct nlattr *attr; unsigned int data_len; @@ -92,9 +151,13 @@ ynl_err_walk(struct ynl_sock *ys, void *start, void *end, unsigned int off, data_len = end - start; - mnl_attr_for_each_payload(start, data_len) { + ynl_attr_for_each_payload(start, data_len, attr) { astart_off = (char *)attr - (char *)start; - aend_off = astart_off + mnl_attr_get_payload_len(attr); + aend_off = (char *)ynl_attr_data_end(attr) - (char *)start; + + if (ynl_err_walk_is_sel(policy, attr)) + selector = attr; + if (aend_off <= off) continue; @@ -106,28 +169,32 @@ ynl_err_walk(struct ynl_sock *ys, void *start, void *end, unsigned int off, off -= astart_off; - type = mnl_attr_get_type(attr); + type = ynl_attr_type(attr); + + if (ynl_err_walk_report_one(policy, selector, type, str, str_sz, &n)) + return n; - if (ynl_err_walk_report_one(policy, type, str, str_sz, &n)) + next_pol = ynl_err_walk_sel_policy(&policy->table[type], selector); + if (!next_pol) return n; if (!off) { if (nest_pol) - *nest_pol = policy->table[type].nest; + *nest_pol = next_pol; return n; } - if (!policy->table[type].nest) { + if (!next_pol) { if (n < str_sz) n += snprintf(str, str_sz, "!nest"); return n; } off -= sizeof(struct nlattr); - start = mnl_attr_get_payload(attr); - end = start + mnl_attr_get_payload_len(attr); + start = ynl_attr_data(attr); + end = start + ynl_attr_data_len(attr); - return n + ynl_err_walk(ys, start, end, off, policy->table[type].nest, + return n + ynl_err_walk(ys, start, end, off, next_pol, &str[n], str_sz - n, nest_pol); } @@ -145,14 +212,16 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh, const struct nlattr *attr; const char *str = NULL; - if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS)) - return MNL_CB_OK; + if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS)) { + yerr_msg(ys, "%s", strerror(ys->err.code)); + return YNL_PARSE_CB_OK; + } - mnl_attr_for_each(attr, nlh, hlen) { + ynl_attr_for_each(attr, nlh, hlen) { unsigned int len, type; - len = mnl_attr_get_payload_len(attr); - type = mnl_attr_get_type(attr); + len = ynl_attr_data_len(attr); + type = ynl_attr_type(attr); if (type > NLMSGERR_ATTR_MAX) continue; @@ -164,12 +233,12 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh, case NLMSGERR_ATTR_MISS_TYPE: case NLMSGERR_ATTR_MISS_NEST: if (len != sizeof(__u32)) - return MNL_CB_ERROR; + return YNL_PARSE_CB_ERROR; break; case NLMSGERR_ATTR_MSG: - str = mnl_attr_get_payload(attr); + str = ynl_attr_get_str(attr); if (str[len - 1]) - return MNL_CB_ERROR; + return YNL_PARSE_CB_ERROR; break; default: break; @@ -183,18 +252,17 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh, unsigned int n, off; void *start, *end; - ys->err.attr_offs = mnl_attr_get_u32(tb[NLMSGERR_ATTR_OFFS]); + ys->err.attr_offs = ynl_attr_get_u32(tb[NLMSGERR_ATTR_OFFS]); n = snprintf(bad_attr, sizeof(bad_attr), "%sbad attribute: ", str ? " (" : ""); - start = mnl_nlmsg_get_payload_offset(ys->nlh, - sizeof(struct genlmsghdr)); - end = mnl_nlmsg_get_payload_tail(ys->nlh); + start = ynl_nlmsg_data_offset(ys->nlh, ys->req_hdr_len); + end = ynl_nlmsg_end_addr(ys->nlh); off = ys->err.attr_offs; off -= sizeof(struct nlmsghdr); - off -= sizeof(struct genlmsghdr); + off -= ys->req_hdr_len; n += ynl_err_walk(ys, start, end, off, ys->req_policy, &bad_attr[n], sizeof(bad_attr) - n, NULL); @@ -204,25 +272,24 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh, bad_attr[n] = '\0'; } if (tb[NLMSGERR_ATTR_MISS_TYPE]) { - struct ynl_policy_nest *nest_pol = NULL; + const struct ynl_policy_nest *nest_pol = NULL; unsigned int n, off, type; void *start, *end; int n2; - type = mnl_attr_get_u32(tb[NLMSGERR_ATTR_MISS_TYPE]); + type = ynl_attr_get_u32(tb[NLMSGERR_ATTR_MISS_TYPE]); n = snprintf(miss_attr, sizeof(miss_attr), "%smissing attribute: ", bad_attr[0] ? ", " : (str ? " (" : "")); - start = mnl_nlmsg_get_payload_offset(ys->nlh, - sizeof(struct genlmsghdr)); - end = mnl_nlmsg_get_payload_tail(ys->nlh); + start = ynl_nlmsg_data_offset(ys->nlh, ys->req_hdr_len); + end = ynl_nlmsg_end_addr(ys->nlh); nest_pol = ys->req_policy; if (tb[NLMSGERR_ATTR_MISS_NEST]) { - off = mnl_attr_get_u32(tb[NLMSGERR_ATTR_MISS_NEST]); + off = ynl_attr_get_u32(tb[NLMSGERR_ATTR_MISS_NEST]); off -= sizeof(struct nlmsghdr); - off -= sizeof(struct genlmsghdr); + off -= ys->req_hdr_len; n += ynl_err_walk(ys, start, end, off, ys->req_policy, &miss_attr[n], sizeof(miss_attr) - n, @@ -230,7 +297,7 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh, } n2 = 0; - ynl_err_walk_report_one(nest_pol, type, &miss_attr[n], + ynl_err_walk_report_one(nest_pol, NULL, type, &miss_attr[n], sizeof(miss_attr) - n, &n2); n += n2; @@ -249,14 +316,16 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh, yerr_msg(ys, "Kernel %s: %s%s", ys->err.code ? "error" : "warning", bad_attr, miss_attr); + else + yerr_msg(ys, "%s", strerror(ys->err.code)); - return MNL_CB_OK; + return YNL_PARSE_CB_OK; } -static int ynl_cb_error(const struct nlmsghdr *nlh, void *data) +static int +ynl_cb_error(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg) { - const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh); - struct ynl_parse_arg *yarg = data; + const struct nlmsgerr *err = ynl_nlmsg_data(nlh); unsigned int hlen; int code; @@ -266,16 +335,15 @@ static int ynl_cb_error(const struct nlmsghdr *nlh, void *data) hlen = sizeof(*err); if (!(nlh->nlmsg_flags & NLM_F_CAPPED)) - hlen += mnl_nlmsg_get_payload_len(&err->msg); + hlen += ynl_nlmsg_data_len(&err->msg); ynl_ext_ack_check(yarg->ys, nlh, hlen); - return code ? MNL_CB_ERROR : MNL_CB_STOP; + return code ? YNL_PARSE_CB_ERROR : YNL_PARSE_CB_STOP; } -static int ynl_cb_done(const struct nlmsghdr *nlh, void *data) +static int ynl_cb_done(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg) { - struct ynl_parse_arg *yarg = data; int err; err = *(int *)NLMSG_DATA(nlh); @@ -285,34 +353,22 @@ static int ynl_cb_done(const struct nlmsghdr *nlh, void *data) ynl_ext_ack_check(yarg->ys, nlh, sizeof(int)); - return MNL_CB_ERROR; + return YNL_PARSE_CB_ERROR; } - return MNL_CB_STOP; + return YNL_PARSE_CB_STOP; } -static int ynl_cb_noop(const struct nlmsghdr *nlh, void *data) -{ - return MNL_CB_OK; -} - -mnl_cb_t ynl_cb_array[NLMSG_MIN_TYPE] = { - [NLMSG_NOOP] = ynl_cb_noop, - [NLMSG_ERROR] = ynl_cb_error, - [NLMSG_DONE] = ynl_cb_done, - [NLMSG_OVERRUN] = ynl_cb_noop, -}; - /* 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) { - struct ynl_policy_attr *policy; - unsigned int type, len; + const struct ynl_policy_attr *policy; unsigned char *data; + unsigned int len; - data = mnl_attr_get_payload(attr); - len = mnl_attr_get_payload_len(attr); - type = mnl_attr_get_type(attr); + data = ynl_attr_data(attr); + len = ynl_attr_data_len(attr); if (type > yarg->rsp_policy->max_attr) { yerr(yarg->ys, YNL_ERROR_INTERNAL, "Internal error, validating unknown attribute"); @@ -352,6 +408,12 @@ int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr) yerr(yarg->ys, YNL_ERROR_ATTR_INVALID, "Invalid attribute (u64 %s)", policy->name); return -1; + case YNL_PT_UINT: + if (len == sizeof(__u32) || len == sizeof(__u64)) + break; + yerr(yarg->ys, YNL_ERROR_ATTR_INVALID, + "Invalid attribute (uint %s)", policy->name); + return -1; case YNL_PT_FLAG: /* Let flags grow into real attrs, why not.. */ break; @@ -368,11 +430,17 @@ int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr) "Invalid attribute (binary %s)", policy->name); return -1; case YNL_PT_NUL_STR: - if ((!policy->len || len <= policy->len) && !data[len - 1]) + if (len && (!policy->len || len <= policy->len) && !data[len - 1]) break; 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); @@ -382,6 +450,15 @@ int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr) return 0; } +int ynl_submsg_failed(struct ynl_parse_arg *yarg, const char *field_name, + const char *sel_name) +{ + yerr(yarg->ys, YNL_ERROR_SUBMSG_KEY, + "Parsing error: Sub-message key not set (msg %s, key %s)", + field_name, sel_name); + return YNL_PARSE_CB_ERROR; +} + /* Generic code */ static void ynl_err_reset(struct ynl_sock *ys) @@ -397,14 +474,38 @@ struct nlmsghdr *ynl_msg_start(struct ynl_sock *ys, __u32 id, __u16 flags) ynl_err_reset(ys); - nlh = ys->nlh = mnl_nlmsg_put_header(ys->tx_buf); + nlh = ys->nlh = ynl_nlmsg_put_header(ys->tx_buf); nlh->nlmsg_type = id; nlh->nlmsg_flags = flags; nlh->nlmsg_seq = ++ys->seq; + /* This is a local YNL hack for length checking, we put the buffer + * length in nlmsg_pid, since messages sent to the kernel always use + * PID 0. Message needs to be terminated with ynl_msg_end(). + */ + nlh->nlmsg_pid = YNL_SOCKET_BUFFER_SIZE; + return nlh; } +static int ynl_msg_end(struct ynl_sock *ys, struct nlmsghdr *nlh) +{ + /* We stash buffer length in nlmsg_pid. */ + if (nlh->nlmsg_pid == 0) { + yerr(ys, YNL_ERROR_INPUT_INVALID, + "Unknown input buffer length"); + return -EINVAL; + } + if (nlh->nlmsg_pid == YNL_MSG_OVERFLOW) { + yerr(ys, YNL_ERROR_INPUT_TOO_BIG, + "Constructed message longer than internal buffer"); + return -EMSGSIZE; + } + + nlh->nlmsg_pid = 0; + return 0; +} + struct nlmsghdr * ynl_gemsg_start(struct ynl_sock *ys, __u32 id, __u16 flags, __u8 cmd, __u8 version) @@ -419,20 +520,20 @@ ynl_gemsg_start(struct ynl_sock *ys, __u32 id, __u16 flags, gehdr.cmd = cmd; gehdr.version = version; - data = mnl_nlmsg_put_extra_header(nlh, sizeof(gehdr)); + data = ynl_nlmsg_put_extra_header(nlh, sizeof(gehdr)); memcpy(data, &gehdr, sizeof(gehdr)); return nlh; } -void ynl_msg_start_req(struct ynl_sock *ys, __u32 id) +struct nlmsghdr *ynl_msg_start_req(struct ynl_sock *ys, __u32 id, __u16 flags) { - ynl_msg_start(ys, id, NLM_F_REQUEST | NLM_F_ACK); + return ynl_msg_start(ys, id, NLM_F_REQUEST | NLM_F_ACK | flags); } -void ynl_msg_start_dump(struct ynl_sock *ys, __u32 id) +struct nlmsghdr *ynl_msg_start_dump(struct ynl_sock *ys, __u32 id) { - ynl_msg_start(ys, id, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP); + return ynl_msg_start(ys, id, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP); } struct nlmsghdr * @@ -448,31 +549,85 @@ ynl_gemsg_start_dump(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version) cmd, version); } -int ynl_recv_ack(struct ynl_sock *ys, int ret) +static int ynl_cb_null(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg) { - if (!ret) { - yerr(ys, YNL_ERROR_EXPECT_ACK, - "Expecting an ACK but nothing received"); - return -1; + yerr(yarg->ys, YNL_ERROR_UNEXPECT_MSG, + "Received a message when none were expected"); + + return YNL_PARSE_CB_ERROR; +} + +static int +__ynl_sock_read_msgs(struct ynl_parse_arg *yarg, ynl_parse_cb_t cb, int flags) +{ + struct ynl_sock *ys = yarg->ys; + const struct nlmsghdr *nlh; + ssize_t len, rem; + int ret; + + len = recv(ys->socket, ys->rx_buf, YNL_SOCKET_BUFFER_SIZE, flags); + if (len < 0) { + if (flags & MSG_DONTWAIT && errno == EAGAIN) + return YNL_PARSE_CB_STOP; + return len; } - ret = mnl_socket_recvfrom(ys->sock, ys->rx_buf, MNL_SOCKET_BUFFER_SIZE); - if (ret < 0) { - perr(ys, "Socket receive failed"); - return ret; + ret = YNL_PARSE_CB_STOP; + for (rem = len; rem > 0; NLMSG_NEXT(nlh, rem)) { + nlh = (struct nlmsghdr *)&ys->rx_buf[len - rem]; + if (!NLMSG_OK(nlh, rem)) { + yerr(yarg->ys, YNL_ERROR_INV_RESP, + "Invalid message or trailing data in the response."); + return YNL_PARSE_CB_ERROR; + } + + if (nlh->nlmsg_flags & NLM_F_DUMP_INTR) { + /* TODO: handle this better */ + yerr(yarg->ys, YNL_ERROR_DUMP_INTER, + "Dump interrupted / inconsistent, please retry."); + return YNL_PARSE_CB_ERROR; + } + + switch (nlh->nlmsg_type) { + case 0: + yerr(yarg->ys, YNL_ERROR_INV_RESP, + "Invalid message type in the response."); + return YNL_PARSE_CB_ERROR; + case NLMSG_NOOP: + case NLMSG_OVERRUN ... NLMSG_MIN_TYPE - 1: + ret = YNL_PARSE_CB_OK; + break; + case NLMSG_ERROR: + ret = ynl_cb_error(nlh, yarg); + break; + case NLMSG_DONE: + ret = ynl_cb_done(nlh, yarg); + break; + default: + ret = cb(nlh, yarg); + break; + } } - return mnl_cb_run(ys->rx_buf, ret, ys->seq, ys->portid, - ynl_cb_null, ys); + + return ret; } -int ynl_cb_null(const struct nlmsghdr *nlh, void *data) +static int ynl_sock_read_msgs(struct ynl_parse_arg *yarg, ynl_parse_cb_t cb) { - struct ynl_parse_arg *yarg = data; + return __ynl_sock_read_msgs(yarg, cb, 0); +} - yerr(yarg->ys, YNL_ERROR_UNEXPECT_MSG, - "Received a message when none were expected"); +static int ynl_recv_ack(struct ynl_sock *ys, int ret) +{ + struct ynl_parse_arg yarg = { .ys = ys, }; + + if (!ret) { + yerr(ys, YNL_ERROR_EXPECT_ACK, + "Expecting an ACK but nothing received"); + return -1; + } - return MNL_CB_ERROR; + return ynl_sock_read_msgs(&yarg, ynl_cb_null); } /* Init/fini and genetlink boiler plate */ @@ -482,7 +637,7 @@ ynl_get_family_info_mcast(struct ynl_sock *ys, const struct nlattr *mcasts) const struct nlattr *entry, *attr; unsigned int i; - mnl_attr_for_each_nested(attr, mcasts) + ynl_attr_for_each_nested(attr, mcasts) ys->n_mcast_groups++; if (!ys->n_mcast_groups) @@ -491,54 +646,55 @@ ynl_get_family_info_mcast(struct ynl_sock *ys, const struct nlattr *mcasts) ys->mcast_groups = calloc(ys->n_mcast_groups, sizeof(*ys->mcast_groups)); if (!ys->mcast_groups) - return MNL_CB_ERROR; + return YNL_PARSE_CB_ERROR; i = 0; - mnl_attr_for_each_nested(entry, mcasts) { - mnl_attr_for_each_nested(attr, entry) { - if (mnl_attr_get_type(attr) == CTRL_ATTR_MCAST_GRP_ID) - ys->mcast_groups[i].id = mnl_attr_get_u32(attr); - if (mnl_attr_get_type(attr) == CTRL_ATTR_MCAST_GRP_NAME) { + ynl_attr_for_each_nested(entry, mcasts) { + ynl_attr_for_each_nested(attr, entry) { + if (ynl_attr_type(attr) == CTRL_ATTR_MCAST_GRP_ID) + ys->mcast_groups[i].id = ynl_attr_get_u32(attr); + if (ynl_attr_type(attr) == CTRL_ATTR_MCAST_GRP_NAME) { strncpy(ys->mcast_groups[i].name, - mnl_attr_get_str(attr), + ynl_attr_get_str(attr), GENL_NAMSIZ - 1); ys->mcast_groups[i].name[GENL_NAMSIZ - 1] = 0; } } + i++; } return 0; } -static int ynl_get_family_info_cb(const struct nlmsghdr *nlh, void *data) +static int +ynl_get_family_info_cb(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg) { - struct ynl_parse_arg *yarg = data; struct ynl_sock *ys = yarg->ys; const struct nlattr *attr; bool found_id = true; - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - if (mnl_attr_get_type(attr) == CTRL_ATTR_MCAST_GROUPS) + ynl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + if (ynl_attr_type(attr) == CTRL_ATTR_MCAST_GROUPS) if (ynl_get_family_info_mcast(ys, attr)) - return MNL_CB_ERROR; + return YNL_PARSE_CB_ERROR; - if (mnl_attr_get_type(attr) != CTRL_ATTR_FAMILY_ID) + if (ynl_attr_type(attr) != CTRL_ATTR_FAMILY_ID) continue; - if (mnl_attr_get_payload_len(attr) != sizeof(__u16)) { + if (ynl_attr_data_len(attr) != sizeof(__u16)) { yerr(ys, YNL_ERROR_ATTR_INVALID, "Invalid family ID"); - return MNL_CB_ERROR; + return YNL_PARSE_CB_ERROR; } - ys->family_id = mnl_attr_get_u16(attr); + ys->family_id = ynl_attr_get_u16(attr); found_id = true; } if (!found_id) { yerr(ys, YNL_ERROR_ATTR_MISSING, "Family ID missing"); - return MNL_CB_ERROR; + return YNL_PARSE_CB_ERROR; } - return MNL_CB_OK; + return YNL_PARSE_CB_OK; } static int ynl_sock_read_family(struct ynl_sock *ys, const char *family_name) @@ -548,68 +704,91 @@ static int ynl_sock_read_family(struct ynl_sock *ys, const char *family_name) int err; nlh = ynl_gemsg_start_req(ys, GENL_ID_CTRL, CTRL_CMD_GETFAMILY, 1); - mnl_attr_put_strz(nlh, CTRL_ATTR_FAMILY_NAME, family_name); + ynl_attr_put_str(nlh, CTRL_ATTR_FAMILY_NAME, family_name); + + err = ynl_msg_end(ys, nlh); + if (err < 0) + return err; - err = mnl_socket_sendto(ys->sock, nlh, nlh->nlmsg_len); + err = send(ys->socket, nlh, nlh->nlmsg_len, 0); if (err < 0) { perr(ys, "failed to request socket family info"); return err; } - err = mnl_socket_recvfrom(ys->sock, ys->rx_buf, MNL_SOCKET_BUFFER_SIZE); - if (err <= 0) { - perr(ys, "failed to receive the socket family info"); + err = ynl_sock_read_msgs(&yarg, ynl_get_family_info_cb); + if (err < 0) { + free(ys->mcast_groups); + perr(ys, "failed to receive the socket family info - no such family?"); return err; } - err = mnl_cb_run2(ys->rx_buf, err, ys->seq, ys->portid, - ynl_get_family_info_cb, &yarg, - ynl_cb_array, ARRAY_SIZE(ynl_cb_array)); + + err = ynl_recv_ack(ys, err); if (err < 0) { free(ys->mcast_groups); - perr(ys, "failed to receive the socket family info - no such family?"); return err; } - return ynl_recv_ack(ys, err); + return 0; } struct ynl_sock * ynl_sock_create(const struct ynl_family *yf, struct ynl_error *yse) { + struct sockaddr_nl addr; struct ynl_sock *ys; + socklen_t addrlen; + int sock_type; int one = 1; - ys = malloc(sizeof(*ys) + 2 * MNL_SOCKET_BUFFER_SIZE); + ys = malloc(sizeof(*ys) + 2 * YNL_SOCKET_BUFFER_SIZE); if (!ys) return NULL; memset(ys, 0, sizeof(*ys)); ys->family = yf; ys->tx_buf = &ys->raw_buf[0]; - ys->rx_buf = &ys->raw_buf[MNL_SOCKET_BUFFER_SIZE]; + ys->rx_buf = &ys->raw_buf[YNL_SOCKET_BUFFER_SIZE]; ys->ntf_last_next = &ys->ntf_first; - ys->sock = mnl_socket_open(NETLINK_GENERIC); - if (!ys->sock) { + sock_type = yf->is_classic ? yf->classic_id : NETLINK_GENERIC; + + ys->socket = socket(AF_NETLINK, SOCK_RAW, sock_type); + if (ys->socket < 0) { __perr(yse, "failed to create a netlink socket"); goto err_free_sock; } - if (mnl_socket_setsockopt(ys->sock, NETLINK_CAP_ACK, - &one, sizeof(one))) { + if (setsockopt(ys->socket, SOL_NETLINK, NETLINK_CAP_ACK, + &one, sizeof(one))) { __perr(yse, "failed to enable netlink ACK"); goto err_close_sock; } - if (mnl_socket_setsockopt(ys->sock, NETLINK_EXT_ACK, - &one, sizeof(one))) { + if (setsockopt(ys->socket, SOL_NETLINK, NETLINK_EXT_ACK, + &one, sizeof(one))) { __perr(yse, "failed to enable netlink ext ACK"); goto err_close_sock; } + memset(&addr, 0, sizeof(addr)); + addr.nl_family = AF_NETLINK; + if (bind(ys->socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + __perr(yse, "unable to bind to a socket address"); + goto err_close_sock; + } + + memset(&addr, 0, sizeof(addr)); + addrlen = sizeof(addr); + if (getsockname(ys->socket, (struct sockaddr *)&addr, &addrlen) < 0) { + __perr(yse, "unable to read socket address"); + goto err_close_sock; + } + ys->portid = addr.nl_pid; ys->seq = random(); - ys->portid = mnl_socket_get_portid(ys->sock); - if (ynl_sock_read_family(ys, yf->name)) { + if (yf->is_classic) { + ys->family_id = yf->classic_id; + } else if (ynl_sock_read_family(ys, yf->name)) { if (yse) memcpy(yse, &ys->err, sizeof(*yse)); goto err_close_sock; @@ -618,7 +797,7 @@ ynl_sock_create(const struct ynl_family *yf, struct ynl_error *yse) return ys; err_close_sock: - mnl_socket_close(ys->sock); + close(ys->socket); err_free_sock: free(ys); return NULL; @@ -628,7 +807,7 @@ void ynl_sock_destroy(struct ynl_sock *ys) { struct ynl_ntf_base_type *ntf; - mnl_socket_close(ys->sock); + close(ys->socket); while ((ntf = ynl_ntf_dequeue(ys))) ynl_ntf_free(ntf); free(ys->mcast_groups); @@ -655,9 +834,9 @@ int ynl_subscribe(struct ynl_sock *ys, const char *grp_name) return -1; } - err = mnl_socket_setsockopt(ys->sock, NETLINK_ADD_MEMBERSHIP, - &ys->mcast_groups[i].id, - sizeof(ys->mcast_groups[i].id)); + err = setsockopt(ys->socket, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, + &ys->mcast_groups[i].id, + sizeof(ys->mcast_groups[i].id)); if (err < 0) { perr(ys, "Subscribing to multicast group failed"); return -1; @@ -668,7 +847,7 @@ int ynl_subscribe(struct ynl_sock *ys, const char *grp_name) int ynl_socket_get_fd(struct ynl_sock *ys) { - return mnl_socket_get_fd(ys->sock); + return ys->socket; } struct ynl_ntf_base_type *ynl_ntf_dequeue(struct ynl_sock *ys) @@ -691,15 +870,23 @@ static int ynl_ntf_parse(struct ynl_sock *ys, const struct nlmsghdr *nlh) struct ynl_parse_arg yarg = { .ys = ys, }; const struct ynl_ntf_info *info; struct ynl_ntf_base_type *rsp; - struct genlmsghdr *gehdr; + __u32 cmd; int ret; - gehdr = mnl_nlmsg_get_payload(nlh); - if (gehdr->cmd >= ys->family->ntf_info_size) - return MNL_CB_ERROR; - info = &ys->family->ntf_info[gehdr->cmd]; + if (ys->family->is_classic) { + cmd = nlh->nlmsg_type; + } else { + struct genlmsghdr *gehdr; + + gehdr = ynl_nlmsg_data(nlh); + cmd = gehdr->cmd; + } + + if (cmd >= ys->family->ntf_info_size) + return YNL_PARSE_CB_ERROR; + info = &ys->family->ntf_info[cmd]; if (!info->cb) - return MNL_CB_ERROR; + return YNL_PARSE_CB_ERROR; rsp = calloc(1, info->alloc_sz); rsp->free = info->free; @@ -707,52 +894,36 @@ static int ynl_ntf_parse(struct ynl_sock *ys, const struct nlmsghdr *nlh) yarg.rsp_policy = info->policy; ret = info->cb(nlh, &yarg); - if (ret <= MNL_CB_STOP) + if (ret <= YNL_PARSE_CB_STOP) goto err_free; rsp->family = nlh->nlmsg_type; - rsp->cmd = gehdr->cmd; + rsp->cmd = cmd; *ys->ntf_last_next = rsp; ys->ntf_last_next = &rsp->next; - return MNL_CB_OK; + return YNL_PARSE_CB_OK; err_free: info->free(rsp); - return MNL_CB_ERROR; + return YNL_PARSE_CB_ERROR; } -static int ynl_ntf_trampoline(const struct nlmsghdr *nlh, void *data) +static int +ynl_ntf_trampoline(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg) { - return ynl_ntf_parse((struct ynl_sock *)data, nlh); + return ynl_ntf_parse(yarg->ys, nlh); } int ynl_ntf_check(struct ynl_sock *ys) { - ssize_t len; + struct ynl_parse_arg yarg = { .ys = ys, }; int err; do { - /* libmnl doesn't let us pass flags to the recv to make - * it non-blocking so we need to poll() or peek() :| - */ - struct pollfd pfd = { }; - - pfd.fd = mnl_socket_get_fd(ys->sock); - pfd.events = POLLIN; - err = poll(&pfd, 1, 1); - if (err < 1) - return err; - - len = mnl_socket_recvfrom(ys->sock, ys->rx_buf, - MNL_SOCKET_BUFFER_SIZE); - if (len < 0) - return len; - - err = mnl_cb_run2(ys->rx_buf, len, ys->seq, ys->portid, - ynl_ntf_trampoline, ys, - ynl_cb_array, NLMSG_MIN_TYPE); + err = __ynl_sock_read_msgs(&yarg, ynl_ntf_trampoline, + MSG_DONTWAIT); if (err < 0) return err; } while (err > 0); @@ -773,35 +944,41 @@ void ynl_error_unknown_notification(struct ynl_sock *ys, __u8 cmd) int ynl_error_parse(struct ynl_parse_arg *yarg, const char *msg) { yerr(yarg->ys, YNL_ERROR_INV_RESP, "Error parsing response: %s", msg); - return MNL_CB_ERROR; + return YNL_PARSE_CB_ERROR; } static int ynl_check_alien(struct ynl_sock *ys, const struct nlmsghdr *nlh, __u32 rsp_cmd) { - struct genlmsghdr *gehdr; + if (ys->family->is_classic) { + if (nlh->nlmsg_type != rsp_cmd) + return ynl_ntf_parse(ys, nlh); + } else { + struct genlmsghdr *gehdr; + + if (ynl_nlmsg_data_len(nlh) < sizeof(*gehdr)) { + yerr(ys, YNL_ERROR_INV_RESP, + "Kernel responded with truncated message"); + return -1; + } - if (mnl_nlmsg_get_payload_len(nlh) < sizeof(*gehdr)) { - yerr(ys, YNL_ERROR_INV_RESP, - "Kernel responded with truncated message"); - return -1; + gehdr = ynl_nlmsg_data(nlh); + if (gehdr->cmd != rsp_cmd) + return ynl_ntf_parse(ys, nlh); } - gehdr = mnl_nlmsg_get_payload(nlh); - if (gehdr->cmd != rsp_cmd) - return ynl_ntf_parse(ys, nlh); - return 0; } -static int ynl_req_trampoline(const struct nlmsghdr *nlh, void *data) +static +int ynl_req_trampoline(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg) { - struct ynl_req_state *yrs = data; + struct ynl_req_state *yrs = (void *)yarg; int ret; ret = ynl_check_alien(yrs->yarg.ys, nlh, yrs->rsp_cmd); if (ret) - return ret < 0 ? MNL_CB_ERROR : MNL_CB_OK; + return ret < 0 ? YNL_PARSE_CB_ERROR : YNL_PARSE_CB_OK; return yrs->cb(nlh, &yrs->yarg); } @@ -809,43 +986,38 @@ static int ynl_req_trampoline(const struct nlmsghdr *nlh, void *data) int ynl_exec(struct ynl_sock *ys, struct nlmsghdr *req_nlh, struct ynl_req_state *yrs) { - ssize_t len; int err; - err = mnl_socket_sendto(ys->sock, req_nlh, req_nlh->nlmsg_len); + err = ynl_msg_end(ys, req_nlh); + if (err < 0) + return err; + + err = send(ys->socket, req_nlh, req_nlh->nlmsg_len, 0); if (err < 0) return err; do { - len = mnl_socket_recvfrom(ys->sock, ys->rx_buf, - MNL_SOCKET_BUFFER_SIZE); - if (len < 0) - return len; - - err = mnl_cb_run2(ys->rx_buf, len, ys->seq, ys->portid, - ynl_req_trampoline, yrs, - ynl_cb_array, NLMSG_MIN_TYPE); - if (err < 0) - return err; + err = ynl_sock_read_msgs(&yrs->yarg, ynl_req_trampoline); } while (err > 0); - return 0; + return err; } -static int ynl_dump_trampoline(const struct nlmsghdr *nlh, void *data) +static int +ynl_dump_trampoline(const struct nlmsghdr *nlh, struct ynl_parse_arg *data) { - struct ynl_dump_state *ds = data; + struct ynl_dump_state *ds = (void *)data; struct ynl_dump_list_type *obj; struct ynl_parse_arg yarg = {}; int ret; - ret = ynl_check_alien(ds->ys, nlh, ds->rsp_cmd); + ret = ynl_check_alien(ds->yarg.ys, nlh, ds->rsp_cmd); if (ret) - return ret < 0 ? MNL_CB_ERROR : MNL_CB_OK; + return ret < 0 ? YNL_PARSE_CB_ERROR : YNL_PARSE_CB_OK; obj = calloc(1, ds->alloc_sz); if (!obj) - return MNL_CB_ERROR; + return YNL_PARSE_CB_ERROR; if (!ds->first) ds->first = obj; @@ -853,8 +1025,7 @@ static int ynl_dump_trampoline(const struct nlmsghdr *nlh, void *data) ds->last->next = obj; ds->last = obj; - yarg.ys = ds->ys; - yarg.rsp_policy = ds->rsp_policy; + yarg = ds->yarg; yarg.data = &obj->data; return ds->cb(nlh, &yarg); @@ -872,22 +1043,18 @@ static void *ynl_dump_end(struct ynl_dump_state *ds) int ynl_exec_dump(struct ynl_sock *ys, struct nlmsghdr *req_nlh, struct ynl_dump_state *yds) { - ssize_t len; int err; - err = mnl_socket_sendto(ys->sock, req_nlh, req_nlh->nlmsg_len); + err = ynl_msg_end(ys, req_nlh); if (err < 0) return err; - do { - len = mnl_socket_recvfrom(ys->sock, ys->rx_buf, - MNL_SOCKET_BUFFER_SIZE); - if (len < 0) - goto err_close_list; + err = send(ys->socket, req_nlh, req_nlh->nlmsg_len, 0); + if (err < 0) + return err; - err = mnl_cb_run2(ys->rx_buf, len, ys->seq, ys->portid, - ynl_dump_trampoline, yds, - ynl_cb_array, NLMSG_MIN_TYPE); + do { + err = ynl_sock_read_msgs(&yds->yarg, ynl_dump_trampoline); if (err < 0) goto err_close_list; } while (err > 0); diff --git a/tools/net/ynl/lib/ynl.h b/tools/net/ynl/lib/ynl.h index 9eafa3552c16..db7c0591a63f 100644 --- a/tools/net/ynl/lib/ynl.h +++ b/tools/net/ynl/lib/ynl.h @@ -2,26 +2,18 @@ #ifndef __YNL_C_H #define __YNL_C_H 1 +#include <stdbool.h> #include <stddef.h> -#include <libmnl/libmnl.h> #include <linux/genetlink.h> #include <linux/types.h> -struct mnl_socket; -struct nlmsghdr; - -/* - * User facing code - */ - -struct ynl_ntf_base_type; -struct ynl_ntf_info; -struct ynl_sock; +#include "ynl-priv.h" enum ynl_error_code { YNL_ERROR_NONE = 0, __YNL_ERRNO_END = 4096, YNL_ERROR_INTERNAL, + YNL_ERROR_DUMP_INTER, YNL_ERROR_EXPECT_ACK, YNL_ERROR_EXPECT_MSG, YNL_ERROR_UNEXPECT_MSG, @@ -29,6 +21,9 @@ enum ynl_error_code { YNL_ERROR_ATTR_INVALID, YNL_ERROR_UNKNOWN_NTF, YNL_ERROR_INV_RESP, + YNL_ERROR_INPUT_INVALID, + YNL_ERROR_INPUT_TOO_BIG, + YNL_ERROR_SUBMSG_KEY, }; /** @@ -54,6 +49,9 @@ struct ynl_error { struct ynl_family { /* private: */ const char *name; + size_t hdr_len; + bool is_classic; + __u16 classic_id; const struct ynl_ntf_info *ntf_info; unsigned int ntf_info_size; }; @@ -67,7 +65,7 @@ struct ynl_sock { /* private: */ const struct ynl_family *family; - struct mnl_socket *sock; + int socket; __u32 seq; __u32 portid; __u16 family_id; @@ -82,12 +80,26 @@ struct ynl_sock { struct ynl_ntf_base_type **ntf_last_next; struct nlmsghdr *nlh; - struct ynl_policy_nest *req_policy; + const struct ynl_policy_nest *req_policy; + size_t req_hdr_len; unsigned char *tx_buf; unsigned char *rx_buf; unsigned char raw_buf[]; }; +/** + * struct ynl_string - parsed individual string + * @len: length of the string (excluding terminating character) + * @str: value of the string + * + * Parsed and nul-terminated string. This struct is only used for arrays of + * strings. Non-array string members are placed directly in respective types. + */ +struct ynl_string { + unsigned int len; + char str[]; +}; + struct ynl_sock * ynl_sock_create(const struct ynl_family *yf, struct ynl_error *e); void ynl_sock_destroy(struct ynl_sock *ys); @@ -97,6 +109,18 @@ void ynl_sock_destroy(struct ynl_sock *ys); !ynl_dump_obj_is_last(iter); \ iter = ynl_dump_obj_next(iter)) +/** + * ynl_dump_empty() - does the dump have no entries + * @dump: pointer to the dump list, as returned by a dump call + * + * Check if the dump is empty, i.e. contains no objects. + * Dump calls return NULL on error, and terminator element if empty. + */ +static inline bool ynl_dump_empty(void *dump) +{ + return dump == (void *)YNL_LIST_END; +} + int ynl_subscribe(struct ynl_sock *ys, const char *grp_name); int ynl_socket_get_fd(struct ynl_sock *ys); int ynl_ntf_check(struct ynl_sock *ys); @@ -116,122 +140,4 @@ static inline bool ynl_has_ntf(struct ynl_sock *ys) struct ynl_ntf_base_type *ynl_ntf_dequeue(struct ynl_sock *ys); void ynl_ntf_free(struct ynl_ntf_base_type *ntf); - -/* - * YNL internals / low level stuff - */ - -/* Generic mnl helper code */ - -enum ynl_policy_type { - YNL_PT_REJECT = 1, - YNL_PT_IGNORE, - YNL_PT_NEST, - YNL_PT_FLAG, - YNL_PT_BINARY, - YNL_PT_U8, - YNL_PT_U16, - YNL_PT_U32, - YNL_PT_U64, - YNL_PT_NUL_STR, -}; - -struct ynl_policy_attr { - enum ynl_policy_type type; - unsigned int len; - const char *name; - struct ynl_policy_nest *nest; -}; - -struct ynl_policy_nest { - unsigned int max_attr; - struct ynl_policy_attr *table; -}; - -struct ynl_parse_arg { - struct ynl_sock *ys; - struct ynl_policy_nest *rsp_policy; - void *data; -}; - -struct ynl_dump_list_type { - struct ynl_dump_list_type *next; - unsigned char data[] __attribute__ ((aligned (8))); -}; -extern struct ynl_dump_list_type *YNL_LIST_END; - -static inline bool ynl_dump_obj_is_last(void *obj) -{ - unsigned long uptr = (unsigned long)obj; - - uptr -= offsetof(struct ynl_dump_list_type, data); - return uptr == (unsigned long)YNL_LIST_END; -} - -static inline void *ynl_dump_obj_next(void *obj) -{ - unsigned long uptr = (unsigned long)obj; - struct ynl_dump_list_type *list; - - uptr -= offsetof(struct ynl_dump_list_type, data); - list = (void *)uptr; - uptr = (unsigned long)list->next; - uptr += offsetof(struct ynl_dump_list_type, data); - - return (void *)uptr; -} - -struct ynl_ntf_base_type { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ynl_ntf_base_type *ntf); - unsigned char data[] __attribute__ ((aligned (8))); -}; - -extern mnl_cb_t ynl_cb_array[NLMSG_MIN_TYPE]; - -struct nlmsghdr * -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_recv_ack(struct ynl_sock *ys, int ret); -int ynl_cb_null(const struct nlmsghdr *nlh, void *data); - -/* YNL specific helpers used by the auto-generated code */ - -struct ynl_req_state { - struct ynl_parse_arg yarg; - mnl_cb_t cb; - __u32 rsp_cmd; -}; - -struct ynl_dump_state { - struct ynl_sock *ys; - struct ynl_policy_nest *rsp_policy; - void *first; - struct ynl_dump_list_type *last; - size_t alloc_sz; - mnl_cb_t cb; - __u32 rsp_cmd; -}; - -struct ynl_ntf_info { - struct ynl_policy_nest *policy; - mnl_cb_t cb; - size_t alloc_sz; - void (*free)(struct ynl_ntf_base_type *ntf); -}; - -int ynl_exec(struct ynl_sock *ys, struct nlmsghdr *req_nlh, - struct ynl_req_state *yrs); -int ynl_exec_dump(struct ynl_sock *ys, struct nlmsghdr *req_nlh, - struct ynl_dump_state *yds); - -void ynl_error_unknown_notification(struct ynl_sock *ys, __u8 cmd); -int ynl_error_parse(struct ynl_parse_arg *yarg, const char *msg); - #endif diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py deleted file mode 100644 index 13c4b019a881..000000000000 --- a/tools/net/ynl/lib/ynl.py +++ /dev/null @@ -1,729 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause - -from collections import namedtuple -import functools -import os -import random -import socket -import struct -from struct import Struct -import yaml -import ipaddress -import uuid - -from .nlspec import SpecFamily - -# -# Generic Netlink code which should really be in some library, but I can't quickly find one. -# - - -class Netlink: - # Netlink socket - SOL_NETLINK = 270 - - NETLINK_ADD_MEMBERSHIP = 1 - NETLINK_CAP_ACK = 10 - NETLINK_EXT_ACK = 11 - NETLINK_GET_STRICT_CHK = 12 - - # Netlink message - NLMSG_ERROR = 2 - NLMSG_DONE = 3 - - NLM_F_REQUEST = 1 - NLM_F_ACK = 4 - NLM_F_ROOT = 0x100 - NLM_F_MATCH = 0x200 - - NLM_F_REPLACE = 0x100 - NLM_F_EXCL = 0x200 - NLM_F_CREATE = 0x400 - NLM_F_APPEND = 0x800 - - NLM_F_CAPPED = 0x100 - NLM_F_ACK_TLVS = 0x200 - - NLM_F_DUMP = NLM_F_ROOT | NLM_F_MATCH - - NLA_F_NESTED = 0x8000 - NLA_F_NET_BYTEORDER = 0x4000 - - NLA_TYPE_MASK = NLA_F_NESTED | NLA_F_NET_BYTEORDER - - # Genetlink defines - NETLINK_GENERIC = 16 - - GENL_ID_CTRL = 0x10 - - # nlctrl - CTRL_CMD_GETFAMILY = 3 - - CTRL_ATTR_FAMILY_ID = 1 - CTRL_ATTR_FAMILY_NAME = 2 - CTRL_ATTR_MAXATTR = 5 - CTRL_ATTR_MCAST_GROUPS = 7 - - CTRL_ATTR_MCAST_GRP_NAME = 1 - CTRL_ATTR_MCAST_GRP_ID = 2 - - # Extack types - NLMSGERR_ATTR_MSG = 1 - NLMSGERR_ATTR_OFFS = 2 - NLMSGERR_ATTR_COOKIE = 3 - NLMSGERR_ATTR_POLICY = 4 - NLMSGERR_ATTR_MISS_TYPE = 5 - NLMSGERR_ATTR_MISS_NEST = 6 - - -class NlError(Exception): - def __init__(self, nl_msg): - self.nl_msg = nl_msg - - def __str__(self): - return f"Netlink error: {os.strerror(-self.nl_msg.error)}\n{self.nl_msg}" - - -class NlAttr: - ScalarFormat = namedtuple('ScalarFormat', ['native', 'big', 'little']) - type_formats = { - 'u8' : ScalarFormat(Struct('B'), Struct("B"), Struct("B")), - 's8' : ScalarFormat(Struct('b'), Struct("b"), Struct("b")), - 'u16': ScalarFormat(Struct('H'), Struct(">H"), Struct("<H")), - 's16': ScalarFormat(Struct('h'), Struct(">h"), Struct("<h")), - 'u32': ScalarFormat(Struct('I'), Struct(">I"), Struct("<I")), - 's32': ScalarFormat(Struct('i'), Struct(">i"), Struct("<i")), - 'u64': ScalarFormat(Struct('Q'), Struct(">Q"), Struct("<Q")), - 's64': ScalarFormat(Struct('q'), Struct(">q"), Struct("<q")) - } - - def __init__(self, raw, offset): - self._len, self._type = struct.unpack("HH", raw[offset:offset + 4]) - self.type = self._type & ~Netlink.NLA_TYPE_MASK - self.payload_len = self._len - self.full_len = (self.payload_len + 3) & ~3 - self.raw = raw[offset + 4:offset + self.payload_len] - - @classmethod - def get_format(cls, attr_type, byte_order=None): - format = cls.type_formats[attr_type] - if byte_order: - return format.big if byte_order == "big-endian" \ - else format.little - return format.native - - @classmethod - def formatted_string(cls, raw, display_hint): - if display_hint == 'mac': - formatted = ':'.join('%02x' % b for b in raw) - elif display_hint == 'hex': - formatted = bytes.hex(raw, ' ') - elif display_hint in [ 'ipv4', 'ipv6' ]: - formatted = format(ipaddress.ip_address(raw)) - elif display_hint == 'uuid': - formatted = str(uuid.UUID(bytes=raw)) - else: - formatted = raw - return formatted - - def as_scalar(self, attr_type, byte_order=None): - format = self.get_format(attr_type, byte_order) - return format.unpack(self.raw)[0] - - def as_strz(self): - return self.raw.decode('ascii')[:-1] - - def as_bin(self): - return self.raw - - def as_c_array(self, type): - format = self.get_format(type) - return [ x[0] for x in format.iter_unpack(self.raw) ] - - def as_struct(self, members): - value = dict() - offset = 0 - for m in members: - # TODO: handle non-scalar members - if m.type == 'binary': - 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) - [ decoded ] = format.unpack_from(self.raw, offset) - offset += format.size - if m.display_hint: - decoded = self.formatted_string(decoded, m.display_hint) - value[m.name] = decoded - return value - - def __repr__(self): - return f"[type:{self.type} len:{self._len}] {self.raw}" - - -class NlAttrs: - def __init__(self, msg): - self.attrs = [] - - offset = 0 - while offset < len(msg): - attr = NlAttr(msg, offset) - offset += attr.full_len - self.attrs.append(attr) - - def __iter__(self): - yield from self.attrs - - def __repr__(self): - msg = '' - for a in self.attrs: - if msg: - msg += '\n' - msg += repr(a) - return msg - - -class NlMsg: - def __init__(self, msg, offset, attr_space=None): - 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.error = 0 - self.done = 0 - - extack_off = None - if self.nl_type == Netlink.NLMSG_ERROR: - self.error = struct.unpack("i", self.raw[0:4])[0] - self.done = 1 - extack_off = 20 - elif self.nl_type == Netlink.NLMSG_DONE: - self.done = 1 - extack_off = 4 - - self.extack = None - if self.nl_flags & Netlink.NLM_F_ACK_TLVS and extack_off: - self.extack = dict() - extack_attrs = NlAttrs(self.raw[extack_off:]) - for extack in extack_attrs: - if extack.type == Netlink.NLMSGERR_ATTR_MSG: - self.extack['msg'] = extack.as_strz() - elif extack.type == Netlink.NLMSGERR_ATTR_MISS_TYPE: - self.extack['miss-type'] = extack.as_scalar('u32') - elif extack.type == Netlink.NLMSGERR_ATTR_MISS_NEST: - self.extack['miss-nest'] = extack.as_scalar('u32') - elif extack.type == Netlink.NLMSGERR_ATTR_OFFS: - self.extack['bad-attr-offs'] = extack.as_scalar('u32') - else: - if 'unknown' not in self.extack: - self.extack['unknown'] = [] - self.extack['unknown'].append(extack) - - if attr_space: - # We don't have the ability to parse nests yet, so only do global - if 'miss-type' in self.extack and 'miss-nest' not in self.extack: - miss_type = self.extack['miss-type'] - if miss_type in attr_space.attrs_by_val: - spec = attr_space.attrs_by_val[miss_type] - desc = spec['name'] - if 'doc' in spec: - desc += f" ({spec['doc']})" - self.extack['miss-type'] = desc - - def cmd(self): - return self.nl_type - - def __repr__(self): - msg = f"nl_len = {self.nl_len} ({len(self.raw)}) nl_flags = 0x{self.nl_flags:x} nl_type = {self.nl_type}\n" - if self.error: - msg += '\terror: ' + str(self.error) - if self.extack: - msg += '\textack: ' + repr(self.extack) - return msg - - -class NlMsgs: - def __init__(self, data, attr_space=None): - self.msgs = [] - - offset = 0 - while offset < len(data): - msg = NlMsg(data, offset, attr_space=attr_space) - offset += msg.nl_len - self.msgs.append(msg) - - def __iter__(self): - yield from self.msgs - - -genl_family_name_to_id = None - - -def _genl_msg(nl_type, nl_flags, genl_cmd, genl_version, seq=None): - # we prepend length in _genl_msg_finalize() - if seq is None: - seq = random.randint(1, 1024) - nlmsg = struct.pack("HHII", nl_type, nl_flags, seq, 0) - genlmsg = struct.pack("BBH", genl_cmd, genl_version, 0) - return nlmsg + genlmsg - - -def _genl_msg_finalize(msg): - return struct.pack("I", len(msg) + 4) + msg - - -def _genl_load_families(): - with socket.socket(socket.AF_NETLINK, socket.SOCK_RAW, Netlink.NETLINK_GENERIC) as sock: - sock.setsockopt(Netlink.SOL_NETLINK, Netlink.NETLINK_CAP_ACK, 1) - - msg = _genl_msg(Netlink.GENL_ID_CTRL, - Netlink.NLM_F_REQUEST | Netlink.NLM_F_ACK | Netlink.NLM_F_DUMP, - Netlink.CTRL_CMD_GETFAMILY, 1) - msg = _genl_msg_finalize(msg) - - sock.send(msg, 0) - - global genl_family_name_to_id - genl_family_name_to_id = dict() - - while True: - reply = sock.recv(128 * 1024) - nms = NlMsgs(reply) - for nl_msg in nms: - if nl_msg.error: - print("Netlink error:", nl_msg.error) - return - if nl_msg.done: - return - - gm = GenlMsg(nl_msg) - fam = dict() - for attr in NlAttrs(gm.raw): - if attr.type == Netlink.CTRL_ATTR_FAMILY_ID: - fam['id'] = attr.as_scalar('u16') - elif attr.type == Netlink.CTRL_ATTR_FAMILY_NAME: - fam['name'] = attr.as_strz() - elif attr.type == Netlink.CTRL_ATTR_MAXATTR: - fam['maxattr'] = attr.as_scalar('u32') - elif attr.type == Netlink.CTRL_ATTR_MCAST_GROUPS: - fam['mcast'] = dict() - for entry in NlAttrs(attr.raw): - mcast_name = None - mcast_id = None - for entry_attr in NlAttrs(entry.raw): - if entry_attr.type == Netlink.CTRL_ATTR_MCAST_GRP_NAME: - mcast_name = entry_attr.as_strz() - elif entry_attr.type == Netlink.CTRL_ATTR_MCAST_GRP_ID: - mcast_id = entry_attr.as_scalar('u32') - if mcast_name and mcast_id is not None: - fam['mcast'][mcast_name] = mcast_id - if 'name' in fam and 'id' in fam: - genl_family_name_to_id[fam['name']] = fam - - -class GenlMsg: - def __init__(self, nl_msg): - self.nl = nl_msg - self.genl_cmd, self.genl_version, _ = struct.unpack_from("BBH", nl_msg.raw, 0) - self.raw = nl_msg.raw[4:] - - def cmd(self): - return self.genl_cmd - - def __repr__(self): - msg = repr(self.nl) - msg += f"\tgenl_cmd = {self.genl_cmd} genl_ver = {self.genl_version}\n" - for a in self.raw_attrs: - msg += '\t\t' + repr(a) + '\n' - return msg - - -class NetlinkProtocol: - def __init__(self, family_name, proto_num): - self.family_name = family_name - self.proto_num = proto_num - - def _message(self, nl_type, nl_flags, seq=None): - if seq is None: - seq = random.randint(1, 1024) - nlmsg = struct.pack("HHII", nl_type, nl_flags, seq, 0) - return nlmsg - - def message(self, flags, command, version, seq=None): - return self._message(command, flags, seq) - - def _decode(self, nl_msg): - return nl_msg - - def decode(self, ynl, nl_msg): - msg = self._decode(nl_msg) - 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:]) - return msg - - def get_mcast_id(self, mcast_name, mcast_groups): - if mcast_name not in mcast_groups: - raise Exception(f'Multicast group "{mcast_name}" not present in the spec') - return mcast_groups[mcast_name].value - - -class GenlProtocol(NetlinkProtocol): - def __init__(self, family_name): - super().__init__(family_name, Netlink.NETLINK_GENERIC) - - global genl_family_name_to_id - if genl_family_name_to_id is None: - _genl_load_families() - - self.genl_family = genl_family_name_to_id[family_name] - self.family_id = genl_family_name_to_id[family_name]['id'] - - def message(self, flags, command, version, seq=None): - nlmsg = self._message(self.family_id, flags, seq) - genlmsg = struct.pack("BBH", command, version, 0) - return nlmsg + genlmsg - - def _decode(self, nl_msg): - return GenlMsg(nl_msg) - - def get_mcast_id(self, mcast_name, mcast_groups): - if mcast_name not in self.genl_family['mcast']: - raise Exception(f'Multicast group "{mcast_name}" not present in the family') - return self.genl_family['mcast'][mcast_name] - - -# -# YNL implementation details. -# - - -class YnlFamily(SpecFamily): - def __init__(self, def_path, schema=None): - super().__init__(def_path, schema) - - self.include_raw = False - - try: - if self.proto == "netlink-raw": - self.nlproto = NetlinkProtocol(self.yaml['name'], - self.yaml['protonum']) - else: - self.nlproto = GenlProtocol(self.yaml['name']) - except KeyError: - raise Exception(f"Family '{self.yaml['name']}' not supported by the kernel") - - self.sock = socket.socket(socket.AF_NETLINK, socket.SOCK_RAW, self.nlproto.proto_num) - self.sock.setsockopt(Netlink.SOL_NETLINK, Netlink.NETLINK_CAP_ACK, 1) - self.sock.setsockopt(Netlink.SOL_NETLINK, Netlink.NETLINK_EXT_ACK, 1) - self.sock.setsockopt(Netlink.SOL_NETLINK, Netlink.NETLINK_GET_STRICT_CHK, 1) - - self.async_msg_ids = set() - self.async_msg_queue = [] - - for msg in self.msgs.values(): - if msg.is_async: - self.async_msg_ids.add(msg.rsp_value) - - for op_name, op in self.ops.items(): - bound_f = functools.partial(self._op, op_name) - setattr(self, op.ident_name, bound_f) - - - def ntf_subscribe(self, mcast_name): - mcast_id = self.nlproto.get_mcast_id(mcast_name, self.mcast_groups) - self.sock.bind((0, 0)) - self.sock.setsockopt(Netlink.SOL_NETLINK, Netlink.NETLINK_ADD_MEMBERSHIP, - mcast_id) - - def _add_attr(self, space, name, value): - try: - attr = self.attr_sets[space][name] - except KeyError: - raise Exception(f"Space '{space}' has no attribute '{name}'") - nl_type = attr.value - if attr["type"] == 'nest': - nl_type |= Netlink.NLA_F_NESTED - attr_payload = b'' - for subname, subvalue in value.items(): - attr_payload += self._add_attr(attr['nested-attributes'], subname, subvalue) - elif attr["type"] == 'flag': - attr_payload = b'' - elif attr["type"] == 'string': - attr_payload = str(value).encode('ascii') + b'\x00' - elif attr["type"] == 'binary': - if isinstance(value, bytes): - attr_payload = value - elif isinstance(value, str): - attr_payload = bytes.fromhex(value) - else: - raise Exception(f'Unknown type for binary attribute, value: {value}') - elif attr['type'] in NlAttr.type_formats: - format = NlAttr.get_format(attr['type'], attr.byte_order) - attr_payload = format.pack(int(value)) - else: - raise Exception(f'Unknown type at {space} {name} {value} {attr["type"]}') - - pad = b'\x00' * ((4 - len(attr_payload) % 4) % 4) - return struct.pack('HH', len(attr_payload) + 4, nl_type) + attr_payload + pad - - def _decode_enum(self, raw, attr_spec): - enum = self.consts[attr_spec['enum']] - if 'enum-as-flags' in attr_spec and attr_spec['enum-as-flags']: - i = 0 - value = set() - while raw: - if raw & 1: - value.add(enum.entries_by_val[i].name) - raw >>= 1 - i += 1 - else: - value = enum.entries_by_val[raw].name - return value - - def _decode_binary(self, attr, attr_spec): - if attr_spec.struct_name: - members = self.consts[attr_spec.struct_name] - decoded = attr.as_struct(members) - for m in members: - if m.enum: - decoded[m.name] = self._decode_enum(decoded[m.name], m) - elif attr_spec.sub_type: - decoded = attr.as_c_array(attr_spec.sub_type) - else: - decoded = attr.as_bin() - if attr_spec.display_hint: - decoded = NlAttr.formatted_string(decoded, attr_spec.display_hint) - return decoded - - def _decode_array_nest(self, attr, attr_spec): - decoded = [] - offset = 0 - while offset < len(attr.raw): - item = NlAttr(attr.raw, offset) - offset += item.full_len - - subattrs = self._decode(NlAttrs(item.raw), attr_spec['nested-attributes']) - decoded.append({ item.type: subattrs }) - return decoded - - def _decode(self, attrs, space): - attr_space = self.attr_sets[space] - rsp = dict() - for attr in attrs: - try: - attr_spec = attr_space.attrs_by_val[attr.type] - except KeyError: - raise Exception(f"Space '{space}' has no attribute with value '{attr.type}'") - if attr_spec["type"] == 'nest': - subdict = self._decode(NlAttrs(attr.raw), attr_spec['nested-attributes']) - decoded = subdict - elif attr_spec["type"] == 'string': - decoded = attr.as_strz() - elif attr_spec["type"] == 'binary': - decoded = self._decode_binary(attr, attr_spec) - elif attr_spec["type"] == 'flag': - decoded = True - elif attr_spec["type"] in NlAttr.type_formats: - decoded = attr.as_scalar(attr_spec['type'], attr_spec.byte_order) - elif attr_spec["type"] == 'array-nest': - decoded = self._decode_array_nest(attr, attr_spec) - 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: - rsp[attr_spec.name].append(decoded) - else: - rsp[attr_spec.name] = [decoded] - - return rsp - - def _decode_extack_path(self, attrs, attr_set, offset, target): - for attr in attrs: - try: - attr_spec = attr_set.attrs_by_val[attr.type] - except KeyError: - raise Exception(f"Space '{attr_set.name}' has no attribute with value '{attr.type}'") - if offset > target: - break - if offset == target: - return '.' + attr_spec.name - - if offset + attr.full_len <= target: - offset += attr.full_len - continue - if attr_spec['type'] != 'nest': - raise Exception(f"Can't dive into {attr.type} ({attr_spec['name']}) for extack") - offset += 4 - subpath = self._decode_extack_path(NlAttrs(attr.raw), - self.attr_sets[attr_spec['nested-attributes']], - offset, target) - if subpath is None: - return None - return '.' + attr_spec.name + subpath - - return None - - def _decode_extack(self, request, op, extack): - if 'bad-attr-offs' not in extack: - return - - msg = self.nlproto.decode(self, NlMsg(request, 0, op.attr_set)) - offset = 20 + self._fixed_header_size(op) - 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 - size = 0 - for m in fixed_header_members: - format = NlAttr.get_format(m.type, m.byte_order) - size += format.size - return size - else: - return 0 - - def _decode_fixed_header(self, msg, name): - fixed_header_members = self.consts[name].members - 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 - return fixed_header_attrs - - def handle_ntf(self, decoded): - msg = dict() - if self.include_raw: - msg['raw'] = decoded - op = self.rsp_by_value[decoded.cmd()] - attrs = self._decode(decoded.raw_attrs, op.attr_set.name) - if op.fixed_header: - attrs.update(self._decode_fixed_header(decoded, op.fixed_header)) - - msg['name'] = op['name'] - msg['msg'] = attrs - self.async_msg_queue.append(msg) - - def check_ntf(self): - while True: - try: - reply = self.sock.recv(128 * 1024, socket.MSG_DONTWAIT) - except BlockingIOError: - return - - nms = NlMsgs(reply) - for nl_msg in nms: - if nl_msg.error: - print("Netlink error in ntf!?", os.strerror(-nl_msg.error)) - print(nl_msg) - continue - if nl_msg.done: - print("Netlink done while checking for ntf!?") - continue - - decoded = self.nlproto.decode(self, nl_msg) - if decoded.cmd() not in self.async_msg_ids: - print("Unexpected msg id done while checking for ntf", decoded) - continue - - self.handle_ntf(decoded) - - def operation_do_attributes(self, name): - """ - For a given operation name, find and return a supported - set of attributes (as a dict). - """ - op = self.find_operation(name) - if not op: - return None - - return op['do']['request']['attributes'].copy() - - def _op(self, method, vals, flags, dump=False): - op = self.ops[method] - - nl_flags = Netlink.NLM_F_REQUEST | Netlink.NLM_F_ACK - for flag in flags or []: - nl_flags |= flag - if dump: - nl_flags |= Netlink.NLM_F_DUMP - - req_seq = random.randint(1024, 65535) - msg = self.nlproto.message(nl_flags, op.req_value, 1, req_seq) - fixed_header_members = [] - if op.fixed_header: - 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) - for name, value in vals.items(): - msg += self._add_attr(op.attr_set.name, name, value) - msg = _genl_msg_finalize(msg) - - self.sock.send(msg, 0) - - done = False - rsp = [] - while not done: - reply = self.sock.recv(128 * 1024) - nms = NlMsgs(reply, attr_space=op.attr_set) - for nl_msg in nms: - if nl_msg.extack: - self._decode_extack(msg, op, nl_msg.extack) - - if nl_msg.error: - raise NlError(nl_msg) - if nl_msg.done: - if nl_msg.extack: - print("Netlink warning:") - print(nl_msg) - done = True - break - - decoded = self.nlproto.decode(self, nl_msg) - - # Check if this is a reply to our request - if nl_msg.nl_seq != req_seq or decoded.cmd() != op.rsp_value: - if decoded.cmd() in self.async_msg_ids: - self.handle_ntf(decoded) - continue - else: - print('Unexpected message: ' + repr(decoded)) - continue - - rsp_msg = self._decode(decoded.raw_attrs, op.attr_set.name) - if op.fixed_header: - rsp_msg.update(self._decode_fixed_header(decoded, op.fixed_header)) - rsp.append(rsp_msg) - - if not rsp: - return None - if not dump and len(rsp) == 1: - return rsp[0] - return rsp - - def do(self, method, vals, flags): - return self._op(method, vals, flags) - - def dump(self, method, vals): - return self._op(method, vals, [], dump=True) diff --git a/tools/net/ynl/pyproject.toml b/tools/net/ynl/pyproject.toml new file mode 100644 index 000000000000..a81d8779b0e0 --- /dev/null +++ b/tools/net/ynl/pyproject.toml @@ -0,0 +1,24 @@ +[build-system] +requires = ["setuptools>=61.0"] +build-backend = "setuptools.build_meta" + +[project] +name = "pyynl" +authors = [ + {name = "Donald Hunter", email = "donald.hunter@gmail.com"}, + {name = "Jakub Kicinski", email = "kuba@kernel.org"}, +] +description = "yaml netlink (ynl)" +version = "0.0.1" +requires-python = ">=3.9" +dependencies = [ + "pyyaml==6.*", + "jsonschema==4.*" +] + +[tool.setuptools.packages.find] +include = ["pyynl", "pyynl.lib"] + +[project.scripts] +ynl = "pyynl.cli:main" +ynl-ethtool = "pyynl.ethtool:main" diff --git a/tools/net/ynl/pyynl/.gitignore b/tools/net/ynl/pyynl/.gitignore new file mode 100644 index 000000000000..b801cd2d016e --- /dev/null +++ b/tools/net/ynl/pyynl/.gitignore @@ -0,0 +1,2 @@ +__pycache__/ +lib/__pycache__/ diff --git a/tools/net/ynl/pyynl/__init__.py b/tools/net/ynl/pyynl/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/tools/net/ynl/pyynl/__init__.py diff --git a/tools/net/ynl/pyynl/cli.py b/tools/net/ynl/pyynl/cli.py new file mode 100755 index 000000000000..af02a5b7e5a2 --- /dev/null +++ b/tools/net/ynl/pyynl/cli.py @@ -0,0 +1,253 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause + +import argparse +import json +import os +import pathlib +import pprint +import sys +import textwrap + +sys.path.append(pathlib.Path(__file__).resolve().parent.as_posix()) +from lib import YnlFamily, Netlink, NlError, SpecFamily + +sys_schema_dir='/usr/share/ynl' +relative_schema_dir='../../../../Documentation/netlink' + +def schema_dir(): + script_dir = os.path.dirname(os.path.abspath(__file__)) + schema_dir = os.path.abspath(f"{script_dir}/{relative_schema_dir}") + if not os.path.isdir(schema_dir): + schema_dir = sys_schema_dir + if not os.path.isdir(schema_dir): + raise Exception(f"Schema directory {schema_dir} does not exist") + return schema_dir + +def spec_dir(): + spec_dir = schema_dir() + '/specs' + if not os.path.isdir(spec_dir): + raise Exception(f"Spec directory {spec_dir} does not exist") + return spec_dir + + +class YnlEncoder(json.JSONEncoder): + def default(self, obj): + if isinstance(obj, bytes): + return bytes.hex(obj) + if isinstance(obj, set): + return list(obj) + return json.JSONEncoder.default(self, obj) + + +def print_attr_list(ynl, attr_names, attr_set, indent=2): + """Print a list of attributes with their types and documentation.""" + prefix = ' ' * indent + for attr_name in attr_names: + if attr_name in attr_set.attrs: + attr = attr_set.attrs[attr_name] + attr_info = f'{prefix}- {attr_name}: {attr.type}' + if 'enum' in attr.yaml: + enum_name = attr.yaml['enum'] + attr_info += f" (enum: {enum_name})" + # Print enum values if available + if enum_name in ynl.consts: + const = ynl.consts[enum_name] + enum_values = list(const.entries.keys()) + attr_info += f"\n{prefix} {const.type.capitalize()}: {', '.join(enum_values)}" + + # Show nested attributes reference and recursively display them + nested_set_name = None + if attr.type == 'nest' and 'nested-attributes' in attr.yaml: + nested_set_name = attr.yaml['nested-attributes'] + attr_info += f" -> {nested_set_name}" + + if attr.yaml.get('doc'): + doc_text = textwrap.indent(attr.yaml['doc'], prefix + ' ') + attr_info += f"\n{doc_text}" + print(attr_info) + + # Recursively show nested attributes + if nested_set_name in ynl.attr_sets: + nested_set = ynl.attr_sets[nested_set_name] + # Filter out 'unspec' and other unused attrs + nested_names = [n for n in nested_set.attrs.keys() + if nested_set.attrs[n].type != 'unused'] + if nested_names: + print_attr_list(ynl, nested_names, nested_set, indent + 4) + + +def print_mode_attrs(ynl, mode, mode_spec, attr_set, print_request=True): + """Print a given mode (do/dump/event/notify).""" + mode_title = mode.capitalize() + + if print_request and 'request' in mode_spec and 'attributes' in mode_spec['request']: + print(f'\n{mode_title} request attributes:') + print_attr_list(ynl, mode_spec['request']['attributes'], attr_set) + + if 'reply' in mode_spec and 'attributes' in mode_spec['reply']: + print(f'\n{mode_title} reply attributes:') + print_attr_list(ynl, mode_spec['reply']['attributes'], attr_set) + + if 'attributes' in mode_spec: + print(f'\n{mode_title} attributes:') + print_attr_list(ynl, mode_spec['attributes'], attr_set) + + +def main(): + description = """ + YNL CLI utility - a general purpose netlink utility that uses YAML + specs to drive protocol encoding and decoding. + """ + epilog = """ + The --multi option can be repeated to include several do operations + in the same netlink payload. + """ + + parser = argparse.ArgumentParser(description=description, + epilog=epilog) + spec_group = parser.add_mutually_exclusive_group(required=True) + spec_group.add_argument('--family', dest='family', type=str, + help='name of the netlink FAMILY') + spec_group.add_argument('--list-families', action='store_true', + help='list all netlink families supported by YNL (has spec)') + spec_group.add_argument('--spec', dest='spec', type=str, + help='choose the family by SPEC file path') + + parser.add_argument('--schema', dest='schema', type=str) + parser.add_argument('--no-schema', action='store_true') + parser.add_argument('--json', dest='json_text', type=str) + + group = parser.add_mutually_exclusive_group() + group.add_argument('--do', dest='do', metavar='DO-OPERATION', type=str) + group.add_argument('--multi', dest='multi', nargs=2, action='append', + metavar=('DO-OPERATION', 'JSON_TEXT'), type=str) + group.add_argument('--dump', dest='dump', metavar='DUMP-OPERATION', type=str) + group.add_argument('--list-ops', action='store_true') + group.add_argument('--list-msgs', action='store_true') + group.add_argument('--list-attrs', dest='list_attrs', metavar='OPERATION', type=str, + help='List attributes for an operation') + group.add_argument('--validate', action='store_true') + + parser.add_argument('--duration', dest='duration', type=int, + help='when subscribed, watch for DURATION seconds') + parser.add_argument('--sleep', dest='duration', type=int, + help='alias for duration') + parser.add_argument('--subscribe', dest='ntf', type=str) + parser.add_argument('--replace', dest='flags', action='append_const', + const=Netlink.NLM_F_REPLACE) + parser.add_argument('--excl', dest='flags', action='append_const', + const=Netlink.NLM_F_EXCL) + parser.add_argument('--create', dest='flags', action='append_const', + const=Netlink.NLM_F_CREATE) + parser.add_argument('--append', dest='flags', action='append_const', + const=Netlink.NLM_F_APPEND) + parser.add_argument('--process-unknown', action=argparse.BooleanOptionalAction) + parser.add_argument('--output-json', action='store_true') + parser.add_argument('--dbg-small-recv', default=0, const=4000, + action='store', nargs='?', type=int) + args = parser.parse_args() + + def output(msg): + if args.output_json: + print(json.dumps(msg, cls=YnlEncoder)) + else: + pprint.PrettyPrinter().pprint(msg) + + if args.list_families: + for filename in sorted(os.listdir(spec_dir())): + if filename.endswith('.yaml'): + print(filename.removesuffix('.yaml')) + return + + if args.no_schema: + args.schema = '' + + attrs = {} + if args.json_text: + attrs = json.loads(args.json_text) + + if args.family: + spec = f"{spec_dir()}/{args.family}.yaml" + else: + spec = args.spec + if not os.path.isfile(spec): + raise Exception(f"Spec file {spec} does not exist") + + if args.validate: + try: + SpecFamily(spec, args.schema) + except Exception as error: + print(error) + exit(1) + return + + if args.family: # set behaviour when using installed specs + if args.schema is None and spec.startswith(sys_schema_dir): + args.schema = '' # disable schema validation when installed + if args.process_unknown is None: + args.process_unknown = True + + ynl = YnlFamily(spec, args.schema, args.process_unknown, + recv_size=args.dbg_small_recv) + if args.dbg_small_recv: + ynl.set_recv_dbg(True) + + if args.ntf: + ynl.ntf_subscribe(args.ntf) + + if args.list_ops: + for op_name, op in ynl.ops.items(): + print(op_name, " [", ", ".join(op.modes), "]") + if args.list_msgs: + for op_name, op in ynl.msgs.items(): + print(op_name, " [", ", ".join(op.modes), "]") + + if args.list_attrs: + op = ynl.msgs.get(args.list_attrs) + if not op: + print(f'Operation {args.list_attrs} not found') + exit(1) + + print(f'Operation: {op.name}') + print(op.yaml['doc']) + + for mode in ['do', 'dump', 'event']: + if mode in op.yaml: + print_mode_attrs(ynl, mode, op.yaml[mode], op.attr_set, True) + + if 'notify' in op.yaml: + mode_spec = op.yaml['notify'] + ref_spec = ynl.msgs.get(mode_spec).yaml.get('do') + if ref_spec: + print_mode_attrs(ynl, 'notify', ref_spec, op.attr_set, False) + + if 'mcgrp' in op.yaml: + print(f"\nMulticast group: {op.yaml['mcgrp']}") + + try: + if args.do: + reply = ynl.do(args.do, attrs, args.flags) + output(reply) + if args.dump: + reply = ynl.dump(args.dump, attrs) + output(reply) + if args.multi: + ops = [ (item[0], json.loads(item[1]), args.flags or []) for item in args.multi ] + reply = ynl.do_multi(ops) + output(reply) + + if args.ntf: + for msg in ynl.poll_ntf(duration=args.duration): + output(msg) + except NlError as e: + print(e) + exit(1) + except KeyboardInterrupt: + pass + except BrokenPipeError: + pass + + +if __name__ == "__main__": + main() diff --git a/tools/net/ynl/ethtool.py b/tools/net/ynl/pyynl/ethtool.py index 6c9f7e31250c..fd0f6b8d54d1 100755 --- a/tools/net/ynl/ethtool.py +++ b/tools/net/ynl/pyynl/ethtool.py @@ -2,12 +2,15 @@ # SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause import argparse -import json +import pathlib import pprint import sys import re +import os +sys.path.append(pathlib.Path(__file__).resolve().parent.as_posix()) from lib import YnlFamily +from cli import schema_dir, spec_dir def args_to_req(ynl, op_name, args, req): """ @@ -41,13 +44,16 @@ def print_field(reply, *desc): Pretty-print a set of fields from the reply. desc specifies the fields and the optional type (bool/yn). """ + if not reply: + return + if len(desc) == 0: return print_field(reply, *zip(reply.keys(), reply.keys())) for spec in desc: try: field, name, tp = spec - except: + except ValueError: field, name = spec tp = 'int' @@ -152,8 +158,8 @@ def main(): global args args = parser.parse_args() - spec = '../../../Documentation/netlink/specs/ethtool.yaml' - schema = '../../../Documentation/netlink/genetlink-legacy.yaml' + spec = os.path.join(spec_dir(), 'ethtool.yaml') + schema = os.path.join(schema_dir(), 'genetlink-legacy.yaml') ynl = YnlFamily(spec, schema) @@ -250,14 +256,14 @@ def main(): reply = dumpit(ynl, args, 'channels-get') print(f'Channel parameters for {args.device}:') - print(f'Pre-set maximums:') + print('Pre-set maximums:') print_field(reply, ('rx-max', 'RX'), ('tx-max', 'TX'), ('other-max', 'Other'), ('combined-max', 'Combined')) - print(f'Current hardware settings:') + print('Current hardware settings:') print_field(reply, ('rx-count', 'RX'), ('tx-count', 'TX'), @@ -271,14 +277,14 @@ def main(): print(f'Ring parameters for {args.device}:') - print(f'Pre-set maximums:') + print('Pre-set maximums:') print_field(reply, ('rx-max', 'RX'), ('rx-mini-max', 'RX Mini'), ('rx-jumbo-max', 'RX Jumbo'), ('tx-max', 'TX')) - print(f'Current hardware settings:') + print('Current hardware settings:') print_field(reply, ('rx', 'RX'), ('rx-mini', 'RX Mini'), @@ -293,7 +299,7 @@ def main(): return if args.statistics: - print(f'NIC statistics:') + print('NIC statistics:') # TODO: pass id? strset = dumpit(ynl, args, 'strset-get') @@ -320,20 +326,37 @@ def main(): return if args.show_time_stamping: - tsinfo = dumpit(ynl, args, 'tsinfo-get') + req = { + 'header': { + 'flags': 'stats', + }, + } + + tsinfo = dumpit(ynl, args, 'tsinfo-get', req) print(f'Time stamping parameters for {args.device}:') print('Capabilities:') [print(f'\t{v}') for v in bits_to_dict(tsinfo['timestamping'])] - print(f'PTP Hardware Clock: {tsinfo["phc-index"]}') + print(f'PTP Hardware Clock: {tsinfo.get("phc-index", "none")}') + + if 'tx-types' in tsinfo: + print('Hardware Transmit Timestamp Modes:') + [print(f'\t{v}') for v in bits_to_dict(tsinfo['tx-types'])] + else: + print('Hardware Transmit Timestamp Modes: none') + + if 'rx-filters' in tsinfo: + print('Hardware Receive Filter Modes:') + [print(f'\t{v}') for v in bits_to_dict(tsinfo['rx-filters'])] + else: + print('Hardware Receive Filter Modes: none') - print('Hardware Transmit Timestamp Modes:') - [print(f'\t{v}') for v in bits_to_dict(tsinfo['tx-types'])] + if 'stats' in tsinfo and tsinfo['stats']: + print('Statistics:') + [print(f'\t{k}: {v}') for k, v in tsinfo['stats'].items()] - print('Hardware Receive Filter Modes:') - [print(f'\t{v}') for v in bits_to_dict(tsinfo['rx-filters'])] return print(f'Settings for {args.device}:') diff --git a/tools/net/ynl/pyynl/lib/__init__.py b/tools/net/ynl/pyynl/lib/__init__.py new file mode 100644 index 000000000000..ec9ea00071be --- /dev/null +++ b/tools/net/ynl/pyynl/lib/__init__.py @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause + +from .nlspec import SpecAttr, SpecAttrSet, SpecEnumEntry, SpecEnumSet, \ + SpecFamily, SpecOperation, SpecSubMessage, SpecSubMessageFormat +from .ynl import YnlFamily, Netlink, NlError + +from .doc_generator import YnlDocGenerator + +__all__ = ["SpecAttr", "SpecAttrSet", "SpecEnumEntry", "SpecEnumSet", + "SpecFamily", "SpecOperation", "SpecSubMessage", "SpecSubMessageFormat", + "YnlFamily", "Netlink", "NlError", "YnlDocGenerator"] diff --git a/tools/net/ynl/pyynl/lib/doc_generator.py b/tools/net/ynl/pyynl/lib/doc_generator.py new file mode 100644 index 000000000000..3a16b8eb01ca --- /dev/null +++ b/tools/net/ynl/pyynl/lib/doc_generator.py @@ -0,0 +1,402 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0 +# -*- coding: utf-8; mode: python -*- + +""" + Class to auto generate the documentation for Netlink specifications. + + :copyright: Copyright (C) 2023 Breno Leitao <leitao@debian.org> + :license: GPL Version 2, June 1991 see linux/COPYING for details. + + This class performs extensive parsing to the Linux kernel's netlink YAML + spec files, in an effort to avoid needing to heavily mark up the original + YAML file. + + This code is split in two classes: + 1) RST formatters: Use to convert a string to a RST output + 2) YAML Netlink (YNL) doc generator: Generate docs from YAML data +""" + +from typing import Any, Dict, List +import yaml + +LINE_STR = '__lineno__' + +class NumberedSafeLoader(yaml.SafeLoader): # pylint: disable=R0901 + """Override the SafeLoader class to add line number to parsed data""" + + def construct_mapping(self, node, *args, **kwargs): + mapping = super().construct_mapping(node, *args, **kwargs) + mapping[LINE_STR] = node.start_mark.line + + return mapping + +class RstFormatters: + """RST Formatters""" + + SPACE_PER_LEVEL = 4 + + @staticmethod + def headroom(level: int) -> str: + """Return space to format""" + return " " * (level * RstFormatters.SPACE_PER_LEVEL) + + @staticmethod + def bold(text: str) -> str: + """Format bold text""" + return f"**{text}**" + + @staticmethod + def inline(text: str) -> str: + """Format inline text""" + return f"``{text}``" + + @staticmethod + def sanitize(text: str) -> str: + """Remove newlines and multiple spaces""" + # This is useful for some fields that are spread across multiple lines + return str(text).replace("\n", " ").strip() + + def rst_fields(self, key: str, value: str, level: int = 0) -> str: + """Return a RST formatted field""" + return self.headroom(level) + f":{key}: {value}" + + def rst_definition(self, key: str, value: Any, level: int = 0) -> str: + """Format a single rst definition""" + return self.headroom(level) + key + "\n" + self.headroom(level + 1) + str(value) + + def rst_paragraph(self, paragraph: str, level: int = 0) -> str: + """Return a formatted paragraph""" + return self.headroom(level) + paragraph + + def rst_bullet(self, item: str, level: int = 0) -> str: + """Return a formatted a bullet""" + return self.headroom(level) + f"- {item}" + + @staticmethod + def rst_subsection(title: str) -> str: + """Add a sub-section to the document""" + return f"{title}\n" + "-" * len(title) + + @staticmethod + def rst_subsubsection(title: str) -> str: + """Add a sub-sub-section to the document""" + return f"{title}\n" + "~" * len(title) + + @staticmethod + def rst_section(namespace: str, prefix: str, title: str) -> str: + """Add a section to the document""" + return f".. _{namespace}-{prefix}-{title}:\n\n{title}\n" + "=" * len(title) + + @staticmethod + def rst_subtitle(title: str) -> str: + """Add a subtitle to the document""" + return "\n" + "-" * len(title) + f"\n{title}\n" + "-" * len(title) + "\n\n" + + @staticmethod + def rst_title(title: str) -> str: + """Add a title to the document""" + return "=" * len(title) + f"\n{title}\n" + "=" * len(title) + "\n\n" + + def rst_list_inline(self, list_: List[str], level: int = 0) -> str: + """Format a list using inlines""" + return self.headroom(level) + "[" + ", ".join(self.inline(i) for i in list_) + "]" + + @staticmethod + def rst_ref(namespace: str, prefix: str, name: str) -> str: + """Add a hyperlink to the document""" + mappings = {'enum': 'definition', + 'fixed-header': 'definition', + 'nested-attributes': 'attribute-set', + 'struct': 'definition'} + if prefix in mappings: + prefix = mappings[prefix] + return f":ref:`{namespace}-{prefix}-{name}`" + + def rst_header(self) -> str: + """The headers for all the auto generated RST files""" + lines = [] + + lines.append(self.rst_paragraph(".. SPDX-License-Identifier: GPL-2.0")) + lines.append(self.rst_paragraph(".. NOTE: This document was auto-generated.\n\n")) + + return "\n".join(lines) + + @staticmethod + def rst_toctree(maxdepth: int = 2) -> str: + """Generate a toctree RST primitive""" + lines = [] + + lines.append(".. toctree::") + lines.append(f" :maxdepth: {maxdepth}\n\n") + + return "\n".join(lines) + + @staticmethod + def rst_label(title: str) -> str: + """Return a formatted label""" + return f".. _{title}:\n\n" + + @staticmethod + def rst_lineno(lineno: int) -> str: + """Return a lineno comment""" + return f".. LINENO {lineno}\n" + +class YnlDocGenerator: + """YAML Netlink specs Parser""" + + fmt = RstFormatters() + + def parse_mcast_group(self, mcast_group: List[Dict[str, Any]]) -> str: + """Parse 'multicast' group list and return a formatted string""" + lines = [] + for group in mcast_group: + lines.append(self.fmt.rst_bullet(group["name"])) + + return "\n".join(lines) + + def parse_do(self, do_dict: Dict[str, Any], level: int = 0) -> str: + """Parse 'do' section and return a formatted string""" + lines = [] + if LINE_STR in do_dict: + lines.append(self.fmt.rst_lineno(do_dict[LINE_STR])) + + for key in do_dict.keys(): + if key == LINE_STR: + continue + lines.append(self.fmt.rst_paragraph(self.fmt.bold(key), level + 1)) + if key in ['request', 'reply']: + lines.append(self.parse_do_attributes(do_dict[key], level + 1) + "\n") + else: + lines.append(self.fmt.headroom(level + 2) + do_dict[key] + "\n") + + return "\n".join(lines) + + def parse_do_attributes(self, attrs: Dict[str, Any], level: int = 0) -> str: + """Parse 'attributes' section""" + if "attributes" not in attrs: + return "" + lines = [self.fmt.rst_fields("attributes", + self.fmt.rst_list_inline(attrs["attributes"]), + level + 1)] + + return "\n".join(lines) + + def parse_operations(self, operations: List[Dict[str, Any]], namespace: str) -> str: + """Parse operations block""" + preprocessed = ["name", "doc", "title", "do", "dump", "flags"] + linkable = ["fixed-header", "attribute-set"] + lines = [] + + for operation in operations: + if LINE_STR in operation: + lines.append(self.fmt.rst_lineno(operation[LINE_STR])) + + lines.append(self.fmt.rst_section(namespace, 'operation', + operation["name"])) + lines.append(self.fmt.rst_paragraph(operation["doc"]) + "\n") + + for key in operation.keys(): + if key == LINE_STR: + continue + + if key in preprocessed: + # Skip the special fields + continue + value = operation[key] + if key in linkable: + value = self.fmt.rst_ref(namespace, key, value) + lines.append(self.fmt.rst_fields(key, value, 0)) + if 'flags' in operation: + lines.append(self.fmt.rst_fields('flags', + self.fmt.rst_list_inline(operation['flags']))) + + if "do" in operation: + lines.append(self.fmt.rst_paragraph(":do:", 0)) + lines.append(self.parse_do(operation["do"], 0)) + if "dump" in operation: + lines.append(self.fmt.rst_paragraph(":dump:", 0)) + lines.append(self.parse_do(operation["dump"], 0)) + + # New line after fields + lines.append("\n") + + return "\n".join(lines) + + def parse_entries(self, entries: List[Dict[str, Any]], level: int) -> str: + """Parse a list of entries""" + ignored = ["pad"] + lines = [] + for entry in entries: + if isinstance(entry, dict): + # entries could be a list or a dictionary + field_name = entry.get("name", "") + if field_name in ignored: + continue + type_ = entry.get("type") + if type_: + field_name += f" ({self.fmt.inline(type_)})" + lines.append( + self.fmt.rst_fields(field_name, + self.fmt.sanitize(entry.get("doc", "")), + level) + ) + elif isinstance(entry, list): + lines.append(self.fmt.rst_list_inline(entry, level)) + else: + lines.append(self.fmt.rst_bullet(self.fmt.inline(self.fmt.sanitize(entry)), + level)) + + lines.append("\n") + return "\n".join(lines) + + def parse_definitions(self, defs: Dict[str, Any], namespace: str) -> str: + """Parse definitions section""" + preprocessed = ["name", "entries", "members"] + ignored = ["render-max"] # This is not printed + lines = [] + + for definition in defs: + if LINE_STR in definition: + lines.append(self.fmt.rst_lineno(definition[LINE_STR])) + + lines.append(self.fmt.rst_section(namespace, 'definition', definition["name"])) + for k in definition.keys(): + if k == LINE_STR: + continue + if k in preprocessed + ignored: + continue + lines.append(self.fmt.rst_fields(k, self.fmt.sanitize(definition[k]), 0)) + + # Field list needs to finish with a new line + lines.append("\n") + if "entries" in definition: + lines.append(self.fmt.rst_paragraph(":entries:", 0)) + lines.append(self.parse_entries(definition["entries"], 1)) + if "members" in definition: + lines.append(self.fmt.rst_paragraph(":members:", 0)) + lines.append(self.parse_entries(definition["members"], 1)) + + return "\n".join(lines) + + def parse_attr_sets(self, entries: List[Dict[str, Any]], namespace: str) -> str: + """Parse attribute from attribute-set""" + preprocessed = ["name", "type"] + linkable = ["enum", "nested-attributes", "struct", "sub-message"] + ignored = ["checks"] + lines = [] + + for entry in entries: + lines.append(self.fmt.rst_section(namespace, 'attribute-set', + entry["name"])) + + if "doc" in entry: + lines.append(self.fmt.rst_paragraph(entry["doc"], 0) + "\n") + + for attr in entry["attributes"]: + if LINE_STR in attr: + lines.append(self.fmt.rst_lineno(attr[LINE_STR])) + + type_ = attr.get("type") + attr_line = attr["name"] + if type_: + # Add the attribute type in the same line + attr_line += f" ({self.fmt.inline(type_)})" + + lines.append(self.fmt.rst_subsubsection(attr_line)) + + for k in attr.keys(): + if k == LINE_STR: + continue + if k in preprocessed + ignored: + continue + if k in linkable: + value = self.fmt.rst_ref(namespace, k, attr[k]) + else: + value = self.fmt.sanitize(attr[k]) + lines.append(self.fmt.rst_fields(k, value, 0)) + lines.append("\n") + + return "\n".join(lines) + + def parse_sub_messages(self, entries: List[Dict[str, Any]], namespace: str) -> str: + """Parse sub-message definitions""" + lines = [] + + for entry in entries: + lines.append(self.fmt.rst_section(namespace, 'sub-message', + entry["name"])) + for fmt in entry["formats"]: + value = fmt["value"] + + lines.append(self.fmt.rst_bullet(self.fmt.bold(value))) + for attr in ['fixed-header', 'attribute-set']: + if attr in fmt: + lines.append(self.fmt.rst_fields(attr, + self.fmt.rst_ref(namespace, + attr, + fmt[attr]), + 1)) + lines.append("\n") + + return "\n".join(lines) + + def parse_yaml(self, obj: Dict[str, Any]) -> str: + """Format the whole YAML into a RST string""" + lines = [] + + # Main header + lineno = obj.get('__lineno__', 0) + lines.append(self.fmt.rst_lineno(lineno)) + + family = obj['name'] + + lines.append(self.fmt.rst_header()) + lines.append(self.fmt.rst_label("netlink-" + family)) + + title = f"Family ``{family}`` netlink specification" + lines.append(self.fmt.rst_title(title)) + lines.append(self.fmt.rst_paragraph(".. contents:: :depth: 3\n")) + + if "doc" in obj: + lines.append(self.fmt.rst_subtitle("Summary")) + lines.append(self.fmt.rst_paragraph(obj["doc"], 0)) + + # Operations + if "operations" in obj: + lines.append(self.fmt.rst_subtitle("Operations")) + lines.append(self.parse_operations(obj["operations"]["list"], + family)) + + # Multicast groups + if "mcast-groups" in obj: + lines.append(self.fmt.rst_subtitle("Multicast groups")) + lines.append(self.parse_mcast_group(obj["mcast-groups"]["list"])) + + # Definitions + if "definitions" in obj: + lines.append(self.fmt.rst_subtitle("Definitions")) + lines.append(self.parse_definitions(obj["definitions"], family)) + + # Attributes set + if "attribute-sets" in obj: + lines.append(self.fmt.rst_subtitle("Attribute sets")) + lines.append(self.parse_attr_sets(obj["attribute-sets"], family)) + + # Sub-messages + if "sub-messages" in obj: + lines.append(self.fmt.rst_subtitle("Sub-messages")) + lines.append(self.parse_sub_messages(obj["sub-messages"], family)) + + return "\n".join(lines) + + # Main functions + # ============== + + def parse_yaml_file(self, filename: str) -> str: + """Transform the YAML specified by filename into an RST-formatted string""" + with open(filename, "r", encoding="utf-8") as spec_file: + numbered_yaml = yaml.load(spec_file, Loader=NumberedSafeLoader) + content = self.parse_yaml(numbered_yaml) + + return content diff --git a/tools/net/ynl/lib/nlspec.py b/tools/net/ynl/pyynl/lib/nlspec.py index 37bcb4d8b37b..85c17fe01e35 100644 --- a/tools/net/ynl/lib/nlspec.py +++ b/tools/net/ynl/pyynl/lib/nlspec.py @@ -131,6 +131,9 @@ class SpecEnumSet(SpecElement): def has_doc(self): if 'doc' in self.yaml: return True + return self.has_entry_doc() + + def has_entry_doc(self): for entry in self.entries.values(): if entry.has_doc(): return True @@ -144,11 +147,12 @@ class SpecEnumSet(SpecElement): class SpecAttr(SpecElement): - """ Single Netlink atttribute type + """ Single Netlink attribute type Represents a single attribute type within an attr space. Attributes: + type string, attribute type value numerical ID when serialized attr_set Attribute Set containing this attr is_multi bool, attr may repeat multiple times @@ -157,10 +161,16 @@ 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 """ def __init__(self, family, attr_set, yaml, value): super().__init__(family, yaml) + self.type = yaml['type'] self.value = value self.attr_set = attr_set self.is_multi = yaml.get('multi-attr', False) @@ -169,6 +179,10 @@ 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" class SpecAttrSet(SpecElement): @@ -205,7 +219,10 @@ class SpecAttrSet(SpecElement): else: real_set = family.attr_sets[self.subset_of] for elem in self.yaml['attributes']: - attr = real_set[elem['name']] + real_attr = real_set[elem['name']] + combined_elem = real_attr.yaml | elem + attr = self.new_attr(combined_elem, real_attr.value) + self.attrs[attr.name] = attr self.attrs_by_val[attr.value] = attr @@ -237,6 +254,7 @@ class SpecStructMember(SpecElement): len integer, optional byte length of binary types display_hint string, hint to help choose format specifier when displaying the value + struct string, name of nested struct type """ def __init__(self, family, yaml): super().__init__(family, yaml) @@ -245,6 +263,7 @@ class SpecStructMember(SpecElement): self.enum = yaml.get('enum') self.len = yaml.get('len') self.display_hint = yaml.get('display-hint') + self.struct = yaml.get('struct') class SpecStruct(SpecElement): @@ -272,6 +291,46 @@ 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 format definition + + Represents a single format for a sub-message. + + 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 @@ -282,6 +341,7 @@ class SpecOperation(SpecElement): req_value numerical ID when serialized, user -> kernel rsp_value numerical ID when serialized, user <- kernel + modes supported operation modes (do, dump, event etc.) is_call bool, whether the operation is a call is_async bool, whether the operation is a notification is_resv bool, whether the operation does not exist (it's just a reserved ID) @@ -297,6 +357,7 @@ class SpecOperation(SpecElement): self.req_value = req_value self.rsp_value = rsp_value + self.modes = yaml.keys() & {'do', 'dump', 'event', 'notify'} self.is_call = 'do' in yaml or 'dump' in yaml self.is_async = 'notify' in yaml or 'event' in yaml self.is_resv = not self.is_async and not self.is_call @@ -359,11 +420,13 @@ 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 fixed_header string, optional name of family default fixed header struct mcast_groups dict of all multicast groups (index by name) + kernel_family dict of kernel family attributes """ def __init__(self, spec_path, schema_path=None, exclude_ops=None): with open(spec_path, "r") as stream: @@ -399,6 +462,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() @@ -406,6 +470,7 @@ class SpecFamily(SpecElement): self.ntfs = collections.OrderedDict() self.consts = collections.OrderedDict() self.mcast_groups = collections.OrderedDict() + self.kernel_family = collections.OrderedDict(self.yaml.get('kernel-family', {})) last_exception = None while len(self._resolution_list) > 0: @@ -435,6 +500,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) @@ -523,6 +591,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': diff --git a/tools/net/ynl/pyynl/lib/ynl.py b/tools/net/ynl/pyynl/lib/ynl.py new file mode 100644 index 000000000000..36d36eb7e3b8 --- /dev/null +++ b/tools/net/ynl/pyynl/lib/ynl.py @@ -0,0 +1,1168 @@ +# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause + +from collections import namedtuple +from enum import Enum +import functools +import os +import random +import socket +import struct +from struct import Struct +import sys +import ipaddress +import uuid +import queue +import selectors +import time + +from .nlspec import SpecFamily + +# +# Generic Netlink code which should really be in some library, but I can't quickly find one. +# + + +class Netlink: + # Netlink socket + SOL_NETLINK = 270 + + NETLINK_ADD_MEMBERSHIP = 1 + NETLINK_CAP_ACK = 10 + NETLINK_EXT_ACK = 11 + NETLINK_GET_STRICT_CHK = 12 + + # Netlink message + NLMSG_ERROR = 2 + NLMSG_DONE = 3 + + NLM_F_REQUEST = 1 + NLM_F_ACK = 4 + NLM_F_ROOT = 0x100 + NLM_F_MATCH = 0x200 + + NLM_F_REPLACE = 0x100 + NLM_F_EXCL = 0x200 + NLM_F_CREATE = 0x400 + NLM_F_APPEND = 0x800 + + NLM_F_CAPPED = 0x100 + NLM_F_ACK_TLVS = 0x200 + + NLM_F_DUMP = NLM_F_ROOT | NLM_F_MATCH + + NLA_F_NESTED = 0x8000 + NLA_F_NET_BYTEORDER = 0x4000 + + NLA_TYPE_MASK = NLA_F_NESTED | NLA_F_NET_BYTEORDER + + # Genetlink defines + NETLINK_GENERIC = 16 + + GENL_ID_CTRL = 0x10 + + # nlctrl + CTRL_CMD_GETFAMILY = 3 + + CTRL_ATTR_FAMILY_ID = 1 + CTRL_ATTR_FAMILY_NAME = 2 + CTRL_ATTR_MAXATTR = 5 + CTRL_ATTR_MCAST_GROUPS = 7 + + CTRL_ATTR_MCAST_GRP_NAME = 1 + CTRL_ATTR_MCAST_GRP_ID = 2 + + # Extack types + NLMSGERR_ATTR_MSG = 1 + NLMSGERR_ATTR_OFFS = 2 + NLMSGERR_ATTR_COOKIE = 3 + NLMSGERR_ATTR_POLICY = 4 + NLMSGERR_ATTR_MISS_TYPE = 5 + NLMSGERR_ATTR_MISS_NEST = 6 + + # Policy types + NL_POLICY_TYPE_ATTR_TYPE = 1 + NL_POLICY_TYPE_ATTR_MIN_VALUE_S = 2 + NL_POLICY_TYPE_ATTR_MAX_VALUE_S = 3 + NL_POLICY_TYPE_ATTR_MIN_VALUE_U = 4 + NL_POLICY_TYPE_ATTR_MAX_VALUE_U = 5 + NL_POLICY_TYPE_ATTR_MIN_LENGTH = 6 + NL_POLICY_TYPE_ATTR_MAX_LENGTH = 7 + NL_POLICY_TYPE_ATTR_POLICY_IDX = 8 + NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE = 9 + NL_POLICY_TYPE_ATTR_BITFIELD32_MASK = 10 + NL_POLICY_TYPE_ATTR_PAD = 11 + NL_POLICY_TYPE_ATTR_MASK = 12 + + AttrType = Enum('AttrType', ['flag', 'u8', 'u16', 'u32', 'u64', + 's8', 's16', 's32', 's64', + 'binary', 'string', 'nul-string', + 'nested', 'nested-array', + 'bitfield32', 'sint', 'uint']) + +class NlError(Exception): + def __init__(self, nl_msg): + self.nl_msg = nl_msg + self.error = -nl_msg.error + + def __str__(self): + msg = "Netlink error: " + + extack = self.nl_msg.extack.copy() if self.nl_msg.extack else {} + if 'msg' in extack: + msg += extack['msg'] + ': ' + del extack['msg'] + msg += os.strerror(self.error) + if extack: + msg += ' ' + str(extack) + return msg + + +class ConfigError(Exception): + pass + + +class NlAttr: + ScalarFormat = namedtuple('ScalarFormat', ['native', 'big', 'little']) + type_formats = { + 'u8' : ScalarFormat(Struct('B'), Struct("B"), Struct("B")), + 's8' : ScalarFormat(Struct('b'), Struct("b"), Struct("b")), + 'u16': ScalarFormat(Struct('H'), Struct(">H"), Struct("<H")), + 's16': ScalarFormat(Struct('h'), Struct(">h"), Struct("<h")), + 'u32': ScalarFormat(Struct('I'), Struct(">I"), Struct("<I")), + 's32': ScalarFormat(Struct('i'), Struct(">i"), Struct("<i")), + 'u64': ScalarFormat(Struct('Q'), Struct(">Q"), Struct("<Q")), + 's64': ScalarFormat(Struct('q'), Struct(">q"), Struct("<q")) + } + + def __init__(self, raw, offset): + 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] + + @classmethod + def get_format(cls, attr_type, byte_order=None): + format = cls.type_formats[attr_type] + if byte_order: + return format.big if byte_order == "big-endian" \ + else format.little + return format.native + + def as_scalar(self, attr_type, byte_order=None): + format = self.get_format(attr_type, byte_order) + return format.unpack(self.raw)[0] + + def as_auto_scalar(self, attr_type, byte_order=None): + if len(self.raw) != 4 and len(self.raw) != 8: + raise Exception(f"Auto-scalar len payload be 4 or 8 bytes, got {len(self.raw)}") + real_type = attr_type[0] + str(len(self.raw) * 8) + format = self.get_format(real_type, byte_order) + return format.unpack(self.raw)[0] + + def as_strz(self): + return self.raw.decode('ascii')[:-1] + + def as_bin(self): + return self.raw + + def as_c_array(self, type): + format = self.get_format(type) + return [ x[0] for x in format.iter_unpack(self.raw) ] + + def __repr__(self): + return f"[type:{self.type} len:{self._len}] {self.raw}" + + +class NlAttrs: + def __init__(self, msg, offset=0): + self.attrs = [] + + while offset < len(msg): + attr = NlAttr(msg, offset) + offset += attr.full_len + self.attrs.append(attr) + + def __iter__(self): + yield from self.attrs + + def __repr__(self): + msg = '' + for a in self.attrs: + if msg: + msg += '\n' + msg += repr(a) + return msg + + +class NlMsg: + def __init__(self, msg, offset, attr_space=None): + 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.error = 0 + self.done = 0 + + extack_off = None + if self.nl_type == Netlink.NLMSG_ERROR: + self.error = struct.unpack("i", self.raw[0:4])[0] + self.done = 1 + extack_off = 20 + elif self.nl_type == Netlink.NLMSG_DONE: + self.error = struct.unpack("i", self.raw[0:4])[0] + self.done = 1 + extack_off = 4 + + self.extack = None + if self.nl_flags & Netlink.NLM_F_ACK_TLVS and extack_off: + self.extack = dict() + extack_attrs = NlAttrs(self.raw[extack_off:]) + for extack in extack_attrs: + if extack.type == Netlink.NLMSGERR_ATTR_MSG: + self.extack['msg'] = extack.as_strz() + elif extack.type == Netlink.NLMSGERR_ATTR_MISS_TYPE: + self.extack['miss-type'] = extack.as_scalar('u32') + elif extack.type == Netlink.NLMSGERR_ATTR_MISS_NEST: + self.extack['miss-nest'] = extack.as_scalar('u32') + elif extack.type == Netlink.NLMSGERR_ATTR_OFFS: + self.extack['bad-attr-offs'] = extack.as_scalar('u32') + elif extack.type == Netlink.NLMSGERR_ATTR_POLICY: + self.extack['policy'] = self._decode_policy(extack.raw) + else: + if 'unknown' not in self.extack: + self.extack['unknown'] = [] + self.extack['unknown'].append(extack) + + if attr_space: + self.annotate_extack(attr_space) + + def _decode_policy(self, raw): + policy = {} + for attr in NlAttrs(raw): + if attr.type == Netlink.NL_POLICY_TYPE_ATTR_TYPE: + type = attr.as_scalar('u32') + policy['type'] = Netlink.AttrType(type).name + elif attr.type == Netlink.NL_POLICY_TYPE_ATTR_MIN_VALUE_S: + policy['min-value'] = attr.as_scalar('s64') + elif attr.type == Netlink.NL_POLICY_TYPE_ATTR_MAX_VALUE_S: + policy['max-value'] = attr.as_scalar('s64') + elif attr.type == Netlink.NL_POLICY_TYPE_ATTR_MIN_VALUE_U: + policy['min-value'] = attr.as_scalar('u64') + elif attr.type == Netlink.NL_POLICY_TYPE_ATTR_MAX_VALUE_U: + policy['max-value'] = attr.as_scalar('u64') + elif attr.type == Netlink.NL_POLICY_TYPE_ATTR_MIN_LENGTH: + policy['min-length'] = attr.as_scalar('u32') + elif attr.type == Netlink.NL_POLICY_TYPE_ATTR_MAX_LENGTH: + policy['max-length'] = attr.as_scalar('u32') + elif attr.type == Netlink.NL_POLICY_TYPE_ATTR_BITFIELD32_MASK: + policy['bitfield32-mask'] = attr.as_scalar('u32') + elif attr.type == Netlink.NL_POLICY_TYPE_ATTR_MASK: + policy['mask'] = attr.as_scalar('u64') + return policy + + def annotate_extack(self, attr_space): + """ Make extack more human friendly with attribute information """ + + # We don't have the ability to parse nests yet, so only do global + if 'miss-type' in self.extack and 'miss-nest' not in self.extack: + miss_type = self.extack['miss-type'] + if miss_type in attr_space.attrs_by_val: + spec = attr_space.attrs_by_val[miss_type] + self.extack['miss-type'] = spec['name'] + if 'doc' in spec: + self.extack['miss-type-doc'] = spec['doc'] + + def cmd(self): + return self.nl_type + + def __repr__(self): + msg = f"nl_len = {self.nl_len} ({len(self.raw)}) nl_flags = 0x{self.nl_flags:x} nl_type = {self.nl_type}" + if self.error: + msg += '\n\terror: ' + str(self.error) + if self.extack: + msg += '\n\textack: ' + repr(self.extack) + return msg + + +class NlMsgs: + def __init__(self, data): + self.msgs = [] + + offset = 0 + while offset < len(data): + msg = NlMsg(data, offset) + offset += msg.nl_len + self.msgs.append(msg) + + def __iter__(self): + yield from self.msgs + + +genl_family_name_to_id = None + + +def _genl_msg(nl_type, nl_flags, genl_cmd, genl_version, seq=None): + # we prepend length in _genl_msg_finalize() + if seq is None: + seq = random.randint(1, 1024) + nlmsg = struct.pack("HHII", nl_type, nl_flags, seq, 0) + genlmsg = struct.pack("BBH", genl_cmd, genl_version, 0) + return nlmsg + genlmsg + + +def _genl_msg_finalize(msg): + return struct.pack("I", len(msg) + 4) + msg + + +def _genl_load_families(): + with socket.socket(socket.AF_NETLINK, socket.SOCK_RAW, Netlink.NETLINK_GENERIC) as sock: + sock.setsockopt(Netlink.SOL_NETLINK, Netlink.NETLINK_CAP_ACK, 1) + + msg = _genl_msg(Netlink.GENL_ID_CTRL, + Netlink.NLM_F_REQUEST | Netlink.NLM_F_ACK | Netlink.NLM_F_DUMP, + Netlink.CTRL_CMD_GETFAMILY, 1) + msg = _genl_msg_finalize(msg) + + sock.send(msg, 0) + + global genl_family_name_to_id + genl_family_name_to_id = dict() + + while True: + reply = sock.recv(128 * 1024) + nms = NlMsgs(reply) + for nl_msg in nms: + if nl_msg.error: + print("Netlink error:", nl_msg.error) + return + if nl_msg.done: + return + + gm = GenlMsg(nl_msg) + fam = dict() + for attr in NlAttrs(gm.raw): + if attr.type == Netlink.CTRL_ATTR_FAMILY_ID: + fam['id'] = attr.as_scalar('u16') + elif attr.type == Netlink.CTRL_ATTR_FAMILY_NAME: + fam['name'] = attr.as_strz() + elif attr.type == Netlink.CTRL_ATTR_MAXATTR: + fam['maxattr'] = attr.as_scalar('u32') + elif attr.type == Netlink.CTRL_ATTR_MCAST_GROUPS: + fam['mcast'] = dict() + for entry in NlAttrs(attr.raw): + mcast_name = None + mcast_id = None + for entry_attr in NlAttrs(entry.raw): + if entry_attr.type == Netlink.CTRL_ATTR_MCAST_GRP_NAME: + mcast_name = entry_attr.as_strz() + elif entry_attr.type == Netlink.CTRL_ATTR_MCAST_GRP_ID: + mcast_id = entry_attr.as_scalar('u32') + if mcast_name and mcast_id is not None: + fam['mcast'][mcast_name] = mcast_id + if 'name' in fam and 'id' in fam: + genl_family_name_to_id[fam['name']] = fam + + +class GenlMsg: + def __init__(self, nl_msg): + self.nl = nl_msg + self.genl_cmd, self.genl_version, _ = struct.unpack_from("BBH", nl_msg.raw, 0) + self.raw = nl_msg.raw[4:] + + def cmd(self): + return self.genl_cmd + + def __repr__(self): + msg = repr(self.nl) + msg += f"\tgenl_cmd = {self.genl_cmd} genl_ver = {self.genl_version}\n" + for a in self.raw_attrs: + msg += '\t\t' + repr(a) + '\n' + return msg + + +class NetlinkProtocol: + def __init__(self, family_name, proto_num): + self.family_name = family_name + self.proto_num = proto_num + + def _message(self, nl_type, nl_flags, seq=None): + if seq is None: + seq = random.randint(1, 1024) + nlmsg = struct.pack("HHII", nl_type, nl_flags, seq, 0) + return nlmsg + + def message(self, flags, command, version, seq=None): + return self._message(command, flags, seq) + + def _decode(self, nl_msg): + return nl_msg + + def decode(self, ynl, nl_msg, op): + msg = self._decode(nl_msg) + if op is None: + op = ynl.rsp_by_value[msg.cmd()] + fixed_header_size = ynl._struct_size(op.fixed_header) + msg.raw_attrs = NlAttrs(msg.raw, fixed_header_size) + return msg + + def get_mcast_id(self, mcast_name, mcast_groups): + if mcast_name not in mcast_groups: + raise Exception(f'Multicast group "{mcast_name}" not present in the spec') + return mcast_groups[mcast_name].value + + def msghdr_size(self): + return 16 + + +class GenlProtocol(NetlinkProtocol): + def __init__(self, family_name): + super().__init__(family_name, Netlink.NETLINK_GENERIC) + + global genl_family_name_to_id + if genl_family_name_to_id is None: + _genl_load_families() + + self.genl_family = genl_family_name_to_id[family_name] + self.family_id = genl_family_name_to_id[family_name]['id'] + + def message(self, flags, command, version, seq=None): + nlmsg = self._message(self.family_id, flags, seq) + genlmsg = struct.pack("BBH", command, version, 0) + return nlmsg + genlmsg + + def _decode(self, nl_msg): + return GenlMsg(nl_msg) + + def get_mcast_id(self, mcast_name, mcast_groups): + if mcast_name not in self.genl_family['mcast']: + raise Exception(f'Multicast group "{mcast_name}" not present in the family') + return self.genl_family['mcast'][mcast_name] + + def msghdr_size(self): + return super().msghdr_size() + 4 + + +class SpaceAttrs: + SpecValuesPair = namedtuple('SpecValuesPair', ['spec', 'values']) + + def __init__(self, attr_space, attrs, outer = None): + outer_scopes = outer.scopes if outer else [] + inner_scope = self.SpecValuesPair(attr_space, attrs) + self.scopes = [inner_scope] + outer_scopes + + def lookup(self, name): + for scope in self.scopes: + if name in scope.spec: + if name in scope.values: + return scope.values[name] + spec_name = scope.spec.yaml['name'] + raise Exception( + f"No value for '{name}' in attribute space '{spec_name}'") + raise Exception(f"Attribute '{name}' not defined in any attribute-set") + + +# +# YNL implementation details. +# + + +class YnlFamily(SpecFamily): + def __init__(self, def_path, schema=None, process_unknown=False, + recv_size=0): + super().__init__(def_path, schema) + + self.include_raw = False + self.process_unknown = process_unknown + + try: + if self.proto == "netlink-raw": + self.nlproto = NetlinkProtocol(self.yaml['name'], + self.yaml['protonum']) + else: + self.nlproto = GenlProtocol(self.yaml['name']) + except KeyError: + raise Exception(f"Family '{self.yaml['name']}' not supported by the kernel") + + self._recv_dbg = False + # Note that netlink will use conservative (min) message size for + # the first dump recv() on the socket, our setting will only matter + # from the second recv() on. + self._recv_size = recv_size if recv_size else 131072 + # Netlink will always allocate at least PAGE_SIZE - sizeof(skb_shinfo) + # for a message, so smaller receive sizes will lead to truncation. + # Note that the min size for other families may be larger than 4k! + if self._recv_size < 4000: + raise ConfigError() + + self.sock = socket.socket(socket.AF_NETLINK, socket.SOCK_RAW, self.nlproto.proto_num) + self.sock.setsockopt(Netlink.SOL_NETLINK, Netlink.NETLINK_CAP_ACK, 1) + self.sock.setsockopt(Netlink.SOL_NETLINK, Netlink.NETLINK_EXT_ACK, 1) + self.sock.setsockopt(Netlink.SOL_NETLINK, Netlink.NETLINK_GET_STRICT_CHK, 1) + + self.async_msg_ids = set() + self.async_msg_queue = queue.Queue() + + for msg in self.msgs.values(): + if msg.is_async: + self.async_msg_ids.add(msg.rsp_value) + + for op_name, op in self.ops.items(): + bound_f = functools.partial(self._op, op_name) + setattr(self, op.ident_name, bound_f) + + + def ntf_subscribe(self, mcast_name): + mcast_id = self.nlproto.get_mcast_id(mcast_name, self.mcast_groups) + self.sock.bind((0, 0)) + self.sock.setsockopt(Netlink.SOL_NETLINK, Netlink.NETLINK_ADD_MEMBERSHIP, + mcast_id) + + def set_recv_dbg(self, enabled): + self._recv_dbg = enabled + + def _recv_dbg_print(self, reply, nl_msgs): + if not self._recv_dbg: + return + print("Recv: read", len(reply), "bytes,", + len(nl_msgs.msgs), "messages", file=sys.stderr) + for nl_msg in nl_msgs: + print(" ", nl_msg, file=sys.stderr) + + def _encode_enum(self, attr_spec, value): + enum = self.consts[attr_spec['enum']] + if enum.type == 'flags' or attr_spec.get('enum-as-flags', False): + scalar = 0 + if isinstance(value, str): + value = [value] + for single_value in value: + scalar += enum.entries[single_value].user_value(as_flags = True) + return scalar + else: + return enum.entries[value].user_value() + + def _get_scalar(self, attr_spec, value): + try: + return int(value) + except (ValueError, TypeError) as e: + 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: + attr = self.attr_sets[space][name] + except KeyError: + raise Exception(f"Space '{space}' has no attribute '{name}'") + nl_type = attr.value + + if attr.is_multi and isinstance(value, list): + attr_payload = b'' + for subvalue in value: + attr_payload += self._add_attr(space, name, subvalue, search_attrs) + return attr_payload + + if attr["type"] == 'nest': + nl_type |= Netlink.NLA_F_NESTED + sub_space = attr['nested-attributes'] + 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. + return b'' + attr_payload = b'' + elif attr["type"] == 'string': + attr_payload = str(value).encode('ascii') + b'\x00' + elif attr["type"] == 'binary': + if value is None: + attr_payload = b'' + elif isinstance(value, bytes): + attr_payload = value + elif isinstance(value, str): + 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) + elif isinstance(value, list) and attr.sub_type in NlAttr.type_formats: + format = NlAttr.get_format(attr.sub_type) + attr_payload = b''.join([format.pack(x) for x in value]) + else: + raise Exception(f'Unknown type for binary attribute, value: {value}') + elif attr['type'] in NlAttr.type_formats or attr.is_auto_scalar: + scalar = self._get_scalar(attr, value) + if attr.is_auto_scalar: + attr_type = attr["type"][0] + ('32' if scalar.bit_length() <= 32 else '64') + else: + attr_type = attr["type"] + format = NlAttr.get_format(attr_type, attr.byte_order) + attr_payload = format.pack(scalar) + elif attr['type'] in "bitfield32": + scalar_value = self._get_scalar(attr, value["value"]) + scalar_selector = self._get_scalar(attr, value["selector"]) + attr_payload = struct.pack("II", scalar_value, scalar_selector) + elif attr['type'] == 'sub-message': + msg_format, _ = self._resolve_selector(attr, search_attrs) + attr_payload = b'' + if msg_format.fixed_header: + attr_payload += self._encode_struct(msg_format.fixed_header, value) + if msg_format.attr_set: + if msg_format.attr_set in self.attr_sets: + nl_type |= Netlink.NLA_F_NESTED + sub_attrs = SpaceAttrs(msg_format.attr_set, value, search_attrs) + for subname, subvalue in value.items(): + attr_payload += self._add_attr(msg_format.attr_set, + subname, subvalue, sub_attrs) + else: + raise Exception(f"Unknown attribute-set '{msg_format.attr_set}'") + 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 + except KeyError as error: + if self.process_unknown: + name = f"Unknown({raw})" + else: + raise error + return name + + def _decode_enum(self, raw, attr_spec): + enum = self.consts[attr_spec['enum']] + if enum.type == 'flags' or attr_spec.get('enum-as-flags', False): + i = 0 + value = set() + while raw: + if raw & 1: + value.add(self._get_enum_or_unknown(enum, i)) + raw >>= 1 + i += 1 + else: + value = self._get_enum_or_unknown(enum, raw) + return value + + def _decode_binary(self, attr, attr_spec): + if attr_spec.struct_name: + 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: + decoded = self._formatted_string(decoded, attr_spec.display_hint) + return decoded + + def _decode_array_attr(self, attr, attr_spec): + decoded = [] + offset = 0 + while offset < len(attr.raw): + item = NlAttr(attr.raw, offset) + offset += item.full_len + + if attr_spec["sub-type"] == 'nest': + subattrs = self._decode(NlAttrs(item.raw), attr_spec['nested-attributes']) + decoded.append({ item.type: subattrs }) + elif attr_spec["sub-type"] == 'binary': + subattr = item.as_bin() + if attr_spec.display_hint: + subattr = self._formatted_string(subattr, attr_spec.display_hint) + decoded.append(subattr) + elif attr_spec["sub-type"] in NlAttr.type_formats: + 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 + + 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): + if attr.is_nest: + return self._decode(NlAttrs(attr.raw), None) + else: + return attr.as_bin() + + def _rsp_add(self, rsp, name, is_multi, decoded): + if is_multi is None: + if name in rsp and type(rsp[name]) is not list: + rsp[name] = [rsp[name]] + is_multi = True + else: + is_multi = False + + if not is_multi: + rsp[name] = decoded + elif name in rsp: + rsp[name].append(decoded) + else: + rsp[name] = [decoded] + + def _resolve_selector(self, attr_spec, search_attrs): + 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 + value = search_attrs.lookup(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, value + + def _decode_sub_msg(self, attr, attr_spec, search_attrs): + msg_format, _ = self._resolve_selector(attr_spec, search_attrs) + decoded = {} + offset = 0 + if msg_format.fixed_header: + decoded.update(self._decode_struct(attr.raw, msg_format.fixed_header)) + offset = self._struct_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 '{msg_format.attr_set}' when decoding '{attr_spec.name}'") + return decoded + + def _decode(self, attrs, space, outer_attrs = None): + rsp = dict() + if space: + attr_space = self.attr_sets[space] + search_attrs = SpaceAttrs(attr_space, rsp, outer_attrs) + + for attr in attrs: + try: + attr_spec = attr_space.attrs_by_val[attr.type] + except (KeyError, UnboundLocalError): + if not self.process_unknown: + raise Exception(f"Space '{space}' has no attribute with value '{attr.type}'") + attr_name = f"UnknownAttr({attr.type})" + self._rsp_add(rsp, attr_name, None, self._decode_unknown(attr)) + continue + + try: + if attr_spec["type"] == 'nest': + subdict = self._decode(NlAttrs(attr.raw), attr_spec['nested-attributes'], search_attrs) + decoded = subdict + elif attr_spec["type"] == 'string': + decoded = attr.as_strz() + elif attr_spec["type"] == 'binary': + decoded = self._decode_binary(attr, attr_spec) + elif attr_spec["type"] == 'flag': + decoded = True + elif attr_spec.is_auto_scalar: + decoded = attr.as_auto_scalar(attr_spec['type'], attr_spec.byte_order) + if 'enum' in attr_spec: + decoded = self._decode_enum(decoded, attr_spec) + 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.display_hint: + decoded = self._formatted_string(decoded, attr_spec.display_hint) + elif attr_spec["type"] == 'indexed-array': + decoded = self._decode_array_attr(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} + elif attr_spec["type"] == 'sub-message': + 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: + if not self.process_unknown: + raise Exception(f'Unknown {attr_spec["type"]} with name {attr_spec["name"]}') + decoded = self._decode_unknown(attr) + + self._rsp_add(rsp, attr_spec["name"], attr_spec.is_multi, decoded) + except: + print(f"Error decoding '{attr_spec.name}' from '{space}'") + raise + + return rsp + + def _decode_extack_path(self, attrs, attr_set, offset, target, search_attrs): + for attr in attrs: + try: + attr_spec = attr_set.attrs_by_val[attr.type] + except KeyError: + raise Exception(f"Space '{attr_set.name}' has no attribute with value '{attr.type}'") + if offset > target: + break + if offset == target: + return '.' + attr_spec.name + + if offset + attr.full_len <= target: + offset += attr.full_len + continue + + pathname = attr_spec.name + if attr_spec['type'] == 'nest': + sub_attrs = self.attr_sets[attr_spec['nested-attributes']] + search_attrs = SpaceAttrs(sub_attrs, search_attrs.lookup(attr_spec['name'])) + elif attr_spec['type'] == 'sub-message': + msg_format, value = self._resolve_selector(attr_spec, search_attrs) + if msg_format is None: + raise Exception(f"Can't resolve sub-message of {attr_spec['name']} for extack") + sub_attrs = self.attr_sets[msg_format.attr_set] + pathname += f"({value})" + else: + raise Exception(f"Can't dive into {attr.type} ({attr_spec['name']}) for extack") + offset += 4 + subpath = self._decode_extack_path(NlAttrs(attr.raw), sub_attrs, + offset, target, search_attrs) + if subpath is None: + return None + return '.' + pathname + subpath + + return None + + def _decode_extack(self, request, op, extack, vals): + if 'bad-attr-offs' not in extack: + return + + msg = self.nlproto.decode(self, NlMsg(request, 0, op.attr_set), op) + offset = self.nlproto.msghdr_size() + self._struct_size(op.fixed_header) + search_attrs = SpaceAttrs(op.attr_set, vals) + path = self._decode_extack_path(msg.raw_attrs, op.attr_set, offset, + extack['bad-attr-offs'], search_attrs) + if path: + del extack['bad-attr-offs'] + extack['bad-attr'] = path + + def _struct_size(self, name): + if name: + members = self.consts[name].members + size = 0 + for m in members: + if m.type in ['pad', 'binary']: + if m.struct: + size += self._struct_size(m.struct) + else: + size += m.len + else: + format = NlAttr.get_format(m.type, m.byte_order) + size += format.size + return size + else: + return 0 + + def _decode_struct(self, data, name): + members = self.consts[name].members + attrs = dict() + offset = 0 + for m in members: + value = None + if m.type == 'pad': + offset += m.len + elif m.type == 'binary': + if m.struct: + len = self._struct_size(m.struct) + value = self._decode_struct(data[offset : offset + len], + m.struct) + offset += len + else: + value = data[offset : offset + m.len] + offset += m.len + else: + format = NlAttr.get_format(m.type, m.byte_order) + [ value ] = format.unpack_from(data, offset) + offset += format.size + if value is not None: + if m.enum: + value = self._decode_enum(value, m) + elif m.display_hint: + value = self._formatted_string(value, m.display_hint) + attrs[m.name] = value + return attrs + + def _encode_struct(self, name, vals): + members = self.consts[name].members + attr_payload = b'' + for m in members: + value = vals.pop(m.name) if m.name in vals else None + if m.type == 'pad': + attr_payload += bytearray(m.len) + elif m.type == 'binary': + if m.struct: + if value is None: + value = dict() + attr_payload += self._encode_struct(m.struct, value) + else: + if value is None: + attr_payload += bytearray(m.len) + else: + attr_payload += bytes.fromhex(value) + else: + if value is None: + value = 0 + format = NlAttr.get_format(m.type, m.byte_order) + attr_payload += format.pack(value) + return attr_payload + + def _formatted_string(self, raw, display_hint): + if display_hint == 'mac': + formatted = ':'.join('%02x' % b for b in raw) + elif display_hint == 'hex': + if isinstance(raw, int): + formatted = hex(raw) + else: + formatted = bytes.hex(raw, ' ') + 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)) + else: + formatted = raw + return formatted + + def _from_string(self, string, attr_spec): + 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) + elif attr_spec.display_hint == 'mac': + # Parse MAC address in format "00:11:22:33:44:55" or "001122334455" + if ':' in string: + mac_bytes = [int(x, 16) for x in string.split(':')] + else: + if len(string) % 2 != 0: + raise Exception(f"Invalid MAC address format: {string}") + mac_bytes = [int(string[i:i+2], 16) for i in range(0, len(string), 2)] + raw = bytes(mac_bytes) + 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: + msg['raw'] = decoded + op = self.rsp_by_value[decoded.cmd()] + attrs = self._decode(decoded.raw_attrs, op.attr_set.name) + if op.fixed_header: + attrs.update(self._decode_struct(decoded.raw, op.fixed_header)) + + msg['name'] = op['name'] + msg['msg'] = attrs + self.async_msg_queue.put(msg) + + def check_ntf(self): + while True: + try: + reply = self.sock.recv(self._recv_size, socket.MSG_DONTWAIT) + except BlockingIOError: + return + + nms = NlMsgs(reply) + self._recv_dbg_print(reply, nms) + for nl_msg in nms: + if nl_msg.error: + print("Netlink error in ntf!?", os.strerror(-nl_msg.error)) + print(nl_msg) + continue + if nl_msg.done: + print("Netlink done while checking for ntf!?") + continue + + decoded = self.nlproto.decode(self, nl_msg, None) + if decoded.cmd() not in self.async_msg_ids: + print("Unexpected msg id while checking for ntf", decoded) + continue + + self.handle_ntf(decoded) + + def poll_ntf(self, duration=None): + start_time = time.time() + selector = selectors.DefaultSelector() + selector.register(self.sock, selectors.EVENT_READ) + + while True: + try: + yield self.async_msg_queue.get_nowait() + except queue.Empty: + if duration is not None: + timeout = start_time + duration - time.time() + if timeout <= 0: + return + else: + timeout = None + events = selector.select(timeout) + if events: + self.check_ntf() + + def operation_do_attributes(self, name): + """ + For a given operation name, find and return a supported + set of attributes (as a dict). + """ + op = self.find_operation(name) + if not op: + return None + + return op['do']['request']['attributes'].copy() + + def _encode_message(self, op, vals, flags, req_seq): + nl_flags = Netlink.NLM_F_REQUEST | Netlink.NLM_F_ACK + for flag in flags or []: + nl_flags |= flag + + msg = self.nlproto.message(nl_flags, op.req_value, 1, req_seq) + if op.fixed_header: + msg += self._encode_struct(op.fixed_header, vals) + search_attrs = SpaceAttrs(op.attr_set, vals) + for name, value in vals.items(): + msg += self._add_attr(op.attr_set.name, name, value, search_attrs) + msg = _genl_msg_finalize(msg) + return msg + + def _ops(self, ops): + reqs_by_seq = {} + req_seq = random.randint(1024, 65535) + payload = b'' + for (method, vals, flags) in ops: + op = self.ops[method] + msg = self._encode_message(op, vals, flags, req_seq) + reqs_by_seq[req_seq] = (op, vals, msg, flags) + payload += msg + req_seq += 1 + + self.sock.send(payload, 0) + + done = False + rsp = [] + op_rsp = [] + while not done: + reply = self.sock.recv(self._recv_size) + nms = NlMsgs(reply) + self._recv_dbg_print(reply, nms) + for nl_msg in nms: + if nl_msg.nl_seq in reqs_by_seq: + (op, vals, req_msg, req_flags) = reqs_by_seq[nl_msg.nl_seq] + if nl_msg.extack: + nl_msg.annotate_extack(op.attr_set) + self._decode_extack(req_msg, op, nl_msg.extack, vals) + else: + op = None + req_flags = [] + + if nl_msg.error: + raise NlError(nl_msg) + if nl_msg.done: + if nl_msg.extack: + print("Netlink warning:") + print(nl_msg) + + if Netlink.NLM_F_DUMP in req_flags: + rsp.append(op_rsp) + elif not op_rsp: + rsp.append(None) + elif len(op_rsp) == 1: + rsp.append(op_rsp[0]) + else: + rsp.append(op_rsp) + op_rsp = [] + + del reqs_by_seq[nl_msg.nl_seq] + done = len(reqs_by_seq) == 0 + break + + decoded = self.nlproto.decode(self, nl_msg, op) + + # Check if this is a reply to our request + if nl_msg.nl_seq not in reqs_by_seq or decoded.cmd() != op.rsp_value: + if decoded.cmd() in self.async_msg_ids: + self.handle_ntf(decoded) + continue + else: + print('Unexpected message: ' + repr(decoded)) + continue + + rsp_msg = self._decode(decoded.raw_attrs, op.attr_set.name) + if op.fixed_header: + rsp_msg.update(self._decode_struct(decoded.raw, op.fixed_header)) + op_rsp.append(rsp_msg) + + return rsp + + def _op(self, method, vals, flags=None, dump=False): + req_flags = flags or [] + if dump: + req_flags.append(Netlink.NLM_F_DUMP) + + ops = [(method, vals, req_flags)] + return self._ops(ops)[0] + + def do(self, method, vals, flags=None): + return self._op(method, vals, flags) + + def dump(self, method, vals): + return self._op(method, vals, dump=True) + + def do_multi(self, ops): + return self._ops(ops) diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index 897af958cee8..b517d0c605ad 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -2,14 +2,18 @@ # SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) import argparse -import collections +import filecmp +import pathlib import os import re import shutil +import sys import tempfile import yaml +sys.path.append(pathlib.Path(__file__).resolve().parent.as_posix()) from lib import SpecFamily, SpecAttrSet, SpecAttr, SpecOperation, SpecEnumSet, SpecEnumEntry +from lib import SpecSubMessage def c_upper(name): @@ -20,18 +24,25 @@ def c_lower(name): return name.lower().replace('-', '_') +def limit_to_number(name): + """ + Turn a string limit like u32-max or s64-min into its numerical value + """ + if name[0] == 'u' and name.endswith('-min'): + return 0 + width = int(name[1:-4]) + if name[0] == 's': + width -= 1 + value = (1 << width) - 1 + if name[0] == 's' and name.endswith('-min'): + value = -value - 1 + return value + + class BaseNlLib: def get_family_id(self): return 'ys->family_id' - def parse_cb_run(self, cb, data, is_dump=False, indent=1): - ind = '\n\t\t' + '\t' * indent + ' ' - if is_dump: - return f"mnl_cb_run2(ys->rx_buf, len, 0, 0, {cb}, {data},{ind}ynl_cb_array, NLMSG_MIN_TYPE)" - else: - return f"mnl_cb_run2(ys->rx_buf, len, ys->seq, ys->portid,{ind}{cb}, {data},{ind}" + \ - "ynl_cb_array, NLMSG_MIN_TYPE)" - class Type(SpecAttr): def __init__(self, family, attr_set, attr, value): @@ -42,14 +53,27 @@ class Type(SpecAttr): self.type = attr['type'] self.checks = attr.get('checks', {}) + self.request = False + self.reply = False + + self.is_selector = False + if 'len' in attr: self.len = attr['len'] + if 'nested-attributes' in attr: - self.nested_attrs = attr['nested-attributes'] + nested = attr['nested-attributes'] + elif 'sub-message' in attr: + nested = attr['sub-message'] + else: + nested = None + + if nested: + self.nested_attrs = nested if self.nested_attrs == family.name: - self.nested_render_name = f"{family.name}" + self.nested_render_name = c_lower(f"{family.ident_name}") else: - self.nested_render_name = f"{family.name}_{c_lower(self.nested_attrs)}" + self.nested_render_name = c_lower(f"{family.ident_name}_{self.nested_attrs}") if self.nested_attrs in self.family.consts: self.nested_struct_type = 'struct ' + self.nested_render_name + '_' @@ -59,38 +83,89 @@ 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 delattr(self, "enum_name") + def _get_real_attr(self): + # if the attr is for a subset return the "real" attr (just one down, does not recurse) + return self.family.attr_sets[self.attr_set.subset_of][self.name] + + def set_request(self): + self.request = True + if self.attr_set.subset_of: + self._get_real_attr().set_request() + + def set_reply(self): + self.reply = True + if self.attr_set.subset_of: + self._get_real_attr().set_reply() + + def get_limit(self, limit, default=None): + value = self.checks.get(limit, default) + if value is None: + return value + if isinstance(value, int): + return value + if value in self.family.consts: + return self.family.consts[value]["value"] + return limit_to_number(value) + + def get_limit_str(self, limit, default=None, suffix=''): + value = self.checks.get(limit, default) + if value is None: + return '' + if isinstance(value, int): + return str(value) + suffix + if value in self.family.consts: + const = self.family.consts[value] + if const.get('header'): + return c_upper(value) + return c_upper(f"{self.family['name']}-{value}") + return c_upper(value) + def resolve(self): - if 'name-prefix' in self.attr: + if 'parent-sub-message' in self.attr: + enum_name = self.attr['parent-sub-message'].enum_name + elif 'name-prefix' in self.attr: enum_name = f"{self.attr['name-prefix']}{self.name}" else: enum_name = f"{self.attr_set.name_prefix}{self.name}" self.enum_name = c_upper(enum_name) + if self.attr_set.subset_of: + if self.checks != self._get_real_attr().checks: + raise Exception("Overriding checks not supported by codegen, yet") + def is_multi_val(self): return None def is_scalar(self): return self.type in {'u8', 'u16', 'u32', 'u64', 's32', 's64'} + def is_recursive(self): + return False + + def is_recursive_for_op(self, ri): + return self.is_recursive() and not ri.op + def presence_type(self): - return 'bit' + return 'present' def presence_member(self, space, type_filter): if self.presence_type() != type_filter: return - if self.presence_type() == 'bit': + if self.presence_type() == 'present': pfx = '__' if space == 'user' else '' return f"{pfx}u32 {self.c_name}:1;" - if self.presence_type() == 'len': + if self.presence_type() in {'len', 'count'}: pfx = '__' if space == 'user' else '' - return f"{pfx}u32 {self.c_name}_len;" + return f"{pfx}u32 {self.c_name};" def _complex_member_type(self, ri): return None @@ -98,26 +173,34 @@ class Type(SpecAttr): def free_needs_iter(self): return False + def _free_lines(self, ri, var, ref): + if self.is_multi_val() or self.presence_type() in {'count', 'len'}: + return [f'free({var}->{ref}{self.c_name});'] + return [] + def free(self, ri, var, ref): - if self.is_multi_val() or self.presence_type() == 'len': - ri.cw.p(f'free({var}->{ref}{self.c_name});') + lines = self._free_lines(ri, var, ref) + for line in lines: + ri.cw.p(line) def arg_member(self, ri): member = self._complex_member_type(ri) if member: - arg = [member + ' *' + self.c_name] + spc = ' ' if member[-1] != '*' else '' + arg = [member + spc + '*' + self.c_name] if self.presence_type() == 'count': arg += ['unsigned int n_' + self.c_name] return arg raise Exception(f"Struct member not implemented for class type {self.type}") def struct_member(self, ri): - if self.is_multi_val(): - ri.cw.p(f"unsigned int n_{self.c_name};") member = self._complex_member_type(ri) if member: ptr = '*' if self.is_multi_val() else '' - ri.cw.p(f"{member} {ptr}{self.c_name};") + if self.is_recursive_for_op(ri): + ptr = '*' + spc = ' ' if member[-1] != '*' else '' + ri.cw.p(f"{member}{spc}{ptr}{self.c_name};") return members = self.arg_member(ri) for one in members: @@ -127,7 +210,10 @@ class Type(SpecAttr): return '{ .type = ' + policy + ', }' def attr_policy(self, cw): - policy = c_upper('nla-' + self.attr['type']) + policy = f'NLA_{c_upper(self.type)}' + if self.attr.get('byte-order') == 'big-endian': + if self.type in {'u16', 'u32'}: + policy = f'NLA_BE{self.type[1:]}' spec = self._attr_policy(policy) cw.p(f"\t[{self.enum_name}] = {spec},") @@ -140,14 +226,13 @@ class Type(SpecAttr): cw.p(f'[{self.enum_name}] = {"{"} .name = "{self.name}", {typol}{"}"},') def _attr_put_line(self, ri, var, line): - if self.presence_type() == 'bit': - ri.cw.p(f"if ({var}->_present.{self.c_name})") - elif self.presence_type() == 'len': - ri.cw.p(f"if ({var}->_present.{self.c_name}_len)") + presence = self.presence_type() + if presence in {'present', 'len'}: + ri.cw.p(f"if ({var}->_{presence}.{self.c_name})") ri.cw.p(f"{line};") def _attr_put_simple(self, ri, var, put_type): - line = f"mnl_attr_put_{put_type}(nlh, {self.enum_name}, {var}->{self.c_name})" + line = f"ynl_attr_put_{put_type}(nlh, {self.enum_name}, {var}->{self.c_name})" self._attr_put_line(ri, var, line) def attr_put(self, ri, var): @@ -157,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: @@ -165,15 +250,11 @@ 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))") - ri.cw.p("return MNL_CB_ERROR;") - if self.presence_type() == 'bit': + ri.cw.p("return YNL_PARSE_CB_ERROR;") + if self.presence_type() == 'present': ri.cw.p(f"{var}->_present.{self.c_name} = 1;") if init_lines: @@ -189,17 +270,28 @@ class Type(SpecAttr): def _setter_lines(self, ri, member, presence): raise Exception(f"Setter not implemented for class type {self.type}") - def setter(self, ri, space, direction, deref=False, ref=None): + def setter(self, ri, space, direction, deref=False, ref=None, var="req"): ref = (ref if ref else []) + [self.c_name] - var = "req" member = f"{var}->{'.'.join(ref)}" + local_vars = [] + if self.free_needs_iter(): + local_vars += ['unsigned int i;'] + code = [] presence = '' for i in range(0, len(ref)): presence = f"{var}->{'.'.join(ref[:i] + [''])}_present.{ref[i]}" - if self.presence_type() == 'bit': - code.append(presence + ' = 1;') + # Every layer below last is a nest, so we know it uses bit presence + # last layer is "self" and may be a complex type + if i == len(ref) - 1 and self.presence_type() != 'present': + presence = f"{var}->{'.'.join(ref[:i] + [''])}_{self.presence_type()}.{ref[i]}" + continue + code.append(presence + ' = 1;') + ref_path = '.'.join(ref[:-1]) + if ref_path: + ref_path += '.' + code += self._free_lines(ri, var, ref_path) code += self._setter_lines(ri, member, presence) func_name = f"{op_prefix(ri, direction, deref=deref)}_set_{'_'.join(ref)}" @@ -207,7 +299,8 @@ class Type(SpecAttr): alloc = bool([x for x in code if 'alloc(' in x]) if free and not alloc: func_name = '__' + func_name - ri.cw.write_func('static inline void', func_name, body=code, + ri.cw.write_func('static inline void', func_name, local_vars=local_vars, + body=code, args=[f'{type_name(ri, direction, deref=deref)} *{var}'] + self.arg_member(ri)) @@ -219,7 +312,7 @@ class TypeUnused(Type): return [] def _attr_get(self, ri, var): - return ['return MNL_CB_ERROR;'], None, None + return ['return YNL_PARSE_CB_ERROR;'], None, None def _attr_typol(self): return '.type = YNL_PT_REJECT, ' @@ -227,6 +320,15 @@ class TypeUnused(Type): def attr_policy(self, cw): pass + def attr_put(self, ri, var): + pass + + def attr_get(self, ri, var, first): + pass + + def setter(self, ri, space, direction, deref=False, ref=None, var=None): + pass + class TypePad(Type): def presence_type(self): @@ -247,7 +349,7 @@ class TypePad(Type): def attr_policy(self, cw): pass - def setter(self, ri, space, direction, deref=False, ref=None): + def setter(self, ri, space, direction, deref=False, ref=None, var=None): pass @@ -259,6 +361,11 @@ class TypeScalar(Type): if 'byte-order' in attr: self.byte_order_comment = f" /* {attr['byte-order']} */" + # Classic families have some funny enums, don't bother + # computing checks, since we only need them for kernel policies + if not family.is_classic(): + self._init_checks() + # Added by resolve(): self.is_bitfield = None delattr(self, "is_bitfield") @@ -275,18 +382,37 @@ class TypeScalar(Type): else: self.is_bitfield = False - maybe_enum = not self.is_bitfield and 'enum' in self.attr - if maybe_enum and self.family.consts[self.attr['enum']].enum_name: - self.type_name = f"enum {self.family.name}_{c_lower(self.attr['enum'])}" + if not self.is_bitfield and 'enum' in self.attr: + self.type_name = self.family.consts[self.attr['enum']].user_type + elif self.is_auto_scalar: + self.type_name = '__' + self.type[0] + '64' else: self.type_name = '__' + self.type - def _mnl_type(self): - t = self.type - # mnl does not have a helper for signed types - if t[0] == 's': - t = 'u' + t[1:] - return t + def _init_checks(self): + if 'enum' in self.attr: + enum = self.family.consts[self.attr['enum']] + low, high = enum.value_range() + if low is None and high is None: + self.checks['sparse'] = True + else: + if 'min' not in self.checks: + if low != 0 or self.type[0] == 's': + self.checks['min'] = low + if 'max' not in self.checks: + self.checks['max'] = high + + if 'min' in self.checks and 'max' in self.checks: + if self.get_limit('min') > self.get_limit('max'): + raise Exception(f'Invalid limit for "{self.name}" min: {self.get_limit("min")} max: {self.get_limit("max")}') + self.checks['range'] = True + + low = min(self.get_limit('min', 0), self.get_limit('max', 0)) + high = max(self.get_limit('min', 0), self.get_limit('max', 0)) + if low < 0 and self.type[0] == 'u': + raise Exception(f'Invalid limit for "{self.name}" negative limit for unsigned type') + if low < -32768 or high > 32767: + self.checks['full-range'] = True def _attr_policy(self, policy): if 'flags-mask' in self.checks or self.is_bitfield: @@ -298,27 +424,29 @@ class TypeScalar(Type): flag_cnt = len(flags['entries']) mask = (1 << flag_cnt) - 1 return f"NLA_POLICY_MASK({policy}, 0x{mask:x})" + elif 'full-range' in self.checks: + return f"NLA_POLICY_FULL_RANGE({policy}, &{c_lower(self.enum_name)}_range)" + elif 'range' in self.checks: + return f"NLA_POLICY_RANGE({policy}, {self.get_limit_str('min')}, {self.get_limit_str('max')})" elif 'min' in self.checks: - return f"NLA_POLICY_MIN({policy}, {self.checks['min']})" - elif 'enum' in self.attr: - enum = self.family.consts[self.attr['enum']] - low, high = enum.value_range() - if low == 0: - return f"NLA_POLICY_MAX({policy}, {high})" - return f"NLA_POLICY_RANGE({policy}, {low}, {high})" + return f"NLA_POLICY_MIN({policy}, {self.get_limit_str('min')})" + elif 'max' in self.checks: + return f"NLA_POLICY_MAX({policy}, {self.get_limit_str('max')})" + elif 'sparse' in self.checks: + return f"NLA_POLICY_VALIDATE_FN({policy}, &{c_lower(self.enum_name)}_validate)" return super()._attr_policy(policy) def _attr_typol(self): - return f'.type = YNL_PT_U{self.type[1:]}, ' + return f'.type = YNL_PT_U{c_upper(self.type[1:])}, ' def arg_member(self, ri): return [f'{self.type_name} {self.c_name}{self.byte_order_comment}'] def attr_put(self, ri, var): - self._attr_put_simple(ri, var, self._mnl_type()) + self._attr_put_simple(ri, var, self.type) def _attr_get(self, ri, var): - return f"{var}->{self.c_name} = mnl_attr_get_{self._mnl_type()}(attr);", None, None + return f"{var}->{self.c_name} = ynl_attr_get_{self.type}(attr);", None, None def _setter_lines(self, ri, member, presence): return [f"{member} = {self.c_name};"] @@ -332,7 +460,7 @@ class TypeFlag(Type): return '.type = YNL_PT_FLAG, ' def attr_put(self, ri, var): - self._attr_put_line(ri, var, f"mnl_attr_put(nlh, {self.enum_name}, 0, NULL)") + self._attr_put_line(ri, var, f"ynl_attr_put(nlh, {self.enum_name}, NULL, 0)") def _attr_get(self, ri, var): return [], None, None @@ -352,13 +480,19 @@ class TypeString(Type): ri.cw.p(f"char *{self.c_name};") def _attr_typol(self): - return f'.type = YNL_PT_NUL_STR, ' + typol = '.type = YNL_PT_NUL_STR, ' + if self.is_selector: + typol += '.is_selector = 1, ' + return typol def _attr_policy(self, policy): - mem = '{ .type = ' + policy - if 'max-len' in self.checks: - mem += ', .len = ' + str(self.checks['max-len']) - mem += ', }' + if 'exact-len' in self.checks: + mem = 'NLA_POLICY_EXACT_LEN(' + self.get_limit_str('exact-len') + ')' + else: + mem = '{ .type = ' + policy + if 'max-len' in self.checks: + mem += ', .len = ' + self.get_limit_str('max-len') + mem += ', }' return mem def attr_policy(self, cw): @@ -371,23 +505,22 @@ class TypeString(Type): cw.p(f"\t[{self.enum_name}] = {spec},") def attr_put(self, ri, var): - self._attr_put_simple(ri, var, 'strz') + self._attr_put_simple(ri, var, 'str') def _attr_get(self, ri, var): - len_mem = var + '->_present.' + self.c_name + '_len' + len_mem = var + '->_len.' + self.c_name return [f"{len_mem} = len;", f"{var}->{self.c_name} = malloc(len + 1);", - f"memcpy({var}->{self.c_name}, mnl_attr_get_str(attr), len);", + f"memcpy({var}->{self.c_name}, ynl_attr_get_str(attr), len);", f"{var}->{self.c_name}[len] = 0;"], \ - ['len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr));'], \ + ['len = strnlen(ynl_attr_get_str(attr), ynl_attr_data_len(attr));'], \ ['unsigned int len;'] def _setter_lines(self, ri, member, presence): - return [f"free({member});", - f"{presence}_len = strlen({self.c_name});", - f"{member} = malloc({presence}_len + 1);", - f'memcpy({member}, {self.c_name}, {presence}_len);', - f'{member}[{presence}_len] = 0;'] + return [f"{presence} = strlen({self.c_name});", + f"{member} = malloc({presence} + 1);", + f'memcpy({member}, {self.c_name}, {presence});', + f'{member}[{presence}] = 0;'] class TypeBinary(Type): @@ -401,44 +534,138 @@ class TypeBinary(Type): ri.cw.p(f"void *{self.c_name};") def _attr_typol(self): - return f'.type = YNL_PT_BINARY,' + return '.type = YNL_PT_BINARY,' def _attr_policy(self, policy): - mem = '{ ' - if len(self.checks) == 1 and 'min-len' in self.checks: - mem += '.len = ' + str(self.checks['min-len']) - elif len(self.checks) == 0: - mem += '.type = NLA_BINARY' + if len(self.checks) == 0: + pass + elif len(self.checks) == 1: + check_name = list(self.checks)[0] + if check_name not in {'exact-len', 'min-len', 'max-len'}: + raise Exception('Unsupported check for binary type: ' + check_name) else: - raise Exception('One or more of binary type checks not implemented, yet') - mem += ', }' + raise Exception('More than one check for binary type not implemented, yet') + + if len(self.checks) == 0: + mem = '{ .type = NLA_BINARY, }' + elif 'exact-len' in self.checks: + mem = 'NLA_POLICY_EXACT_LEN(' + self.get_limit_str('exact-len') + ')' + elif 'min-len' in self.checks: + mem = 'NLA_POLICY_MIN_LEN(' + self.get_limit_str('min-len') + ')' + elif 'max-len' in self.checks: + mem = 'NLA_POLICY_MAX_LEN(' + self.get_limit_str('max-len') + ')' + return mem def attr_put(self, ri, var): - self._attr_put_line(ri, var, f"mnl_attr_put(nlh, {self.enum_name}, " + - f"{var}->_present.{self.c_name}_len, {var}->{self.c_name})") + self._attr_put_line(ri, var, f"ynl_attr_put(nlh, {self.enum_name}, " + + f"{var}->{self.c_name}, {var}->_len.{self.c_name})") def _attr_get(self, ri, var): - len_mem = var + '->_present.' + self.c_name + '_len' + len_mem = var + '->_len.' + self.c_name return [f"{len_mem} = len;", f"{var}->{self.c_name} = malloc(len);", - f"memcpy({var}->{self.c_name}, mnl_attr_get_payload(attr), len);"], \ - ['len = mnl_attr_get_payload_len(attr);'], \ + f"memcpy({var}->{self.c_name}, ynl_attr_data(attr), len);"], \ + ['len = ynl_attr_data_len(attr);'], \ ['unsigned int len;'] def _setter_lines(self, ri, member, presence): - return [f"free({member});", - f"{presence}_len = len;", - f"{member} = malloc({presence}_len);", - f'memcpy({member}, {self.c_name}, {presence}_len);'] + return [f"{presence} = len;", + f"{member} = malloc({presence});", + f'memcpy({member}, {self.c_name}, {presence});'] + + +class TypeBinaryStruct(TypeBinary): + def struct_member(self, ri): + ri.cw.p(f'struct {c_lower(self.get("struct"))} *{self.c_name};') + + def _attr_get(self, ri, var): + struct_sz = 'sizeof(struct ' + c_lower(self.get("struct")) + ')' + len_mem = var + '->_' + self.presence_type() + '.' + self.c_name + return [f"{len_mem} = len;", + f"if (len < {struct_sz})", + f"{var}->{self.c_name} = calloc(1, {struct_sz});", + "else", + f"{var}->{self.c_name} = malloc(len);", + f"memcpy({var}->{self.c_name}, ynl_attr_data(attr), len);"], \ + ['len = ynl_attr_data_len(attr);'], \ + ['unsigned int len;'] + + +class TypeBinaryScalarArray(TypeBinary): + def arg_member(self, ri): + return [f'__{self.get("sub-type")} *{self.c_name}', 'size_t count'] + + def presence_type(self): + return 'count' + + def struct_member(self, ri): + ri.cw.p(f'__{self.get("sub-type")} *{self.c_name};') + + def attr_put(self, ri, var): + presence = self.presence_type() + ri.cw.block_start(line=f"if ({var}->_{presence}.{self.c_name})") + ri.cw.p(f"i = {var}->_{presence}.{self.c_name} * sizeof(__{self.get('sub-type')});") + ri.cw.p(f"ynl_attr_put(nlh, {self.enum_name}, " + + f"{var}->{self.c_name}, i);") + ri.cw.block_end() + + def _attr_get(self, ri, var): + len_mem = var + '->_count.' + self.c_name + return [f"{len_mem} = len / sizeof(__{self.get('sub-type')});", + f"len = {len_mem} * sizeof(__{self.get('sub-type')});", + f"{var}->{self.c_name} = malloc(len);", + f"memcpy({var}->{self.c_name}, ynl_attr_data(attr), len);"], \ + ['len = ynl_attr_data_len(attr);'], \ + ['unsigned int len;'] + + def _setter_lines(self, ri, member, presence): + return [f"{presence} = count;", + f"count *= sizeof(__{self.get('sub-type')});", + f"{member} = malloc(count);", + f'memcpy({member}, {self.c_name}, count);'] + + +class TypeBitfield32(Type): + def _complex_member_type(self, ri): + return "struct nla_bitfield32" + + def _attr_typol(self): + return '.type = YNL_PT_BITFIELD32, ' + + def _attr_policy(self, policy): + if 'enum' not 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"ynl_attr_put(nlh, {self.enum_name}, &{var}->{self.c_name}, sizeof(struct nla_bitfield32))" + self._attr_put_line(ri, var, line) + + def _attr_get(self, ri, var): + return f"memcpy(&{var}->{self.c_name}, ynl_attr_data(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 is_recursive(self): + return self.family.pure_nested_structs[self.nested_attrs].recursive + def _complex_member_type(self, ri): return self.nested_struct_type - def free(self, ri, var, ref): - ri.cw.p(f'{self.nested_render_name}_free(&{var}->{ref}{self.c_name});') + def _free_lines(self, ri, var, ref): + lines = [] + at = '&' + if self.is_recursive_for_op(ri): + at = '' + lines += [f'if ({var}->{ref}{self.c_name})'] + lines += [f'{self.nested_render_name}_free({at}{var}->{ref}{self.c_name});'] + return lines def _attr_typol(self): return f'.type = YNL_PT_NEST, .nest = &{self.nested_render_name}_nest, ' @@ -447,21 +674,29 @@ class TypeNest(Type): return 'NLA_POLICY_NESTED(' + self.nested_render_name + '_nl_policy)' def attr_put(self, ri, var): + at = '' if self.is_recursive_for_op(ri) else '&' self._attr_put_line(ri, var, f"{self.nested_render_name}_put(nlh, " + - f"{self.enum_name}, &{var}->{self.c_name})") + f"{self.enum_name}, {at}{var}->{self.c_name})") def _attr_get(self, ri, var): - get_lines = [f"if ({self.nested_render_name}_parse(&parg, attr))", - "return MNL_CB_ERROR;"] + pns = self.family.pure_nested_structs[self.nested_attrs] + args = ["&parg", "attr"] + for sel in pns.external_selectors(): + args.append(f'{var}->{sel.name}') + get_lines = [f"if ({self.nested_render_name}_parse({', '.join(args)}))", + "return YNL_PARSE_CB_ERROR;"] init_lines = [f"parg.rsp_policy = &{self.nested_render_name}_nest;", f"parg.data = &{var}->{self.c_name};"] return get_lines, init_lines, None - def setter(self, ri, space, direction, deref=False, ref=None): + def setter(self, ri, space, direction, deref=False, ref=None, var="req"): ref = (ref if ref else []) + [self.c_name] for _, attr in ri.family.pure_nested_structs[self.nested_attrs].member_list(): - attr.setter(ri, self.nested_attrs, direction, deref=deref, ref=ref) + if attr.is_recursive(): + continue + attr.setter(ri, self.nested_attrs, direction, deref=deref, ref=ref, + var=var) class TypeMultiAttr(Type): @@ -476,34 +711,53 @@ class TypeMultiAttr(Type): def presence_type(self): return 'count' - def _mnl_type(self): - t = self.type - # mnl does not have a helper for signed types - if t[0] == 's': - t = 'u' + t[1:] - return t - def _complex_member_type(self, ri): if 'type' not in self.attr or self.attr['type'] == 'nest': return self.nested_struct_type + elif self.attr['type'] == 'binary' and 'struct' in self.attr: + return None # use arg_member() + elif self.attr['type'] == 'string': + return 'struct ynl_string *' elif self.attr['type'] in scalars: scalar_pfx = '__' if ri.ku_space == 'user' else '' - return scalar_pfx + self.attr['type'] + if self.is_auto_scalar: + name = self.type[0] + '64' + else: + name = self.attr['type'] + return scalar_pfx + name else: raise Exception(f"Sub-type {self.attr['type']} not supported yet") + def arg_member(self, ri): + if self.type == 'binary' and 'struct' in self.attr: + return [f'struct {c_lower(self.attr["struct"])} *{self.c_name}', + f'unsigned int n_{self.c_name}'] + return super().arg_member(ri) + def free_needs_iter(self): - return 'type' not in self.attr or self.attr['type'] == 'nest' + return self.attr['type'] in {'nest', 'string'} - def free(self, ri, var, ref): + def _free_lines(self, ri, var, ref): + lines = [] if self.attr['type'] in scalars: - ri.cw.p(f"free({var}->{ref}{self.c_name});") + lines += [f"free({var}->{ref}{self.c_name});"] + elif self.attr['type'] == 'binary': + lines += [f"free({var}->{ref}{self.c_name});"] + elif self.attr['type'] == 'string': + lines += [ + f"for (i = 0; i < {var}->{ref}_count.{self.c_name}; i++)", + f"free({var}->{ref}{self.c_name}[i]);", + f"free({var}->{ref}{self.c_name});", + ] elif 'type' not in self.attr or self.attr['type'] == 'nest': - ri.cw.p(f"for (i = 0; i < {var}->{ref}n_{self.c_name}; i++)") - ri.cw.p(f'{self.nested_render_name}_free(&{var}->{ref}{self.c_name}[i]);') - ri.cw.p(f"free({var}->{ref}{self.c_name});") + lines += [ + f"for (i = 0; i < {var}->{ref}_count.{self.c_name}; i++)", + f'{self.nested_render_name}_free(&{var}->{ref}{self.c_name}[i]);', + f"free({var}->{ref}{self.c_name});", + ] else: raise Exception(f"Free of MultiAttr sub-type {self.attr['type']} not supported yet") + return lines def _attr_policy(self, policy): return self.base_type._attr_policy(policy) @@ -516,25 +770,28 @@ class TypeMultiAttr(Type): def attr_put(self, ri, var): if self.attr['type'] in scalars: - put_type = self._mnl_type() - ri.cw.p(f"for (unsigned int i = 0; i < {var}->n_{self.c_name}; i++)") - ri.cw.p(f"mnl_attr_put_{put_type}(nlh, {self.enum_name}, {var}->{self.c_name}[i]);") + put_type = self.type + ri.cw.p(f"for (i = 0; i < {var}->_count.{self.c_name}; i++)") + ri.cw.p(f"ynl_attr_put_{put_type}(nlh, {self.enum_name}, {var}->{self.c_name}[i]);") + elif self.attr['type'] == 'binary' and 'struct' in self.attr: + ri.cw.p(f"for (i = 0; i < {var}->_count.{self.c_name}; i++)") + ri.cw.p(f"ynl_attr_put(nlh, {self.enum_name}, &{var}->{self.c_name}[i], sizeof(struct {c_lower(self.attr['struct'])}));") + elif self.attr['type'] == 'string': + ri.cw.p(f"for (i = 0; i < {var}->_count.{self.c_name}; i++)") + ri.cw.p(f"ynl_attr_put_str(nlh, {self.enum_name}, {var}->{self.c_name}[i]->str);") elif 'type' not in self.attr or self.attr['type'] == 'nest': - ri.cw.p(f"for (unsigned int i = 0; i < {var}->n_{self.c_name}; i++)") + ri.cw.p(f"for (i = 0; i < {var}->_count.{self.c_name}; i++)") self._attr_put_line(ri, var, f"{self.nested_render_name}_put(nlh, " + f"{self.enum_name}, &{var}->{self.c_name}[i])") else: raise Exception(f"Put of MultiAttr sub-type {self.attr['type']} not supported yet") def _setter_lines(self, ri, member, presence): - # For multi-attr we have a count, not presence, hack up the presence - presence = presence[:-(len('_present.') + len(self.c_name))] + "n_" + self.c_name - return [f"free({member});", - f"{member} = {self.c_name};", + return [f"{member} = {self.c_name};", f"{presence} = n_{self.c_name};"] -class TypeArrayNest(Type): +class TypeIndexedArray(Type): def is_multi_val(self): return True @@ -547,19 +804,75 @@ class TypeArrayNest(Type): elif self.attr['sub-type'] in scalars: scalar_pfx = '__' if ri.ku_space == 'user' else '' return scalar_pfx + self.attr['sub-type'] + elif self.attr['sub-type'] == 'binary' and 'exact-len' in self.checks: + return None # use arg_member() else: raise Exception(f"Sub-type {self.attr['sub-type']} not supported yet") + def arg_member(self, ri): + if self.sub_type == 'binary' and 'exact-len' in self.checks: + return [f'unsigned char (*{self.c_name})[{self.checks["exact-len"]}]', + 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): - 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:])}, ' + elif self.attr['sub-type'] == 'binary' and 'exact-len' in self.checks: + return f'.type = YNL_PT_BINARY, .len = {self.checks["exact-len"]}, ' + 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;', - 'mnl_attr_for_each_nested(attr2, attr)', - f'\t{var}->n_{self.c_name}++;'] + 'ynl_attr_for_each_nested(attr2, attr) {', + '\tif (__ynl_attr_validate(yarg, attr2, type))', + '\t\treturn YNL_PARSE_CB_ERROR;', + f'\tn_{self.c_name}++;', + '}'] return get_lines, None, local_vars + def attr_put(self, ri, var): + ri.cw.p(f'array = ynl_attr_nest_start(nlh, {self.enum_name});') + if self.sub_type in scalars: + put_type = self.sub_type + ri.cw.block_start(line=f'for (i = 0; i < {var}->_count.{self.c_name}; i++)') + ri.cw.p(f"ynl_attr_put_{put_type}(nlh, i, {var}->{self.c_name}[i]);") + ri.cw.block_end() + elif self.sub_type == 'binary' and 'exact-len' in self.checks: + ri.cw.p(f'for (i = 0; i < {var}->_count.{self.c_name}; i++)') + ri.cw.p(f"ynl_attr_put(nlh, i, {var}->{self.c_name}[i], {self.checks['exact-len']});") + elif self.sub_type == 'nest': + 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 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): + return [f"{member} = {self.c_name};", + f"{presence} = n_{self.c_name};"] + + def free_needs_iter(self): + return self.sub_type == 'nest' + + def _free_lines(self, ri, var, ref): + lines = [] + if self.sub_type == 'nest': + lines += [ + f"for (i = 0; i < {var}->{ref}_count.{self.c_name}; i++)", + f'{self.nested_render_name}_free(&{var}->{ref}{self.c_name}[i]);', + ] + lines += f"free({var}->{ref}{self.c_name});", + return lines class TypeNestTypeValue(Type): def _complex_member_type(self, ri): @@ -581,8 +894,8 @@ class TypeNestTypeValue(Type): local_vars += [f'__u32 {", ".join(tv_names)};'] for level in self.attr["type-value"]: level = c_lower(level) - get_lines += [f'attr_{level} = mnl_attr_get_payload({prev});'] - get_lines += [f'{level} = mnl_attr_get_type(attr_{level});'] + get_lines += [f'attr_{level} = ynl_attr_data({prev});'] + get_lines += [f'{level} = ynl_attr_type(attr_{level});'] prev = 'attr_' + level tv_args = f", {', '.join(tv_names)}" @@ -591,27 +904,88 @@ class TypeNestTypeValue(Type): return get_lines, init_lines, local_vars +class TypeSubMessage(TypeNest): + def __init__(self, family, attr_set, attr, value): + super().__init__(family, attr_set, attr, value) + + self.selector = Selector(attr, attr_set) + + def _attr_typol(self): + typol = f'.type = YNL_PT_NEST, .nest = &{self.nested_render_name}_nest, ' + typol += '.is_submsg = 1, ' + # Reverse-parsing of the policy (ynl_err_walk() in ynl.c) does not + # support external selectors. No family uses sub-messages with external + # selector for requests so this is fine for now. + if not self.selector.is_external(): + typol += f'.selector_type = {self.attr_set[self["selector"]].value} ' + return typol + + def _attr_get(self, ri, var): + sel = c_lower(self['selector']) + if self.selector.is_external(): + sel_var = f"_sel_{sel}" + else: + sel_var = f"{var}->{sel}" + get_lines = [f'if (!{sel_var})', + 'return ynl_submsg_failed(yarg, "%s", "%s");' % + (self.name, self['selector']), + f"if ({self.nested_render_name}_parse(&parg, {sel_var}, attr))", + "return YNL_PARSE_CB_ERROR;"] + init_lines = [f"parg.rsp_policy = &{self.nested_render_name}_nest;", + f"parg.data = &{var}->{self.c_name};"] + return get_lines, init_lines, None + + +class Selector: + def __init__(self, msg_attr, attr_set): + self.name = msg_attr["selector"] + + if self.name in attr_set: + self.attr = attr_set[self.name] + self.attr.is_selector = True + self._external = False + else: + # The selector will need to get passed down thru the structs + self.attr = None + self._external = True + + def set_attr(self, attr): + self.attr = attr + + def is_external(self): + return self._external + + class Struct: - def __init__(self, family, space_name, type_list=None, inherited=None): + def __init__(self, family, space_name, type_list=None, fixed_header=None, + inherited=None, submsg=None): self.family = family self.space_name = space_name self.attr_set = family.attr_sets[space_name] # Use list to catch comparisons with empty sets self._inherited = inherited if inherited is not None else [] self.inherited = [] + self.fixed_header = None + if fixed_header: + self.fixed_header = 'struct ' + c_lower(fixed_header) + self.submsg = submsg self.nested = type_list is None if family.name == c_lower(space_name): - self.render_name = f"{family.name}" + self.render_name = c_lower(family.ident_name) else: - self.render_name = f"{family.name}_{c_lower(space_name)}" + self.render_name = c_lower(family.ident_name + '-' + space_name) self.struct_name = 'struct ' + self.render_name if self.nested and space_name in family.consts: self.struct_name += '_' self.ptr_name = self.struct_name + ' *' + # All attr sets this one contains, directly or multiple levels down + self.child_nests = set() self.request = False self.reply = False + self.recursive = False + self.in_multi_val = False # used by a MultiAttr or and legacy arrays self.attr_list = [] self.attrs = dict() @@ -644,6 +1018,19 @@ class Struct: raise Exception("Inheriting different members not supported") self.inherited = [c_lower(x) for x in sorted(self._inherited)] + def external_selectors(self): + sels = [] + for name, attr in self.attr_list: + if isinstance(attr, TypeSubMessage) and attr.selector.is_external(): + sels.append(attr.selector) + return sels + + def free_needs_iter(self): + for _, attr in self.attr_list: + if attr.free_needs_iter(): + return True + return False + class EnumEntry(SpecEnumEntry): def __init__(self, enum_set, yaml, prev, value_start): @@ -667,17 +1054,25 @@ class EnumEntry(SpecEnumEntry): class EnumSet(SpecEnumSet): def __init__(self, family, yaml): - self.render_name = c_lower(family.name + '-' + yaml['name']) + self.render_name = c_lower(family.ident_name + '-' + yaml['name']) if 'enum-name' in yaml: if yaml['enum-name']: self.enum_name = 'enum ' + c_lower(yaml['enum-name']) + self.user_type = self.enum_name else: self.enum_name = None else: self.enum_name = 'enum ' + self.render_name - self.value_pfx = yaml.get('name-prefix', f"{family.name}-{yaml['name']}-") + if self.enum_name: + self.user_type = self.enum_name + else: + self.user_type = 'int' + + self.value_pfx = yaml.get('name-prefix', f"{family.ident_name}-{yaml['name']}-") + self.header = yaml.get('header', None) + self.enum_cnt_name = yaml.get('enum-cnt-name', None) super().__init__(family, yaml) @@ -689,7 +1084,7 @@ class EnumSet(SpecEnumSet): high = max([x.value for x in self.entries.values()]) if high - low + 1 != len(self.entries): - raise Exception("Can't get value range for a noncontiguous enum") + return None, None return low, high @@ -702,14 +1097,16 @@ class AttrSet(SpecAttrSet): if 'name-prefix' in yaml: pfx = yaml['name-prefix'] elif self.name == family.name: - pfx = family.name + '-a-' + pfx = family.ident_name + '-a-' else: - pfx = f"{family.name}-a-{self.name}-" + pfx = f"{family.ident_name}-a-{self.name}-" self.name_prefix = c_upper(pfx) self.max_name = c_upper(self.yaml.get('attr-max-name', f"{self.name_prefix}max")) + self.cnt_name = c_upper(self.yaml.get('attr-cnt-name', f"__{self.name_prefix}max")) else: self.name_prefix = family.attr_sets[self.subset_of].name_prefix self.max_name = family.attr_sets[self.subset_of].max_name + self.cnt_name = family.attr_sets[self.subset_of].cnt_name # Added by resolve: self.c_name = None @@ -734,13 +1131,25 @@ class AttrSet(SpecAttrSet): elif elem['type'] == 'string': t = TypeString(self.family, self, elem, value) elif elem['type'] == 'binary': - t = TypeBinary(self.family, self, elem, value) + if 'struct' in elem: + t = TypeBinaryStruct(self.family, self, elem, value) + elif elem.get('sub-type') in scalars: + t = TypeBinaryScalarArray(self.family, self, elem, value) + else: + 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': - t = TypeArrayNest(self.family, self, elem, value) + elif elem['type'] == 'indexed-array' and 'sub-type' in elem: + if elem["sub-type"] in ['binary', 'nest', 'u32']: + 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': t = TypeNestTypeValue(self.family, self, elem, value) + elif elem['type'] == 'sub-message': + t = TypeSubMessage(self.family, self, elem, value) else: raise Exception(f"No typed class for type {elem['type']}") @@ -752,9 +1161,17 @@ class AttrSet(SpecAttrSet): class Operation(SpecOperation): def __init__(self, family, yaml, req_value, rsp_value): + # Fill in missing operation properties (for fixed hdr-only msgs) + for mode in ['do', 'dump', 'event']: + for direction in ['request', 'reply']: + try: + yaml[mode][direction].setdefault('attributes', []) + except KeyError: + pass + super().__init__(family, yaml, req_value, rsp_value) - self.render_name = family.name + '_' + c_lower(self.name) + self.render_name = c_lower(family.ident_name + '_' + self.name) self.dual_policy = ('do' in yaml and 'request' in yaml['do']) and \ ('dump' in yaml and 'request' in yaml['dump']) @@ -777,8 +1194,18 @@ class Operation(SpecOperation): self.has_ntf = True +class SubMessage(SpecSubMessage): + def __init__(self, family, yaml): + super().__init__(family, yaml) + + self.render_name = c_lower(family.ident_name + '-' + yaml['name']) + + def resolve(self): + self.resolve_up(super()) + + class Family(SpecFamily): - def __init__(self, file_name, exclude_ops): + def __init__(self, file_name, exclude_ops, fn_prefix): # Added by resolve: self.c_name = None delattr(self, "c_name") @@ -804,15 +1231,18 @@ class Family(SpecFamily): if 'uapi-header' in self.yaml: self.uapi_header = self.yaml['uapi-header'] else: - self.uapi_header = f"linux/{self.name}.h" + self.uapi_header = f"linux/{self.ident_name}.h" + if self.uapi_header.startswith("linux/") and self.uapi_header.endswith('.h'): + self.uapi_header_name = self.uapi_header[6:-2] + else: + self.uapi_header_name = self.ident_name + + self.fn_prefix = fn_prefix if fn_prefix else f'{self.ident_name}-nl' def resolve(self): self.resolve_up(super()) - if self.yaml.get('protocol', 'genetlink') not in {'genetlink', 'genetlink-c', 'genetlink-legacy'}: - raise Exception("Codegen only supported for genetlink") - - self.c_name = c_lower(self.name) + self.c_name = c_lower(self.ident_name) if 'name-prefix' in self.yaml['operations']: self.op_prefix = c_upper(self.yaml['operations']['name-prefix']) else: @@ -834,7 +1264,7 @@ class Family(SpecFamily): # dict space-name -> 'request': set(attrs), 'reply': set(attrs) self.root_sets = dict() - # dict space-name -> set('request', 'reply') + # dict space-name -> Struct self.pure_nested_structs = dict() self._mark_notify() @@ -842,6 +1272,8 @@ class Family(SpecFamily): self._load_root_sets() self._load_nested_sets() + self._load_attr_use() + self._load_selector_passing() self._load_hooks() self.kernel_policy = self.yaml.get('kernel-policy', 'split') @@ -857,6 +1289,12 @@ class Family(SpecFamily): def new_operation(self, elem, req_value, rsp_value): return Operation(self, elem, req_value, rsp_value) + def new_sub_message(self, elem): + return SubMessage(self, elem) + + def is_classic(self): + return self.proto == 'netlink-raw' + def _mark_notify(self): for op in self.msgs.values(): if 'notify' in op: @@ -893,6 +1331,98 @@ class Family(SpecFamily): self.root_sets[op['attribute-set']]['request'].update(req_attrs) self.root_sets[op['attribute-set']]['reply'].update(rsp_attrs) + def _sort_pure_types(self): + # Try to reorder according to dependencies + pns_key_list = list(self.pure_nested_structs.keys()) + pns_key_seen = set() + rounds = len(pns_key_list) ** 2 # it's basically bubble sort + for _ in range(rounds): + if len(pns_key_list) == 0: + break + name = pns_key_list.pop(0) + finished = True + for _, spec in self.attr_sets[name].items(): + if 'nested-attributes' in spec: + nested = spec['nested-attributes'] + elif 'sub-message' in spec: + nested = spec.sub_message + else: + continue + + # If the unknown nest we hit is recursive it's fine, it'll be a pointer + if self.pure_nested_structs[nested].recursive: + continue + if nested not in pns_key_seen: + # Dicts are sorted, this will make struct last + struct = self.pure_nested_structs.pop(name) + self.pure_nested_structs[name] = struct + finished = False + break + if finished: + pns_key_seen.add(name) + else: + pns_key_list.append(name) + + def _load_nested_set_nest(self, spec): + inherit = set() + nested = spec['nested-attributes'] + if nested not in self.root_sets: + if nested not in self.pure_nested_structs: + self.pure_nested_structs[nested] = \ + Struct(self, nested, inherited=inherit, + fixed_header=spec.get('fixed-header')) + else: + raise Exception(f'Using attr set as root and nested not supported - {nested}') + + if 'type-value' in spec: + if nested in self.root_sets: + raise Exception("Inheriting members to a space used as root not supported") + inherit.update(set(spec['type-value'])) + elif spec['type'] == 'indexed-array': + inherit.add('idx') + self.pure_nested_structs[nested].set_inherited(inherit) + + return nested + + def _load_nested_set_submsg(self, spec): + # Fake the struct type for the sub-message itself + # its not a attr_set but codegen wants attr_sets. + submsg = self.sub_msgs[spec["sub-message"]] + nested = submsg.name + + attrs = [] + for name, fmt in submsg.formats.items(): + attr = { + "name": name, + "parent-sub-message": spec, + } + if 'attribute-set' in fmt: + attr |= { + "type": "nest", + "nested-attributes": fmt['attribute-set'], + } + if 'fixed-header' in fmt: + attr |= { "fixed-header": fmt["fixed-header"] } + elif 'fixed-header' in fmt: + attr |= { + "type": "binary", + "struct": fmt["fixed-header"], + } + else: + attr["type"] = "flag" + attrs.append(attr) + + self.attr_sets[nested] = AttrSet(self, { + "name": nested, + "name-pfx": self.name + '-' + spec.name + '-', + "attributes": attrs + }) + + if nested not in self.pure_nested_structs: + self.pure_nested_structs[nested] = Struct(self, nested, submsg=submsg) + + return nested + def _load_nested_sets(self): attr_set_queue = list(self.root_sets.keys()) attr_set_seen = set(self.root_sets.keys()) @@ -900,67 +1430,102 @@ class Family(SpecFamily): while len(attr_set_queue): a_set = attr_set_queue.pop(0) for attr, spec in self.attr_sets[a_set].items(): - if 'nested-attributes' not in spec: + if 'nested-attributes' in spec: + nested = self._load_nested_set_nest(spec) + elif 'sub-message' in spec: + nested = self._load_nested_set_submsg(spec) + else: continue - nested = spec['nested-attributes'] if nested not in attr_set_seen: attr_set_queue.append(nested) attr_set_seen.add(nested) - inherit = set() - if nested not in self.root_sets: - if nested not in self.pure_nested_structs: - self.pure_nested_structs[nested] = Struct(self, nested, inherited=inherit) - else: - raise Exception(f'Using attr set as root and nested not supported - {nested}') - - if 'type-value' in spec: - if nested in self.root_sets: - raise Exception("Inheriting members to a space used as root not supported") - inherit.update(set(spec['type-value'])) - elif spec['type'] == 'array-nest': - inherit.add('idx') - self.pure_nested_structs[nested].set_inherited(inherit) - for root_set, rs_members in self.root_sets.items(): for attr, spec in self.attr_sets[root_set].items(): if 'nested-attributes' in spec: nested = spec['nested-attributes'] + elif 'sub-message' in spec: + nested = spec.sub_message + else: + nested = None + + if nested: if attr in rs_members['request']: self.pure_nested_structs[nested].request = True if attr in rs_members['reply']: self.pure_nested_structs[nested].reply = True - # Try to reorder according to dependencies - pns_key_list = list(self.pure_nested_structs.keys()) - pns_key_seen = set() - rounds = len(pns_key_list)**2 # it's basically bubble sort - for _ in range(rounds): - if len(pns_key_list) == 0: - break - name = pns_key_list.pop(0) - finished = True - for _, spec in self.attr_sets[name].items(): - if 'nested-attributes' in spec: - if spec['nested-attributes'] not in pns_key_seen: - # Dicts are sorted, this will make struct last - struct = self.pure_nested_structs.pop(name) - self.pure_nested_structs[name] = struct - finished = False - break - if finished: - pns_key_seen.add(name) - else: - pns_key_list.append(name) - # Propagate the request / reply + if spec.is_multi_val(): + child = self.pure_nested_structs.get(nested) + child.in_multi_val = True + + self._sort_pure_types() + + # Propagate the request / reply / recursive for attr_set, struct in reversed(self.pure_nested_structs.items()): for _, spec in self.attr_sets[attr_set].items(): + if attr_set in struct.child_nests: + struct.recursive = True + if 'nested-attributes' in spec: - child = self.pure_nested_structs.get(spec['nested-attributes']) - if child: - child.request |= struct.request - child.reply |= struct.reply + child_name = spec['nested-attributes'] + elif 'sub-message' in spec: + child_name = spec.sub_message + else: + continue + + struct.child_nests.add(child_name) + child = self.pure_nested_structs.get(child_name) + if child: + if not child.recursive: + struct.child_nests.update(child.child_nests) + child.request |= struct.request + child.reply |= struct.reply + if spec.is_multi_val(): + child.in_multi_val = True + + self._sort_pure_types() + + def _load_attr_use(self): + for _, struct in self.pure_nested_structs.items(): + if struct.request: + for _, arg in struct.member_list(): + arg.set_request() + if struct.reply: + for _, arg in struct.member_list(): + arg.set_reply() + + for root_set, rs_members in self.root_sets.items(): + for attr, spec in self.attr_sets[root_set].items(): + if attr in rs_members['request']: + spec.set_request() + if attr in rs_members['reply']: + spec.set_reply() + + def _load_selector_passing(self): + def all_structs(): + for k, v in reversed(self.pure_nested_structs.items()): + yield k, v + for k, _ in self.root_sets.items(): + yield k, None # we don't have a struct, but it must be terminal + + for attr_set, struct in all_structs(): + for _, spec in self.attr_sets[attr_set].items(): + if 'nested-attributes' in spec: + child_name = spec['nested-attributes'] + elif 'sub-message' in spec: + child_name = spec.sub_message + else: + continue + + child = self.pure_nested_structs.get(child_name) + for selector in child.external_selectors(): + if selector.name in self.attr_sets[attr_set]: + sel_attr = self.attr_sets[attr_set][selector.name] + selector.set_attr(sel_attr) + else: + raise Exception("Passing selector thru more than one layer not supported") def _load_global_policy(self): global_set = set() @@ -1011,13 +1576,28 @@ class RenderInfo: self.op_mode = op_mode self.op = op + fixed_hdr = op.fixed_header if op else None + self.fixed_hdr_len = 'ys->family->hdr_len' + if op and op.fixed_header: + if op.fixed_header != family.fixed_header: + if family.is_classic(): + self.fixed_hdr_len = f"sizeof(struct {c_lower(fixed_hdr)})" + else: + raise Exception("Per-op fixed header not supported, yet") + + # 'do' and 'dump' response parsing is identical self.type_consistent = True - if op_mode != 'do' and 'dump' in op and 'do' in op: - if ('reply' in op['do']) != ('reply' in op["dump"]): - self.type_consistent = False - elif 'reply' in op['do'] and op["do"]["reply"] != op["dump"]["reply"]: - self.type_consistent = False + self.type_oneside = False + if op_mode != 'do' and 'dump' in op: + if 'do' in op: + if ('reply' in op['do']) != ('reply' in op["dump"]): + self.type_consistent = False + elif 'reply' in op['do'] and op["do"]["reply"] != op["dump"]["reply"]: + self.type_consistent = False + else: + self.type_consistent = True + self.type_oneside = True self.attr_set = attr_set if not self.attr_set: @@ -1035,27 +1615,42 @@ class RenderInfo: self.struct = dict() if op_mode == 'notify': - op_mode = 'do' + op_mode = 'do' if 'do' in op else 'dump' for op_dir in ['request', 'reply']: - if op and op_dir in op[op_mode]: + if op: + type_list = [] + if op_dir in op[op_mode]: + type_list = op[op_mode][op_dir]['attributes'] self.struct[op_dir] = Struct(family, self.attr_set, - type_list=op[op_mode][op_dir]['attributes']) + fixed_header=fixed_hdr, + type_list=type_list) if op_mode == 'event': - self.struct['reply'] = Struct(family, self.attr_set, type_list=op['event']['attributes']) + self.struct['reply'] = Struct(family, self.attr_set, + fixed_header=fixed_hdr, + type_list=op['event']['attributes']) + + def type_empty(self, key): + return len(self.struct[key].attr_list) == 0 and \ + self.struct['request'].fixed_header is None + + def needs_nlflags(self, direction): + return self.op_mode == 'do' and direction == 'request' and self.family.is_classic() class CodeWriter: - def __init__(self, nlib, out_file=None): + def __init__(self, nlib, out_file=None, overwrite=True): self.nlib = nlib + self._overwrite = overwrite self._nl = False self._block_end = False self._silent_block = False self._ind = 0 + self._ifdef_block = None if out_file is None: self._out = os.sys.stdout else: - self._out = tempfile.TemporaryFile('w+') + self._out = tempfile.NamedTemporaryFile('w+') self._out_file = out_file def __del__(self): @@ -1064,6 +1659,11 @@ class CodeWriter: def close_out_file(self): if self._out == os.sys.stdout: return + # Avoid modifying the file if contents didn't change + self._out.flush() + if not self._overwrite and os.path.isfile(self._out_file): + if filecmp.cmp(self._out.name, self._out_file, shallow=False): + return with open(self._out_file, 'w+') as out_file: self._out.seek(0) shutil.copyfileobj(self._out, out_file) @@ -1092,6 +1692,9 @@ class CodeWriter: if self._silent_block: ind += 1 self._silent_block = line.endswith(')') and CodeWriter._is_cond(line) + self._silent_block |= line.strip() == 'else' + if line[0] == '#': + ind = 0 if add_ind: ind += add_ind self._out.write('\t' * ind + line + '\n') @@ -1186,9 +1789,9 @@ class CodeWriter: def write_func(self, qual_ret, name, body, args=None, local_vars=None): self.write_func_prot(qual_ret=qual_ret, name=name, args=args) + self.block_start() self.write_func_lvar(local_vars=local_vars) - self.block_start() for line in body: self.p(line) self.block_end() @@ -1215,11 +1818,24 @@ class CodeWriter: for one in members: line = '.' + one[0] line += '\t' * ((longest - len(one[0]) - 1 + 7) // 8) - line += '= ' + one[1] + ',' + line += '= ' + str(one[1]) + ',' self.p(line) + def ifdef_block(self, config): + config_option = None + if config: + config_option = 'CONFIG_' + c_upper(config) + if self._ifdef_block == config_option: + return + + if self._ifdef_block: + self.p('#endif /* ' + self._ifdef_block + ' */') + if config_option: + self.p('#ifdef ' + config_option) + self._ifdef_block = config_option -scalars = {'u8', 'u16', 'u32', 'u64', 's32', 's64'} + +scalars = {'u8', 'u16', 'u32', 'u64', 's8', 's16', 's32', 's64', 'uint', 'sint'} direction_to_suffix = { 'reply': '_rsp', @@ -1283,11 +1899,15 @@ def rdir(direction): def op_prefix(ri, direction, deref=False): suffix = f"_{ri.type_name}" - if not ri.op_mode or ri.op_mode == 'do': + if not ri.op_mode: + pass + elif ri.op_mode == 'do': suffix += f"{direction_to_suffix[direction]}" else: if direction == 'request': - suffix += '_req_dump' + suffix += '_req' + if not ri.type_oneside: + suffix += '_dump' else: if ri.type_consistent: if deref: @@ -1298,7 +1918,7 @@ def op_prefix(ri, direction, deref=False): suffix += '_rsp' suffix += '_dump' if deref else '_list' - return f"{ri.family['name']}{suffix}" + return f"{ri.family.c_name}{suffix}" def type_name(ri, direction, deref=False): @@ -1331,9 +1951,39 @@ def print_dump_prototype(ri): print_prototype(ri, "request") +def put_typol_submsg(cw, struct): + cw.block_start(line=f'const struct ynl_policy_attr {struct.render_name}_policy[] =') + + i = 0 + for name, arg in struct.member_list(): + nest = "" + if arg.type == 'nest': + nest = f" .nest = &{arg.nested_render_name}_nest," + cw.p('[%d] = { .type = YNL_PT_SUBMSG, .name = "%s",%s },' % + (i, name, nest)) + i += 1 + + cw.block_end(line=';') + cw.nl() + + cw.block_start(line=f'const struct ynl_policy_nest {struct.render_name}_nest =') + cw.p(f'.max_attr = {i - 1},') + cw.p(f'.table = {struct.render_name}_policy,') + cw.block_end(line=';') + cw.nl() + + +def put_typol_fwd(cw, struct): + cw.p(f'extern const struct ynl_policy_nest {struct.render_name}_nest;') + + def put_typol(cw, struct): + if struct.submsg: + put_typol_submsg(cw, struct) + return + type_max = struct.attr_set.max_name - cw.block_start(line=f'struct ynl_policy_attr {struct.render_name}_policy[{type_max} + 1] =') + cw.block_start(line=f'const struct ynl_policy_attr {struct.render_name}_policy[{type_max} + 1] =') for _, arg in struct.member_list(): arg.attr_typol(cw) @@ -1341,7 +1991,7 @@ def put_typol(cw, struct): cw.block_end(line=';') cw.nl() - cw.block_start(line=f'struct ynl_policy_nest {struct.render_name}_nest =') + cw.block_start(line=f'const struct ynl_policy_nest {struct.render_name}_nest =') cw.p(f'.max_attr = {type_max},') cw.p(f'.table = {struct.render_name}_policy,') cw.block_end(line=';') @@ -1350,13 +2000,13 @@ def put_typol(cw, struct): def _put_enum_to_str_helper(cw, render_name, map_name, arg_name, enum=None): args = [f'int {arg_name}'] - if enum and not ('enum-name' in enum and not enum['enum-name']): - args = [f'enum {render_name} {arg_name}'] + if enum: + args = [enum.user_type + ' ' + arg_name] cw.write_func_prot('const char *', f'{render_name}_str', args) cw.block_start() if enum and enum.type == 'flags': cw.p(f'{arg_name} = ffs({arg_name}) - 1;') - cw.p(f'if ({arg_name} < 0 || {arg_name} >= (int)MNL_ARRAY_SIZE({map_name}))') + cw.p(f'if ({arg_name} < 0 || {arg_name} >= (int)YNL_ARRAY_SIZE({map_name}))') cw.p('return NULL;') cw.p(f'return {map_name}[{arg_name}];') cw.block_end() @@ -1364,14 +2014,20 @@ def _put_enum_to_str_helper(cw, render_name, map_name, arg_name, enum=None): def put_op_name_fwd(family, cw): - cw.write_func_prot('const char *', f'{family.name}_op_str', ['int op'], suffix=';') + cw.write_func_prot('const char *', f'{family.c_name}_op_str', ['int op'], suffix=';') def put_op_name(family, cw): - map_name = f'{family.name}_op_strmap' + map_name = f'{family.c_name}_op_strmap' cw.block_start(line=f"static const char * const {map_name}[] =") for op_name, op in family.msgs.items(): if op.rsp_value: + # Make sure we don't add duplicated entries, if multiple commands + # produce the same response in legacy families. + if family.rsp_by_value[op.rsp_value] != op: + cw.p(f'// skip "{op_name}", duplicate reply value') + continue + if op.req_value == op.rsp_value: cw.p(f'[{op.enum_name}] = "{op_name}",') else: @@ -1379,13 +2035,11 @@ def put_op_name(family, cw): cw.block_end(line=';') cw.nl() - _put_enum_to_str_helper(cw, family.name + '_op', map_name, 'op') + _put_enum_to_str_helper(cw, family.c_name + '_op', map_name, 'op') def put_enum_to_str_fwd(family, cw, enum): - args = [f'enum {enum.render_name} value'] - if 'enum-name' in enum and not enum['enum-name']: - args = ['int value'] + args = [enum.user_type + ' value'] cw.write_func_prot('const char *', f'{enum.render_name}_str', args, suffix=';') @@ -1400,21 +2054,56 @@ def put_enum_to_str(family, cw, enum): _put_enum_to_str_helper(cw, enum.render_name, map_name, 'value', enum=enum) -def put_req_nested(ri, struct): +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', f'{struct.ptr_name}obj'] - ri.cw.write_func_prot('int', f'{struct.render_name}_put', func_args) + ri.cw.write_func_prot('int', f'{struct.render_name}_put', func_args, + suffix=suffix) + + +def put_req_nested(ri, struct): + local_vars = [] + init_lines = [] + + if struct.submsg is None: + local_vars.append('struct nlattr *nest;') + init_lines.append("nest = ynl_attr_nest_start(nlh, attr_type);") + if struct.fixed_header: + local_vars.append('void *hdr;') + struct_sz = f'sizeof({struct.fixed_header})' + init_lines.append(f"hdr = ynl_nlmsg_put_extra_header(nlh, {struct_sz});") + init_lines.append(f"memcpy(hdr, &obj->_hdr, {struct_sz});") + + local_vars += put_local_vars(struct) + + put_req_nested_prototype(ri, struct, suffix='') ri.cw.block_start() - ri.cw.write_func_lvar('struct nlattr *nest;') + ri.cw.write_func_lvar(local_vars) - ri.cw.p("nest = mnl_attr_nest_start(nlh, attr_type);") + for line in init_lines: + ri.cw.p(line) for _, arg in struct.member_list(): arg.attr_put(ri, "obj") - ri.cw.p("mnl_attr_nest_end(nlh, nest);") + if struct.submsg is None: + ri.cw.p("ynl_attr_nest_end(nlh, nest);") ri.cw.nl() ri.cw.p('return 0;') @@ -1423,31 +2112,56 @@ def put_req_nested(ri, struct): def _multi_parse(ri, struct, init_lines, local_vars): + if struct.fixed_header: + local_vars += ['void *hdr;'] if struct.nested: - iter_line = "mnl_attr_for_each_nested(attr, nested)" + if struct.fixed_header: + iter_line = f"ynl_attr_for_each_nested_off(attr, nested, sizeof({struct.fixed_header}))" + else: + iter_line = "ynl_attr_for_each_nested(attr, nested)" else: - iter_line = "mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr))" + iter_line = "ynl_attr_for_each(attr, nlh, yarg->ys->family->hdr_len)" + if ri.op.fixed_header != ri.family.fixed_header: + if ri.family.is_classic(): + iter_line = f"ynl_attr_for_each(attr, nlh, sizeof({struct.fixed_header}))" + 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'] == 'array-nest': - local_vars.append(f'const struct nlattr *attr_{aspec.c_name};') - array_nests.add(arg) + 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;') + indexed_arrays.add(arg) + elif aspec['sub-type'] in scalars: + local_vars.append(f'const struct nlattr *attr_{aspec.c_name} = NULL;') + 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 - if array_nests or multi_attrs: + needs_parg |= 'sub-message' in aspec + + 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) @@ -1459,14 +2173,22 @@ def _multi_parse(ri, struct, init_lines, local_vars): for arg in struct.inherited: ri.cw.p(f'dst->{arg} = {arg};') - for anest in sorted(all_multi): - aspec = struct[anest] + if struct.fixed_header: + if struct.nested: + ri.cw.p('hdr = ynl_attr_data(nested);') + elif ri.family.is_classic(): + ri.cw.p('hdr = ynl_nlmsg_data(nlh);') + 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 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})");') ri.cw.nl() ri.cw.block_start(line=iter_line) - ri.cw.p('unsigned int type = mnl_attr_get_type(attr);') + ri.cw.p('unsigned int type = ynl_attr_type(attr);') ri.cw.nl() first = True @@ -1478,44 +2200,64 @@ 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({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->{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};") ri.cw.p('i = 0;') - ri.cw.p(f"parg.rsp_policy = &{aspec.nested_render_name}_nest;") - ri.cw.block_start(line=f"mnl_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, mnl_attr_get_type(attr)))") - ri.cw.p('return MNL_CB_ERROR;') + 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})") + 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);") + elif aspec.sub_type == 'binary' and 'exact-len' in aspec.checks: + # Length is validated by typol + ri.cw.p(f'memcpy(dst->{aspec.c_name}[i], ynl_attr_data(attr), {aspec.checks["exact-len"]});') + else: + raise Exception(f"Nest parsing type not supported in {aspec['name']}") ri.cw.p('i++;') ri.cw.block_end() 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->n_{aspec.c_name} = n_{aspec.c_name};") + ri.cw.p(f"dst->_count.{aspec.c_name} = n_{aspec.c_name};") ri.cw.p('i = 0;') if 'nested-attributes' in aspec: ri.cw.p(f"parg.rsp_policy = &{aspec.nested_render_name}_nest;") ri.cw.block_start(line=iter_line) - ri.cw.block_start(line=f"if (mnl_attr_get_type(attr) == {aspec.enum_name})") + ri.cw.block_start(line=f"if (ynl_attr_type(attr) == {aspec.enum_name})") 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))") - ri.cw.p('return MNL_CB_ERROR;') - elif aspec['type'] in scalars: - t = aspec['type'] - if t[0] == 's': - t = 'u' + t[1:] - ri.cw.p(f"dst->{aspec.c_name}[i] = mnl_attr_get_{t}(attr);") + ri.cw.p('return YNL_PARSE_CB_ERROR;') + elif aspec.type in scalars: + ri.cw.p(f"dst->{aspec.c_name}[i] = ynl_attr_get_{aspec.type}(attr);") + elif aspec.type == 'binary' and 'struct' in aspec: + ri.cw.p('size_t len = ynl_attr_data_len(attr);') + ri.cw.nl() + ri.cw.p(f'if (len > sizeof(dst->{aspec.c_name}[0]))') + ri.cw.p(f'len = sizeof(dst->{aspec.c_name}[0]);') + ri.cw.p(f"memcpy(&dst->{aspec.c_name}[i], ynl_attr_data(attr), len);") + elif aspec.type == 'string': + ri.cw.p('unsigned int len;') + ri.cw.nl() + ri.cw.p('len = strnlen(ynl_attr_get_str(attr), ynl_attr_data_len(attr));') + ri.cw.p(f'dst->{aspec.c_name}[i] = malloc(sizeof(struct ynl_string) + len + 1);') + ri.cw.p(f"dst->{aspec.c_name}[i]->len = len;") + ri.cw.p(f"memcpy(dst->{aspec.c_name}[i]->str, ynl_attr_get_str(attr), len);") + ri.cw.p(f"dst->{aspec.c_name}[i]->str[len] = 0;") else: - raise Exception('Nest parsing type not supported yet') + raise Exception(f'Nest parsing of type {aspec.type} not supported yet') ri.cw.p('i++;') ri.cw.block_end() ri.cw.block_end() @@ -1525,24 +2267,79 @@ def _multi_parse(ri, struct, init_lines, local_vars): if struct.nested: ri.cw.p('return 0;') else: - ri.cw.p('return MNL_CB_OK;') + ri.cw.p('return YNL_PARSE_CB_OK;') ri.cw.block_end() ri.cw.nl() -def parse_rsp_nested(ri, struct): +def parse_rsp_submsg(ri, struct): + parse_rsp_nested_prototype(ri, struct, suffix='') + + var = 'dst' + local_vars = {'const struct nlattr *attr = nested;', + f'{struct.ptr_name}{var} = yarg->data;', + 'struct ynl_parse_arg parg;'} + + for _, arg in struct.member_list(): + _, _, l_vars = arg._attr_get(ri, var) + local_vars |= set(l_vars) if l_vars else set() + + ri.cw.block_start() + ri.cw.write_func_lvar(list(local_vars)) + ri.cw.p('parg.ys = yarg->ys;') + ri.cw.nl() + + first = True + for name, arg in struct.member_list(): + kw = 'if' if first else 'else if' + first = False + + ri.cw.block_start(line=f'{kw} (!strcmp(sel, "{name}"))') + get_lines, init_lines, _ = arg._attr_get(ri, var) + for line in init_lines or []: + ri.cw.p(line) + for line in get_lines: + ri.cw.p(line) + if arg.presence_type() == 'present': + ri.cw.p(f"{var}->_present.{arg.c_name} = 1;") + ri.cw.block_end() + ri.cw.p('return 0;') + ri.cw.block_end() + ri.cw.nl() + + +def parse_rsp_nested_prototype(ri, struct, suffix=';'): func_args = ['struct ynl_parse_arg *yarg', 'const struct nlattr *nested'] + for sel in struct.external_selectors(): + func_args.append('const char *_sel_' + sel.name) + if struct.submsg: + func_args.insert(1, 'const char *sel') for arg in struct.inherited: func_args.append('__u32 ' + arg) + ri.cw.write_func_prot('int', f'{struct.render_name}_parse', func_args, + suffix=suffix) + + +def parse_rsp_nested(ri, struct): + if struct.submsg: + return parse_rsp_submsg(ri, struct) + + parse_rsp_nested_prototype(ri, struct, suffix='') + local_vars = ['const struct nlattr *attr;', f'{struct.ptr_name}dst = yarg->data;'] init_lines = [] - ri.cw.write_func_prot('int', f'{struct.render_name}_parse', func_args) - - _multi_parse(ri, struct, init_lines, local_vars) + if struct.member_list(): + _multi_parse(ri, struct, init_lines, local_vars) + else: + # Empty nest + ri.cw.block_start() + ri.cw.p('return 0;') + ri.cw.block_end() + ri.cw.nl() def parse_rsp_msg(ri, deref=False): @@ -1550,10 +2347,9 @@ def parse_rsp_msg(ri, deref=False): return func_args = ['const struct nlmsghdr *nlh', - 'void *data'] + 'struct ynl_parse_arg *yarg'] local_vars = [f'{type_name(ri, "reply", deref=deref)} *dst;', - 'struct ynl_parse_arg *yarg = data;', 'const struct nlattr *attr;'] init_lines = ['dst = yarg->data;'] @@ -1564,7 +2360,7 @@ def parse_rsp_msg(ri, deref=False): else: # Empty reply ri.cw.block_start() - ri.cw.p('return MNL_CB_OK;') + ri.cw.p('return YNL_PARSE_CB_OK;') ri.cw.block_end() ri.cw.nl() @@ -1573,30 +2369,46 @@ def print_req(ri): ret_ok = '0' ret_err = '-1' direction = "request" - local_vars = ['struct nlmsghdr *nlh;', + local_vars = ['struct ynl_req_state yrs = { .yarg = { .ys = ys, }, };', + 'struct nlmsghdr *nlh;', 'int err;'] if 'reply' in ri.op[ri.op_mode]: ret_ok = 'rsp' ret_err = 'NULL' - local_vars += [f'{type_name(ri, rdir(direction))} *rsp;', - 'struct ynl_req_state yrs = { .yarg = { .ys = ys, }, };'] + local_vars += [f'{type_name(ri, rdir(direction))} *rsp;'] + + if ri.struct["request"].fixed_header: + local_vars += ['size_t hdr_len;', + 'void *hdr;'] + + local_vars += put_local_vars(ri.struct['request']) print_prototype(ri, direction, terminate=False) ri.cw.block_start() ri.cw.write_func_lvar(local_vars) - ri.cw.p(f"nlh = ynl_gemsg_start_req(ys, {ri.nl.get_family_id()}, {ri.op.enum_name}, 1);") + if ri.family.is_classic(): + ri.cw.p(f"nlh = ynl_msg_start_req(ys, {ri.op.enum_name}, req->_nlmsg_flags);") + else: + ri.cw.p(f"nlh = ynl_gemsg_start_req(ys, {ri.nl.get_family_id()}, {ri.op.enum_name}, 1);") ri.cw.p(f"ys->req_policy = &{ri.struct['request'].render_name}_nest;") + ri.cw.p(f"ys->req_hdr_len = {ri.fixed_hdr_len};") if 'reply' in ri.op[ri.op_mode]: ri.cw.p(f"yrs.yarg.rsp_policy = &{ri.struct['reply'].render_name}_nest;") ri.cw.nl() + + if ri.struct['request'].fixed_header: + ri.cw.p("hdr_len = sizeof(req->_hdr);") + ri.cw.p("hdr = ynl_nlmsg_put_extra_header(nlh, hdr_len);") + ri.cw.p("memcpy(hdr, &req->_hdr, hdr_len);") + ri.cw.nl() + for _, attr in ri.struct["request"].member_list(): attr.attr_put(ri, "req") ri.cw.nl() - parse_arg = "NULL" if 'reply' in ri.op[ri.op_mode]: ri.cw.p('rsp = calloc(1, sizeof(*rsp));') ri.cw.p('yrs.yarg.data = rsp;') @@ -1606,8 +2418,7 @@ def print_req(ri): else: ri.cw.p(f'yrs.rsp_cmd = {ri.op.rsp_value};') ri.cw.nl() - parse_arg = '&yrs' - ri.cw.p(f"err = ynl_exec(ys, nlh, {parse_arg});") + ri.cw.p("err = ynl_exec(ys, nlh, &yrs);") ri.cw.p('if (err < 0)') if 'reply' in ri.op[ri.op_mode]: ri.cw.p('goto err_free;') @@ -1634,23 +2445,39 @@ def print_dump(ri): 'struct nlmsghdr *nlh;', 'int err;'] - for var in local_vars: - ri.cw.p(f'{var}') - ri.cw.nl() + if ri.struct['request'].fixed_header: + 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.p('yds.ys = ys;') + ri.cw.write_func_lvar(local_vars) + + ri.cw.p('yds.yarg.ys = ys;') + ri.cw.p(f"yds.yarg.rsp_policy = &{ri.struct['reply'].render_name}_nest;") + ri.cw.p("yds.yarg.data = NULL;") ri.cw.p(f"yds.alloc_sz = sizeof({type_name(ri, rdir(direction))});") ri.cw.p(f"yds.cb = {op_prefix(ri, 'reply', deref=True)}_parse;") if ri.op.value is not None: ri.cw.p(f'yds.rsp_cmd = {ri.op.enum_name};') else: ri.cw.p(f'yds.rsp_cmd = {ri.op.rsp_value};') - ri.cw.p(f"yds.rsp_policy = &{ri.struct['reply'].render_name}_nest;") ri.cw.nl() - ri.cw.p(f"nlh = ynl_gemsg_start_dump(ys, {ri.nl.get_family_id()}, {ri.op.enum_name}, 1);") + if ri.family.is_classic(): + ri.cw.p(f"nlh = ynl_msg_start_dump(ys, {ri.op.enum_name});") + else: + ri.cw.p(f"nlh = ynl_gemsg_start_dump(ys, {ri.nl.get_family_id()}, {ri.op.enum_name}, 1);") + + if ri.struct['request'].fixed_header: + ri.cw.p("hdr_len = sizeof(req->_hdr);") + ri.cw.p("hdr = ynl_nlmsg_put_extra_header(nlh, hdr_len);") + ri.cw.p("memcpy(hdr, &req->_hdr, hdr_len);") + ri.cw.nl() if "request" in ri.op[ri.op_mode]: ri.cw.p(f"ys->req_policy = &{ri.struct['request'].render_name}_nest;") + ri.cw.p(f"ys->req_hdr_len = {ri.fixed_hdr_len};") ri.cw.nl() for _, attr in ri.struct["request"].member_list(): attr.attr_put(ri, "req") @@ -1679,11 +2506,22 @@ def free_arg_name(direction): return 'obj' -def print_alloc_wrapper(ri, direction): +def print_alloc_wrapper(ri, direction, struct=None): name = op_prefix(ri, direction) - ri.cw.write_func_prot(f'static inline struct {name} *', f"{name}_alloc", [f"void"]) + struct_name = name + if ri.type_name_conflict: + struct_name += '_' + + args = ["void"] + cnt = "1" + if struct and struct.in_multi_val: + args = ["unsigned int n"] + cnt = "n" + + ri.cw.write_func_prot(f'static inline struct {struct_name} *', + f"{name}_alloc", args) ri.cw.block_start() - ri.cw.p(f'return calloc(1, sizeof(struct {name}));') + ri.cw.p(f'return calloc({cnt}, sizeof(struct {struct_name}));') ri.cw.block_end() @@ -1696,28 +2534,45 @@ def print_free_prototype(ri, direction, suffix=';'): ri.cw.write_func_prot('void', f"{name}_free", [f"struct {struct_name} *{arg}"], suffix=suffix) +def print_nlflags_set(ri, direction): + name = op_prefix(ri, direction) + ri.cw.write_func_prot('static inline void', f"{name}_set_nlflags", + [f"struct {name} *req", "__u16 nl_flags"]) + ri.cw.block_start() + ri.cw.p('req->_nlmsg_flags = nl_flags;') + ri.cw.block_end() + ri.cw.nl() + + def _print_type(ri, direction, struct): suffix = f'_{ri.type_name}{direction_to_suffix[direction]}' if not direction and ri.type_name_conflict: suffix += '_' - if ri.op_mode == 'dump': + if ri.op_mode == 'dump' and not ri.type_oneside: suffix += '_dump' - ri.cw.block_start(line=f"struct {ri.family['name']}{suffix}") + ri.cw.block_start(line=f"struct {ri.family.c_name}{suffix}") - meta_started = False - for _, attr in struct.member_list(): - for type_filter in ['len', 'bit']: + if ri.needs_nlflags(direction): + ri.cw.p('__u16 _nlmsg_flags;') + ri.cw.nl() + if struct.fixed_header: + ri.cw.p(struct.fixed_header + ' _hdr;') + ri.cw.nl() + + for type_filter in ['present', 'len', 'count']: + meta_started = False + for _, attr in struct.member_list(): line = attr.presence_member(ri.ku_space, type_filter) if line: if not meta_started: - ri.cw.block_start(line=f"struct") + ri.cw.block_start(line="struct") meta_started = True ri.cw.p(line) - if meta_started: - ri.cw.block_end(line='_present;') - ri.cw.nl() + if meta_started: + ri.cw.block_end(line=f'_{type_filter};') + ri.cw.nl() for arg in struct.inherited: ri.cw.p(f"__u32 {arg};") @@ -1736,11 +2591,27 @@ def print_type(ri, direction): def print_type_full(ri, struct): _print_type(ri, "", struct) + if struct.request and struct.in_multi_val: + print_alloc_wrapper(ri, "", struct) + ri.cw.nl() + free_rsp_nested_prototype(ri) + ri.cw.nl() + + # Name conflicts are too hard to deal with with the current code base, + # they are very rare so don't bother printing setters in that case. + if ri.ku_space == 'user' and not ri.type_name_conflict: + for _, attr in struct.member_list(): + attr.setter(ri, ri.attr_set, "", var="obj") + ri.cw.nl() + def print_type_helpers(ri, direction, deref=False): print_free_prototype(ri, direction) ri.cw.nl() + if ri.needs_nlflags(direction): + print_nlflags_set(ri, direction) + if ri.ku_space == 'user' and direction == 'request': for _, attr in ri.struct[direction].member_list(): attr.setter(ri, ri.attr_set, direction, deref=deref) @@ -1748,6 +2619,8 @@ def print_type_helpers(ri, direction, deref=False): def print_req_type_helpers(ri): + if ri.type_empty("request"): + return print_alloc_wrapper(ri, "request") print_type_helpers(ri, "request") @@ -1769,6 +2642,8 @@ def print_parse_prototype(ri, direction, terminate=True): def print_req_type(ri): + if ri.type_empty("request"): + return print_type(ri, "request") @@ -1797,7 +2672,7 @@ def print_wrapped_type(ri): ri.cw.p('__u8 cmd;') ri.cw.p('struct ynl_ntf_base_type *next;') ri.cw.p(f"void (*free)({type_name(ri, 'reply')} *ntf);") - ri.cw.p(f"{type_name(ri, 'reply', deref=True)} obj __attribute__ ((aligned (8)));") + ri.cw.p(f"{type_name(ri, 'reply', deref=True)} obj __attribute__((aligned(8)));") ri.cw.block_end(line=';') ri.cw.nl() print_free_prototype(ri, 'reply') @@ -1805,11 +2680,9 @@ def print_wrapped_type(ri): def _free_type_members_iter(ri, struct): - for _, attr in struct.member_list(): - if attr.free_needs_iter(): - ri.cw.p('unsigned int i;') - ri.cw.nl() - break + if struct.free_needs_iter(): + ri.cw.p('unsigned int i;') + ri.cw.nl() def _free_type_members(ri, var, struct, ref=''): @@ -1830,6 +2703,10 @@ def _free_type(ri, direction, struct): ri.cw.nl() +def free_rsp_nested_prototype(ri): + print_free_prototype(ri, "") + + def free_rsp_nested(ri, struct): _free_type(ri, "", struct) @@ -1854,7 +2731,7 @@ def print_dump_type_free(ri): ri.cw.nl() _free_type_members(ri, 'rsp', ri.struct['reply'], ref='obj.') - ri.cw.p(f'free(rsp);') + ri.cw.p('free(rsp);') ri.cw.block_end() ri.cw.block_end() ri.cw.nl() @@ -1865,7 +2742,7 @@ def print_ntf_type_free(ri): ri.cw.block_start() _free_type_members_iter(ri, ri.struct['reply']) _free_type_members(ri, 'rsp', ri.struct['reply'], ref='obj.') - ri.cw.p(f'free(rsp);') + ri.cw.p('free(rsp);') ri.cw.block_end() ri.cw.nl() @@ -1895,10 +2772,13 @@ def print_req_policy_fwd(cw, struct, ri=None, terminate=True): def print_req_policy(cw, struct, ri=None): + if ri and ri.op: + cw.ifdef_block(ri.op.get('config-cond', None)) print_req_policy_fwd(cw, struct, ri=ri, terminate=False) for _, arg in struct.member_list(): arg.attr_policy(cw) cw.p("};") + cw.ifdef_block(None) cw.nl() @@ -1910,11 +2790,78 @@ def policy_should_be_static(family): return family.kernel_policy == 'split' or kernel_can_gen_family_struct(family) +def print_kernel_policy_ranges(family, cw): + first = True + for _, attr_set in family.attr_sets.items(): + if attr_set.subset_of: + continue + + for _, attr in attr_set.items(): + if not attr.request: + continue + if 'full-range' not in attr.checks: + continue + + if first: + cw.p('/* Integer value ranges */') + first = False + + sign = '' if attr.type[0] == 'u' else '_signed' + suffix = 'ULL' if attr.type[0] == 'u' else 'LL' + cw.block_start(line=f'static const struct netlink_range_validation{sign} {c_lower(attr.enum_name)}_range =') + members = [] + if 'min' in attr.checks: + members.append(('min', attr.get_limit_str('min', suffix=suffix))) + if 'max' in attr.checks: + members.append(('max', attr.get_limit_str('max', suffix=suffix))) + cw.write_struct_init(members) + cw.block_end(line=';') + cw.nl() + + +def print_kernel_policy_sparse_enum_validates(family, cw): + first = True + for _, attr_set in family.attr_sets.items(): + if attr_set.subset_of: + continue + + for _, attr in attr_set.items(): + if not attr.request: + continue + if not attr.enum_name: + continue + if 'sparse' not in attr.checks: + continue + + if first: + cw.p('/* Sparse enums validation callbacks */') + first = False + + cw.write_func_prot('static int', f'{c_lower(attr.enum_name)}_validate', + ['const struct nlattr *attr', 'struct netlink_ext_ack *extack']) + cw.block_start() + cw.block_start(line=f'switch (nla_get_{attr["type"]}(attr))') + enum = family.consts[attr['enum']] + first_entry = True + for entry in enum.entries.values(): + if first_entry: + first_entry = False + else: + cw.p('fallthrough;') + cw.p(f'case {entry.c_name}:') + cw.p('return 0;') + cw.block_end() + cw.p('NL_SET_ERR_MSG_ATTR(extack, attr, "invalid enum value");') + cw.p('return -EINVAL;') + cw.block_end() + cw.nl() + + def print_kernel_op_table_fwd(family, cw, terminate): exported = not kernel_can_gen_family_struct(family) if not terminate or exported: - cw.p(f"/* Ops table for {family.name} */") + cw.p(f"/* Ops table for {family.ident_name} */") pol_to_struct = {'global': 'genl_small_ops', 'per-op': 'genl_ops', @@ -1934,7 +2881,7 @@ def print_kernel_op_table_fwd(family, cw, terminate): cnt = len(family.ops) qual = 'static const' if not exported else 'const' - line = f"{qual} struct {struct_type} {family.name}_nl_ops[{cnt}]" + line = f"{qual} struct {struct_type} {family.c_name}_nl_ops[{cnt}]" if terminate: cw.p(f"extern {line};") else: @@ -1966,12 +2913,12 @@ def print_kernel_op_table_fwd(family, cw, terminate): continue if 'do' in op: - name = c_lower(f"{family.name}-nl-{op_name}-doit") + name = c_lower(f"{family.fn_prefix}-{op_name}-doit") cw.write_func_prot('int', name, ['struct sk_buff *skb', 'struct genl_info *info'], suffix=';') if 'dump' in op: - name = c_lower(f"{family.name}-nl-{op_name}-dumpit") + name = c_lower(f"{family.fn_prefix}-{op_name}-dumpit") cw.write_func_prot('int', name, ['struct sk_buff *skb', 'struct netlink_callback *cb'], suffix=';') cw.nl() @@ -1988,6 +2935,7 @@ def print_kernel_op_table(family, cw): if op.is_async: continue + cw.ifdef_block(op.get('config-cond', None)) cw.block_start() members = [('cmd', op.enum_name)] if 'dont-validate' in op: @@ -1996,13 +2944,13 @@ def print_kernel_op_table(family, cw): for x in op['dont-validate']])), ) for op_mode in ['do', 'dump']: if op_mode in op: - name = c_lower(f"{family.name}-nl-{op_name}-{op_mode}it") + name = c_lower(f"{family.fn_prefix}-{op_name}-{op_mode}it") members.append((op_mode + 'it', name)) if family.kernel_policy == 'per-op': struct = Struct(family, op['attribute-set'], type_list=op['do']['request']['attributes']) - name = c_lower(f"{family.name}-{op_name}-nl-policy") + name = c_lower(f"{family.ident_name}-{op_name}-nl-policy") members.append(('policy', name)) members.append(('maxattr', struct.attr_max_val.enum_name)) if 'flags' in op: @@ -2018,6 +2966,7 @@ def print_kernel_op_table(family, cw): if op.is_async or op_mode not in op: continue + cw.ifdef_block(op.get('config-cond', None)) cw.block_start() members = [('cmd', op.enum_name)] if 'dont-validate' in op: @@ -2033,7 +2982,7 @@ def print_kernel_op_table(family, cw): members.append(('validate', ' | '.join([c_upper('genl-dont-validate-' + x) for x in dont_validate])), ) - name = c_lower(f"{family.name}-nl-{op_name}-{op_mode}it") + name = c_lower(f"{family.fn_prefix}-{op_name}-{op_mode}it") if 'pre' in op[op_mode]: members.append((cb_names[op_mode]['pre'], c_lower(op[op_mode]['pre']))) members.append((op_mode + 'it', name)) @@ -2044,15 +2993,16 @@ def print_kernel_op_table(family, cw): type_list=op[op_mode]['request']['attributes']) if op.dual_policy: - name = c_lower(f"{family.name}-{op_name}-{op_mode}-nl-policy") + name = c_lower(f"{family.ident_name}-{op_name}-{op_mode}-nl-policy") else: - name = c_lower(f"{family.name}-{op_name}-nl-policy") + name = c_lower(f"{family.ident_name}-{op_name}-nl-policy") members.append(('policy', name)) members.append(('maxattr', struct.attr_max_val.enum_name)) flags = (op['flags'] if 'flags' in op else []) + ['cmd-cap-' + op_mode] members.append(('flags', ' | '.join([c_upper('genl-' + x) for x in flags]))) cw.write_struct_init(members) cw.block_end(line=',') + cw.ifdef_block(None) cw.block_end(line=';') cw.nl() @@ -2064,7 +3014,7 @@ def print_kernel_mcgrp_hdr(family, cw): cw.block_start('enum') for grp in family.mcgrps['list']: - grp_id = c_upper(f"{family.name}-nlgrp-{grp['name']},") + grp_id = c_upper(f"{family.ident_name}-nlgrp-{grp['name']},") cw.p(grp_id) cw.block_end(';') cw.nl() @@ -2074,10 +3024,10 @@ def print_kernel_mcgrp_src(family, cw): if not family.mcgrps['list']: return - cw.block_start('static const struct genl_multicast_group ' + family.name + '_nl_mcgrps[] =') + cw.block_start('static const struct genl_multicast_group ' + family.c_name + '_nl_mcgrps[] =') for grp in family.mcgrps['list']: name = grp['name'] - grp_id = c_upper(f"{family.name}-nlgrp-{name}") + grp_id = c_upper(f"{family.ident_name}-nlgrp-{name}") cw.p('[' + grp_id + '] = { "' + name + '", },') cw.block_end(';') cw.nl() @@ -2087,29 +3037,48 @@ def print_kernel_family_struct_hdr(family, cw): if not kernel_can_gen_family_struct(family): return - cw.p(f"extern struct genl_family {family.name}_nl_family;") + cw.p(f"extern struct genl_family {family.c_name}_nl_family;") cw.nl() + if 'sock-priv' in family.kernel_family: + cw.p(f'void {family.c_name}_nl_sock_priv_init({family.kernel_family["sock-priv"]} *priv);') + cw.p(f'void {family.c_name}_nl_sock_priv_destroy({family.kernel_family["sock-priv"]} *priv);') + cw.nl() def print_kernel_family_struct_src(family, cw): if not kernel_can_gen_family_struct(family): return - cw.block_start(f"struct genl_family {family.name}_nl_family __ro_after_init =") + if 'sock-priv' in family.kernel_family: + # Generate "trampolines" to make CFI happy + cw.write_func("static void", f"__{family.c_name}_nl_sock_priv_init", + [f"{family.c_name}_nl_sock_priv_init(priv);"], + ["void *priv"]) + cw.nl() + cw.write_func("static void", f"__{family.c_name}_nl_sock_priv_destroy", + [f"{family.c_name}_nl_sock_priv_destroy(priv);"], + ["void *priv"]) + cw.nl() + + cw.block_start(f"struct genl_family {family.ident_name}_nl_family __ro_after_init =") cw.p('.name\t\t= ' + family.fam_key + ',') cw.p('.version\t= ' + family.ver_key + ',') cw.p('.netnsok\t= true,') cw.p('.parallel_ops\t= true,') cw.p('.module\t\t= THIS_MODULE,') if family.kernel_policy == 'per-op': - cw.p(f'.ops\t\t= {family.name}_nl_ops,') - cw.p(f'.n_ops\t\t= ARRAY_SIZE({family.name}_nl_ops),') + cw.p(f'.ops\t\t= {family.c_name}_nl_ops,') + cw.p(f'.n_ops\t\t= ARRAY_SIZE({family.c_name}_nl_ops),') elif family.kernel_policy == 'split': - cw.p(f'.split_ops\t= {family.name}_nl_ops,') - cw.p(f'.n_split_ops\t= ARRAY_SIZE({family.name}_nl_ops),') + cw.p(f'.split_ops\t= {family.c_name}_nl_ops,') + cw.p(f'.n_split_ops\t= ARRAY_SIZE({family.c_name}_nl_ops),') if family.mcgrps['list']: - cw.p(f'.mcgrps\t\t= {family.name}_nl_mcgrps,') - cw.p(f'.n_mcgrps\t= ARRAY_SIZE({family.name}_nl_mcgrps),') + cw.p(f'.mcgrps\t\t= {family.c_name}_nl_mcgrps,') + cw.p(f'.n_mcgrps\t= ARRAY_SIZE({family.c_name}_nl_mcgrps),') + if 'sock-priv' in family.kernel_family: + cw.p(f'.sock_priv_size\t= sizeof({family.kernel_family["sock-priv"]}),') + cw.p(f'.sock_priv_init\t= __{family.c_name}_nl_sock_priv_init,') + cw.p(f'.sock_priv_destroy = __{family.c_name}_nl_sock_priv_destroy,') cw.block_end(';') @@ -2119,12 +3088,94 @@ def uapi_enum_start(family, cw, obj, ckey='', enum_name='enum-name'): if obj[enum_name]: start_line = 'enum ' + c_lower(obj[enum_name]) elif ckey and ckey in obj: - start_line = 'enum ' + family.name + '_' + c_lower(obj[ckey]) + start_line = 'enum ' + family.c_name + '_' + c_lower(obj[ckey]) cw.block_start(line=start_line) +def render_uapi_unified(family, cw, max_by_define, separate_ntf): + max_name = c_upper(family.get('cmd-max-name', f"{family.op_prefix}MAX")) + cnt_name = c_upper(family.get('cmd-cnt-name', f"__{family.op_prefix}MAX")) + max_value = f"({cnt_name} - 1)" + + uapi_enum_start(family, cw, family['operations'], 'enum-name') + val = 0 + for op in family.msgs.values(): + if separate_ntf and ('notify' in op or 'event' in op): + continue + + suffix = ',' + if op.value != val: + suffix = f" = {op.value}," + val = op.value + cw.p(op.enum_name + suffix) + val += 1 + cw.nl() + cw.p(cnt_name + ('' if max_by_define else ',')) + if not max_by_define: + cw.p(f"{max_name} = {max_value}") + cw.block_end(line=';') + if max_by_define: + cw.p(f"#define {max_name} {max_value}") + cw.nl() + + +def render_uapi_directional(family, cw, max_by_define): + max_name = f"{family.op_prefix}USER_MAX" + cnt_name = f"__{family.op_prefix}USER_CNT" + max_value = f"({cnt_name} - 1)" + + cw.block_start(line='enum') + cw.p(c_upper(f'{family.name}_MSG_USER_NONE = 0,')) + val = 0 + for op in family.msgs.values(): + if 'do' in op and 'event' not in op: + suffix = ',' + if op.value and op.value != val: + suffix = f" = {op.value}," + val = op.value + cw.p(op.enum_name + suffix) + val += 1 + cw.nl() + cw.p(cnt_name + ('' if max_by_define else ',')) + if not max_by_define: + cw.p(f"{max_name} = {max_value}") + cw.block_end(line=';') + if max_by_define: + cw.p(f"#define {max_name} {max_value}") + cw.nl() + + max_name = f"{family.op_prefix}KERNEL_MAX" + cnt_name = f"__{family.op_prefix}KERNEL_CNT" + max_value = f"({cnt_name} - 1)" + + cw.block_start(line='enum') + cw.p(c_upper(f'{family.name}_MSG_KERNEL_NONE = 0,')) + val = 0 + for op in family.msgs.values(): + if ('do' in op and 'reply' in op['do']) or 'notify' in op or 'event' in op: + enum_name = op.enum_name + if 'event' not in op and 'notify' not in op: + enum_name = f'{enum_name}_REPLY' + + suffix = ',' + if op.value and op.value != val: + suffix = f" = {op.value}," + val = op.value + cw.p(enum_name + suffix) + val += 1 + cw.nl() + cw.p(cnt_name + ('' if max_by_define else ',')) + if not max_by_define: + cw.p(f"{max_name} = {max_value}") + cw.block_end(line=';') + if max_by_define: + cw.p(f"#define {max_name} {max_value}") + cw.nl() + + def render_uapi(family, cw): - hdr_prot = f"_UAPI_LINUX_{family.name.upper()}_H" + hdr_prot = f"_UAPI_LINUX_{c_upper(family.uapi_header_name)}_H" + hdr_prot = hdr_prot.replace('/', '_') cw.p('#ifndef ' + hdr_prot) cw.p('#define ' + hdr_prot) cw.nl() @@ -2136,6 +3187,9 @@ def render_uapi(family, cw): defines = [] for const in family['definitions']: + if const.get('header'): + continue + if const['type'] != 'const': cw.writes_defines(defines) defines = [] @@ -2145,12 +3199,19 @@ def render_uapi(family, cw): if const['type'] == 'enum' or const['type'] == 'flags': enum = family.consts[const['name']] + if enum.header: + continue + if enum.has_doc(): - cw.p('/**') - doc = '' - if 'doc' in enum: - doc = ' - ' + enum['doc'] - cw.write_doc_line(enum.enum_name + doc) + if enum.has_entry_doc(): + cw.p('/**') + doc = '' + if 'doc' in enum: + doc = ' - ' + enum['doc'] + cw.write_doc_line(enum.enum_name + doc) + else: + cw.p('/*') + cw.write_doc_line(enum['doc'], indent=False) for entry in enum.entries.values(): if entry.has_doc(): doc = '@' + entry.c_name + ': ' + entry['doc'] @@ -2158,7 +3219,7 @@ def render_uapi(family, cw): cw.p(' */') uapi_enum_start(family, cw, const, 'name') - name_pfx = const.get('name-prefix', f"{family.name}-{const['name']}-") + name_pfx = const.get('name-prefix', f"{family.ident_name}-{const['name']}-") for entry in enum.entries.values(): suffix = ',' if entry.value_change: @@ -2173,14 +3234,18 @@ def render_uapi(family, cw): max_val = f' = {enum.get_mask()},' cw.p(max_name + max_val) else: + cnt_name = enum.enum_cnt_name max_name = c_upper(name_pfx + 'max') - cw.p('__' + max_name + ',') - cw.p(max_name + ' = (__' + max_name + ' - 1)') + if not cnt_name: + cnt_name = '__' + name_pfx + 'max' + cw.p(c_upper(cnt_name) + ',') + cw.p(max_name + ' = (' + c_upper(cnt_name) + ' - 1)') 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.name}-{const['name']}")), + f"{name_pfx}{const['name']}")), const['value']]) if defines: @@ -2193,8 +3258,7 @@ def render_uapi(family, cw): if attr_set.subset_of: continue - cnt_name = c_upper(family.get('attr-cnt-name', f"__{attr_set.name_prefix}MAX")) - max_value = f"({cnt_name} - 1)" + max_value = f"({attr_set.cnt_name} - 1)" val = 0 uapi_enum_start(family, cw, attr_set.yaml, 'enum-name') @@ -2205,8 +3269,9 @@ def render_uapi(family, cw): val = attr.value val += 1 cw.p(attr.enum_name + suffix) - cw.nl() - cw.p(cnt_name + ('' if max_by_define else ',')) + if attr_set.items(): + cw.nl() + cw.p(attr_set.cnt_name + ('' if max_by_define else ',')) if not max_by_define: cw.p(f"{attr_set.max_name} = {max_value}") cw.block_end(line=';') @@ -2217,30 +3282,12 @@ def render_uapi(family, cw): # Commands separate_ntf = 'async-prefix' in family['operations'] - max_name = c_upper(family.get('cmd-max-name', f"{family.op_prefix}MAX")) - cnt_name = c_upper(family.get('cmd-cnt-name', f"__{family.op_prefix}MAX")) - max_value = f"({cnt_name} - 1)" - - uapi_enum_start(family, cw, family['operations'], 'enum-name') - val = 0 - for op in family.msgs.values(): - if separate_ntf and ('notify' in op or 'event' in op): - continue - - suffix = ',' - if op.value != val: - suffix = f" = {op.value}," - val = op.value - cw.p(op.enum_name + suffix) - val += 1 - cw.nl() - cw.p(cnt_name + ('' if max_by_define else ',')) - if not max_by_define: - cw.p(f"{max_name} = {max_value}") - cw.block_end(line=';') - if max_by_define: - cw.p(f"#define {max_name} {max_value}") - cw.nl() + if family.msg_id_model == 'unified': + render_uapi_unified(family, cw, max_by_define, separate_ntf) + elif family.msg_id_model == 'directional': + render_uapi_directional(family, cw, max_by_define) + else: + raise Exception(f'Unsupported message enum-model {family.msg_id_model}') if separate_ntf: uapi_enum_start(family, cw, family['operations'], enum_name='async-enum') @@ -2259,7 +3306,7 @@ def render_uapi(family, cw): defines = [] for grp in family.mcgrps['list']: name = grp['name'] - defines.append([c_upper(grp.get('c-define-name', f"{family.name}-mcgrp-{name}")), + defines.append([c_upper(grp.get('c-define-name', f"{family.ident_name}-mcgrp-{name}")), f'{name}']) cw.nl() if defines: @@ -2270,7 +3317,11 @@ def render_uapi(family, cw): def _render_user_ntf_entry(ri, op): - ri.cw.block_start(line=f"[{op.enum_name}] = ") + if not ri.family.is_classic(): + ri.cw.block_start(line=f"[{op.enum_name}] = ") + else: + crud_op = ri.family.req_by_value[op.rsp_value] + ri.cw.block_start(line=f"[{crud_op.enum_name}] = ") ri.cw.p(f".alloc_sz\t= sizeof({type_name(ri, 'event')}),") ri.cw.p(f".cb\t\t= {op_prefix(ri, 'reply', deref=True)}_parse,") ri.cw.p(f".policy\t\t= &{ri.struct['reply'].render_name}_nest,") @@ -2285,7 +3336,7 @@ def render_user_family(family, cw, prototype): return if family.ntfs: - cw.block_start(line=f"static const struct ynl_ntf_info {family['name']}_ntf_info[] = ") + cw.block_start(line=f"static const struct ynl_ntf_info {family.c_name}_ntf_info[] = ") for ntf_op_name, ntf_op in family.ntfs.items(): if 'notify' in ntf_op: op = family.ops[ntf_op['notify']] @@ -2304,13 +3355,33 @@ def render_user_family(family, cw, prototype): cw.nl() cw.block_start(f'{symbol} = ') - cw.p(f'.name\t\t= "{family.name}",') + cw.p(f'.name\t\t= "{family.c_name}",') + if family.is_classic(): + cw.p('.is_classic\t= true,') + cw.p(f'.classic_id\t= {family.get("protonum")},') + if family.is_classic(): + if family.fixed_header: + cw.p(f'.hdr_len\t= sizeof(struct {c_lower(family.fixed_header)}),') + elif family.fixed_header: + cw.p(f'.hdr_len\t= sizeof(struct genlmsghdr) + sizeof(struct {c_lower(family.fixed_header)}),') + else: + cw.p('.hdr_len\t= sizeof(struct genlmsghdr),') if family.ntfs: - cw.p(f".ntf_info\t= {family['name']}_ntf_info,") - cw.p(f".ntf_info_size\t= MNL_ARRAY_SIZE({family['name']}_ntf_info),") + cw.p(f".ntf_info\t= {family.c_name}_ntf_info,") + cw.p(f".ntf_info_size\t= YNL_ARRAY_SIZE({family.c_name}_ntf_info),") 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: @@ -2323,13 +3394,17 @@ def find_kernel_root(full_path): def main(): parser = argparse.ArgumentParser(description='Netlink simple parsing generator') - parser.add_argument('--mode', dest='mode', type=str, required=True) + parser.add_argument('--mode', dest='mode', type=str, required=True, + choices=('user', 'kernel', 'uapi')) parser.add_argument('--spec', dest='spec', type=str, required=True) parser.add_argument('--header', dest='header', action='store_true', default=None) parser.add_argument('--source', dest='header', action='store_false') parser.add_argument('--user-header', nargs='+', default=[]) + parser.add_argument('--cmp-out', action='store_true', default=None, + help='Do not overwrite the output file if the new output is identical to the old') parser.add_argument('--exclude-op', action='append', default=[]) parser.add_argument('-o', dest='out_file', type=str, default=None) + parser.add_argument('--function-prefix', dest='fn_prefix', type=str) args = parser.parse_args() if args.header is None: @@ -2338,7 +3413,7 @@ def main(): exclude_ops = [re.compile(expr) for expr in args.exclude_op] try: - parsed = Family(args.spec, exclude_ops) + parsed = Family(args.spec, exclude_ops, args.fn_prefix) if parsed.license != '((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)': print('Spec license:', parsed.license) print('License must be: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)') @@ -2348,14 +3423,7 @@ def main(): os.sys.exit(1) return - supported_models = ['unified'] - if args.mode in ['user', 'kernel']: - supported_models += ['directional'] - if parsed.msg_id_model not in supported_models: - print(f'Message enum-model {parsed.msg_id_model} not supported for {args.mode} generation') - os.sys.exit(1) - - cw = CodeWriter(BaseNlLib(), args.out_file) + cw = CodeWriter(BaseNlLib(), args.out_file, overwrite=(not args.cmp_out)) _, spec_kernel = find_kernel_root(args.spec) if args.mode == 'uapi' or args.header: @@ -2365,51 +3433,68 @@ def main(): cw.p("/* Do not edit directly, auto-generated from: */") cw.p(f"/*\t{spec_kernel} */") cw.p(f"/* YNL-GEN {args.mode} {'header' if args.header else 'source'} */") - if args.exclude_op or args.user_header: + if args.exclude_op or args.user_header or args.fn_prefix: line = '' - line += ' --user-header '.join([''] + args.user_header) - line += ' --exclude-op '.join([''] + args.exclude_op) + if args.user_header: + line += ' --user-header '.join([''] + args.user_header) + if args.exclude_op: + line += ' --exclude-op '.join([''] + args.exclude_op) + if args.fn_prefix: + line += f' --function-prefix {args.fn_prefix}' cw.p(f'/* YNL-ARG{line} */') + cw.p('/* To regenerate run: tools/net/ynl/ynl-regen.sh */') cw.nl() if args.mode == 'uapi': render_uapi(parsed, cw) return - hdr_prot = f"_LINUX_{parsed.name.upper()}_GEN_H" + hdr_prot = f"_LINUX_{parsed.c_name.upper()}_GEN_H" if args.header: cw.p('#ifndef ' + hdr_prot) cw.p('#define ' + hdr_prot) cw.nl() + if args.out_file: + hdr_file = os.path.basename(args.out_file[:-2]) + ".h" + else: + hdr_file = "generated_header_file.h" + if args.mode == 'kernel': cw.p('#include <net/netlink.h>') cw.p('#include <net/genetlink.h>') cw.nl() if not args.header: if args.out_file: - cw.p(f'#include "{os.path.basename(args.out_file[:-2])}.h"') + cw.p(f'#include "{hdr_file}"') cw.nl() headers = ['uapi/' + parsed.uapi_header] + headers += parsed.kernel_family.get('headers', []) else: cw.p('#include <stdlib.h>') 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(f'#include "{hdr_file}"') cw.p('#include "ynl.h"') - headers = [parsed.uapi_header] - for definition in parsed['definitions']: + headers = [] + for definition in parsed['definitions'] + parsed['attribute-sets']: if 'header' in definition: headers.append(definition['header']) + if args.mode == 'user': + headers.append(parsed.uapi_header) + seen_header = [] for one in headers: - cw.p(f"#include <{one}>") + if one not in seen_header: + cw.p(f"#include <{one}>") + seen_header.append(one) cw.nl() if args.mode == "user": if not args.header: - cw.p("#include <libmnl/libmnl.h>") cw.p("#include <linux/genetlink.h>") cw.nl() for one in args.user_header: @@ -2449,6 +3534,9 @@ def main(): print_kernel_mcgrp_hdr(parsed, cw) print_kernel_family_struct_hdr(parsed, cw) else: + print_kernel_policy_ranges(parsed, cw) + print_kernel_policy_sparse_enum_validates(parsed, cw) + for _, struct in sorted(parsed.pure_nested_structs.items()): if struct.request: cw.p('/* Common nested types */') @@ -2511,10 +3599,9 @@ def main(): if 'dump' in op: cw.p(f"/* {op.enum_name} - dump */") ri = RenderInfo(cw, parsed, args.mode, op, 'dump') - if 'request' in op['dump']: - print_req_type(ri) - print_req_type_helpers(ri) - if not ri.type_consistent: + print_req_type(ri) + print_req_type_helpers(ri) + if not ri.type_consistent or ri.type_oneside: print_rsp_type(ri) print_wrapped_type(ri) print_dump_prototype(ri) @@ -2544,15 +3631,30 @@ def main(): put_enum_to_str(parsed, cw, const) cw.nl() + has_recursive_nests = False cw.p('/* Policies */') - for name in parsed.pure_nested_structs: - struct = Struct(parsed, name) + for struct in parsed.pure_nested_structs.values(): + if struct.recursive: + put_typol_fwd(cw, struct) + has_recursive_nests = True + if has_recursive_nests: + cw.nl() + for struct in parsed.pure_nested_structs.values(): put_typol(cw, struct) for name in parsed.root_sets: struct = Struct(parsed, name) put_typol(cw, struct) cw.p('/* Common nested types */') + if has_recursive_nests: + for attr_set, struct in parsed.pure_nested_structs.items(): + ri = RenderInfo(cw, parsed, args.mode, "", "", attr_set) + free_rsp_nested_prototype(ri) + if struct.request: + put_req_nested_prototype(ri, struct) + if struct.reply: + parse_rsp_nested_prototype(ri, struct) + cw.nl() for attr_set, struct in parsed.pure_nested_structs.items(): ri = RenderInfo(cw, parsed, args.mode, "", "", attr_set) @@ -2576,8 +3678,9 @@ def main(): if 'dump' in op: cw.p(f"/* {op.enum_name} - dump */") ri = RenderInfo(cw, parsed, args.mode, op, "dump") - if not ri.type_consistent: + if not ri.type_consistent or ri.type_oneside: parse_rsp_msg(ri, deref=True) + print_req_free(ri) print_dump_type_free(ri) print_dump(ri) cw.nl() diff --git a/tools/net/ynl/pyynl/ynl_gen_rst.py b/tools/net/ynl/pyynl/ynl_gen_rst.py new file mode 100755 index 000000000000..90ae19aac89d --- /dev/null +++ b/tools/net/ynl/pyynl/ynl_gen_rst.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0 +# -*- coding: utf-8; mode: python -*- + +""" + Script to auto generate the documentation for Netlink specifications. + + :copyright: Copyright (C) 2023 Breno Leitao <leitao@debian.org> + :license: GPL Version 2, June 1991 see linux/COPYING for details. + + This script performs extensive parsing to the Linux kernel's netlink YAML + spec files, in an effort to avoid needing to heavily mark up the original + YAML file. It uses the library code from scripts/lib. +""" + +import os.path +import pathlib +import sys +import argparse +import logging + +sys.path.append(pathlib.Path(__file__).resolve().parent.as_posix()) +from lib import YnlDocGenerator # pylint: disable=C0413 + +def parse_arguments() -> argparse.Namespace: + """Parse arguments from user""" + parser = argparse.ArgumentParser(description="Netlink RST generator") + + parser.add_argument("-v", "--verbose", action="store_true") + parser.add_argument("-o", "--output", help="Output file name") + + # Index and input are mutually exclusive + group = parser.add_mutually_exclusive_group() + group.add_argument("-i", "--input", help="YAML file name") + + args = parser.parse_args() + + if args.verbose: + logging.basicConfig(level=logging.DEBUG) + + if args.input and not os.path.isfile(args.input): + logging.warning("%s is not a valid file.", args.input) + sys.exit(-1) + + if not args.output: + logging.error("No output file specified.") + sys.exit(-1) + + if os.path.isfile(args.output): + logging.debug("%s already exists. Overwriting it.", args.output) + + return args + + +def write_to_rstfile(content: str, filename: str) -> None: + """Write the generated content into an RST file""" + logging.debug("Saving RST file to %s", filename) + + with open(filename, "w", encoding="utf-8") as rst_file: + rst_file.write(content) + + +def main() -> None: + """Main function that reads the YAML files and generates the RST files""" + + args = parse_arguments() + + parser = YnlDocGenerator() + + if args.input: + logging.debug("Parsing %s", args.input) + try: + content = parser.parse_yaml_file(os.path.join(args.input)) + except Exception as exception: + logging.warning("Failed to parse %s.", args.input) + logging.warning(exception) + sys.exit(-1) + + write_to_rstfile(content, args.output) + + +if __name__ == "__main__": + main() diff --git a/tools/net/ynl/samples/.gitignore b/tools/net/ynl/samples/.gitignore index 2aae60c4829f..05087ee323ba 100644 --- a/tools/net/ynl/samples/.gitignore +++ b/tools/net/ynl/samples/.gitignore @@ -1,3 +1,10 @@ ethtool devlink netdev +ovs +page-pool +rt-addr +rt-link +rt-route +tc +tc-filter-add diff --git a/tools/net/ynl/samples/Makefile b/tools/net/ynl/samples/Makefile index f2db8bb78309..d76cbd41cbb1 100644 --- a/tools/net/ynl/samples/Makefile +++ b/tools/net/ynl/samples/Makefile @@ -3,13 +3,13 @@ include ../Makefile.deps CC=gcc -CFLAGS=-std=gnu11 -O2 -W -Wall -Wextra -Wno-unused-parameter -Wshadow \ +CFLAGS += -std=gnu11 -O2 -W -Wall -Wextra -Wno-unused-parameter -Wshadow \ -I../lib/ -I../generated/ -idirafter $(UAPI_PATH) ifeq ("$(DEBUG)","1") CFLAGS += -g -fsanitize=address -fsanitize=leak -static-libasan endif -LDLIBS=-lmnl ../lib/ynl.a ../generated/protos.a +LDLIBS=../lib/ynl.a ../generated/protos.a SRCS=$(wildcard *.c) BINS=$(patsubst %.c,%,${SRCS}) @@ -18,13 +18,19 @@ include $(wildcard *.d) all: $(BINS) -$(BINS): ../lib/ynl.a ../generated/protos.a +CFLAGS_page-pool=$(CFLAGS_netdev) +CFLAGS_tc-filter-add:=$(CFLAGS_tc) + +$(BINS): ../lib/ynl.a ../generated/protos.a $(SRCS) + @echo -e '\tCC sample $@' + @$(COMPILE.c) $(CFLAGS_$@) $@.c -o $@.o + @$(LINK.c) $@.o -o $@ $(LDLIBS) clean: rm -f *.o *.d *~ -hardclean: clean +distclean: clean rm -f $(BINS) -.PHONY: all clean +.PHONY: all clean distclean .DEFAULT_GOAL=all diff --git a/tools/net/ynl/samples/devlink.c b/tools/net/ynl/samples/devlink.c index d2611d7ebab4..ac9dfb01f280 100644 --- a/tools/net/ynl/samples/devlink.c +++ b/tools/net/ynl/samples/devlink.c @@ -22,6 +22,7 @@ int main(int argc, char **argv) ynl_dump_foreach(devs, d) { struct devlink_info_get_req *info_req; struct devlink_info_get_rsp *info_rsp; + unsigned i; printf("%s/%s:\n", d->bus_name, d->dev_name); @@ -34,11 +35,11 @@ int main(int argc, char **argv) if (!info_rsp) goto err_free_devs; - if (info_rsp->_present.info_driver_name_len) + if (info_rsp->_len.info_driver_name) printf(" driver: %s\n", info_rsp->info_driver_name); - if (info_rsp->n_info_version_running) + if (info_rsp->_count.info_version_running) printf(" running fw:\n"); - for (unsigned i = 0; i < info_rsp->n_info_version_running; i++) + for (i = 0; i < info_rsp->_count.info_version_running; i++) printf(" %s: %s\n", info_rsp->info_version_running[i].info_version_name, info_rsp->info_version_running[i].info_version_value); diff --git a/tools/net/ynl/samples/netdev.c b/tools/net/ynl/samples/netdev.c index 06433400dddd..22609d44c89a 100644 --- a/tools/net/ynl/samples/netdev.c +++ b/tools/net/ynl/samples/netdev.c @@ -32,12 +32,24 @@ static void netdev_print_device(struct netdev_dev_get_rsp *d, unsigned int op) if (!d->_present.xdp_features) return; - printf("%llx:", d->xdp_features); - for (int i = 0; d->xdp_features > 1U << i; i++) { + printf("xdp-features (%llx):", d->xdp_features); + for (int i = 0; d->xdp_features >= 1U << i; i++) { if (d->xdp_features & (1U << i)) printf(" %s", netdev_xdp_act_str(1 << i)); } + printf(" xdp-rx-metadata-features (%llx):", d->xdp_rx_metadata_features); + for (int i = 0; d->xdp_rx_metadata_features >= 1U << i; i++) { + if (d->xdp_rx_metadata_features & (1U << i)) + printf(" %s", netdev_xdp_rx_metadata_str(1 << i)); + } + + printf(" xsk-features (%llx):", d->xsk_features); + for (int i = 0; d->xsk_features >= 1U << i; i++) { + if (d->xsk_features & (1U << i)) + printf(" %s", netdev_xsk_flags_str(1 << i)); + } + printf(" xdp-zc-max-segs=%u", d->xdp_zc_max_segs); name = netdev_op_str(op); @@ -67,7 +79,10 @@ int main(int argc, char **argv) goto err_close; printf("Select ifc ($ifindex; or 0 = dump; or -2 ntf check): "); - scanf("%d", &ifindex); + if (scanf("%d", &ifindex) != 1) { + fprintf(stderr, "Error: unable to parse input\n"); + goto err_destroy; + } if (ifindex > 0) { struct netdev_dev_get_req *req; @@ -88,6 +103,8 @@ int main(int argc, char **argv) if (!devs) goto err_close; + if (ynl_dump_empty(devs)) + fprintf(stderr, "Error: no devices reported\n"); ynl_dump_foreach(devs, d) netdev_print_device(d, 0); netdev_dev_get_list_free(devs); @@ -105,6 +122,7 @@ int main(int argc, char **argv) err_close: fprintf(stderr, "YNL: %s\n", ys->err.msg); +err_destroy: ynl_sock_destroy(ys); return 2; } diff --git a/tools/net/ynl/samples/ovs.c b/tools/net/ynl/samples/ovs.c new file mode 100644 index 000000000000..3e975c003d77 --- /dev/null +++ b/tools/net/ynl/samples/ovs.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <stdio.h> +#include <string.h> + +#include <ynl.h> + +#include "ovs_datapath-user.h" + +int main(int argc, char **argv) +{ + struct ynl_sock *ys; + int err; + + ys = ynl_sock_create(&ynl_ovs_datapath_family, NULL); + if (!ys) + return 1; + + if (argc > 1) { + struct ovs_datapath_new_req *req; + + req = ovs_datapath_new_req_alloc(); + if (!req) + goto err_close; + + ovs_datapath_new_req_set_upcall_pid(req, 1); + ovs_datapath_new_req_set_name(req, argv[1]); + + err = ovs_datapath_new(ys, req); + ovs_datapath_new_req_free(req); + if (err) + goto err_close; + } else { + struct ovs_datapath_get_req_dump *req; + struct ovs_datapath_get_list *dps; + + printf("Dump:\n"); + req = ovs_datapath_get_req_dump_alloc(); + + dps = ovs_datapath_get_dump(ys, req); + ovs_datapath_get_req_dump_free(req); + if (!dps) + goto err_close; + + ynl_dump_foreach(dps, dp) { + printf(" %s(%d): pid:%u cache:%u\n", + dp->name, dp->_hdr.dp_ifindex, + dp->upcall_pid, dp->masks_cache_size); + } + ovs_datapath_get_list_free(dps); + } + + ynl_sock_destroy(ys); + + return 0; + +err_close: + fprintf(stderr, "YNL (%d): %s\n", ys->err.code, ys->err.msg); + ynl_sock_destroy(ys); + return 2; +} diff --git a/tools/net/ynl/samples/rt-addr.c b/tools/net/ynl/samples/rt-addr.c new file mode 100644 index 000000000000..2edde5c36b18 --- /dev/null +++ b/tools/net/ynl/samples/rt-addr.c @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <stdio.h> +#include <string.h> + +#include <ynl.h> + +#include <arpa/inet.h> +#include <net/if.h> + +#include "rt-addr-user.h" + +static void rt_addr_print(struct rt_addr_getaddr_rsp *a) +{ + char ifname[IF_NAMESIZE]; + char addr_str[64]; + const char *addr; + const char *name; + + name = if_indextoname(a->_hdr.ifa_index, ifname); + if (name) + printf("%16s: ", name); + + switch (a->_len.address) { + case 4: + addr = inet_ntop(AF_INET, a->address, + addr_str, sizeof(addr_str)); + break; + case 16: + addr = inet_ntop(AF_INET6, a->address, + addr_str, sizeof(addr_str)); + break; + default: + addr = NULL; + break; + } + if (addr) + printf("%s", addr); + else + printf("[%d]", a->_len.address); + + printf("\n"); +} + +int main(int argc, char **argv) +{ + struct rt_addr_getaddr_list *rsp; + struct rt_addr_getaddr_req *req; + struct ynl_error yerr; + struct ynl_sock *ys; + + ys = ynl_sock_create(&ynl_rt_addr_family, &yerr); + if (!ys) { + fprintf(stderr, "YNL: %s\n", yerr.msg); + return 1; + } + + req = rt_addr_getaddr_req_alloc(); + if (!req) + goto err_destroy; + + rsp = rt_addr_getaddr_dump(ys, req); + rt_addr_getaddr_req_free(req); + if (!rsp) + goto err_close; + + if (ynl_dump_empty(rsp)) + fprintf(stderr, "Error: no addresses reported\n"); + ynl_dump_foreach(rsp, addr) + rt_addr_print(addr); + rt_addr_getaddr_list_free(rsp); + + ynl_sock_destroy(ys); + return 0; + +err_close: + fprintf(stderr, "YNL: %s\n", ys->err.msg); +err_destroy: + ynl_sock_destroy(ys); + return 2; +} diff --git a/tools/net/ynl/samples/rt-link.c b/tools/net/ynl/samples/rt-link.c new file mode 100644 index 000000000000..acdd4b4a0f74 --- /dev/null +++ b/tools/net/ynl/samples/rt-link.c @@ -0,0 +1,184 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <stdio.h> +#include <string.h> + +#include <ynl.h> + +#include <arpa/inet.h> +#include <net/if.h> + +#include "rt-link-user.h" + +static void rt_link_print(struct rt_link_getlink_rsp *r) +{ + unsigned int i; + + printf("%3d: ", r->_hdr.ifi_index); + + if (r->_len.ifname) + printf("%16s: ", r->ifname); + + if (r->_present.mtu) + printf("mtu %5d ", r->mtu); + + if (r->linkinfo._len.kind) + printf("kind %-8s ", r->linkinfo.kind); + else + printf(" %8s ", ""); + + if (r->prop_list._count.alt_ifname) { + printf("altname "); + for (i = 0; i < r->prop_list._count.alt_ifname; i++) + printf("%s ", r->prop_list.alt_ifname[i]->str); + printf(" "); + } + + if (r->linkinfo._present.data && r->linkinfo.data._present.netkit) { + struct rt_link_linkinfo_netkit_attrs *netkit; + const char *name; + + netkit = &r->linkinfo.data.netkit; + printf("primary %d ", netkit->primary); + + name = NULL; + if (netkit->_present.policy) + name = rt_link_netkit_policy_str(netkit->policy); + if (name) + printf("policy %s ", name); + } + + printf("\n"); +} + +static int rt_link_create_netkit(struct ynl_sock *ys) +{ + struct rt_link_getlink_ntf *ntf_gl; + struct rt_link_newlink_req *req; + struct ynl_ntf_base_type *ntf; + int ret; + + req = rt_link_newlink_req_alloc(); + if (!req) { + fprintf(stderr, "Can't alloc req\n"); + return -1; + } + + /* rtnetlink doesn't provide info about the created object. + * It expects us to set the ECHO flag and the dig the info out + * of the notifications... + */ + rt_link_newlink_req_set_nlflags(req, NLM_F_CREATE | NLM_F_ECHO); + + rt_link_newlink_req_set_linkinfo_kind(req, "netkit"); + + /* Test error messages */ + rt_link_newlink_req_set_linkinfo_data_netkit_policy(req, 10); + ret = rt_link_newlink(ys, req); + if (ret) { + printf("Testing error message for policy being bad:\n\t%s\n", ys->err.msg); + } else { + fprintf(stderr, "Warning: unexpected success creating netkit with bad attrs\n"); + goto created; + } + + rt_link_newlink_req_set_linkinfo_data_netkit_policy(req, NETKIT_DROP); + + ret = rt_link_newlink(ys, req); +created: + rt_link_newlink_req_free(req); + if (ret) { + fprintf(stderr, "YNL: %s\n", ys->err.msg); + return -1; + } + + if (!ynl_has_ntf(ys)) { + fprintf(stderr, + "Warning: interface created but received no notification, won't delete the interface\n"); + return 0; + } + + ntf = ynl_ntf_dequeue(ys); + if (ntf->cmd != RTM_NEWLINK) { + fprintf(stderr, + "Warning: unexpected notification type, won't delete the interface\n"); + return 0; + } + ntf_gl = (void *)ntf; + ret = ntf_gl->obj._hdr.ifi_index; + ynl_ntf_free(ntf); + + return ret; +} + +static void rt_link_del(struct ynl_sock *ys, int ifindex) +{ + struct rt_link_dellink_req *req; + + req = rt_link_dellink_req_alloc(); + if (!req) { + fprintf(stderr, "Can't alloc req\n"); + return; + } + + req->_hdr.ifi_index = ifindex; + if (rt_link_dellink(ys, req)) + fprintf(stderr, "YNL: %s\n", ys->err.msg); + else + fprintf(stderr, + "Trying to delete a Netkit interface (ifindex %d)\n", + ifindex); + + rt_link_dellink_req_free(req); +} + +int main(int argc, char **argv) +{ + struct rt_link_getlink_req_dump *req; + struct rt_link_getlink_list *rsp; + struct ynl_error yerr; + struct ynl_sock *ys; + int created = 0; + + ys = ynl_sock_create(&ynl_rt_link_family, &yerr); + if (!ys) { + fprintf(stderr, "YNL: %s\n", yerr.msg); + return 1; + } + + if (argc > 1) { + fprintf(stderr, "Trying to create a Netkit interface\n"); + created = rt_link_create_netkit(ys); + if (created < 0) + goto err_destroy; + } + + req = rt_link_getlink_req_dump_alloc(); + if (!req) + goto err_del_ifc; + + rsp = rt_link_getlink_dump(ys, req); + rt_link_getlink_req_dump_free(req); + if (!rsp) + goto err_close; + + if (ynl_dump_empty(rsp)) + fprintf(stderr, "Error: no links reported\n"); + ynl_dump_foreach(rsp, link) + rt_link_print(link); + rt_link_getlink_list_free(rsp); + + if (created) + rt_link_del(ys, created); + + ynl_sock_destroy(ys); + return 0; + +err_close: + fprintf(stderr, "YNL: %s\n", ys->err.msg); +err_del_ifc: + if (created) + rt_link_del(ys, created); +err_destroy: + ynl_sock_destroy(ys); + return 2; +} diff --git a/tools/net/ynl/samples/rt-route.c b/tools/net/ynl/samples/rt-route.c new file mode 100644 index 000000000000..7427104a96df --- /dev/null +++ b/tools/net/ynl/samples/rt-route.c @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <stdio.h> +#include <string.h> + +#include <ynl.h> + +#include <arpa/inet.h> +#include <net/if.h> + +#include "rt-route-user.h" + +static void rt_route_print(struct rt_route_getroute_rsp *r) +{ + char ifname[IF_NAMESIZE]; + char route_str[64]; + const char *route; + const char *name; + + /* Ignore local */ + if (r->_hdr.rtm_table == RT_TABLE_LOCAL) + return; + + if (r->_present.oif) { + name = if_indextoname(r->oif, ifname); + if (name) + printf("oif: %-16s ", name); + } + + if (r->_len.dst) { + route = inet_ntop(r->_hdr.rtm_family, r->dst, + route_str, sizeof(route_str)); + printf("dst: %s/%d", route, r->_hdr.rtm_dst_len); + } + + if (r->_len.gateway) { + route = inet_ntop(r->_hdr.rtm_family, r->gateway, + route_str, sizeof(route_str)); + printf("gateway: %s ", route); + } + + printf("\n"); +} + +int main(int argc, char **argv) +{ + struct rt_route_getroute_req_dump *req; + struct rt_route_getroute_list *rsp; + struct ynl_error yerr; + struct ynl_sock *ys; + + ys = ynl_sock_create(&ynl_rt_route_family, &yerr); + if (!ys) { + fprintf(stderr, "YNL: %s\n", yerr.msg); + return 1; + } + + req = rt_route_getroute_req_dump_alloc(); + if (!req) + goto err_destroy; + + rsp = rt_route_getroute_dump(ys, req); + rt_route_getroute_req_dump_free(req); + if (!rsp) + goto err_close; + + if (ynl_dump_empty(rsp)) + fprintf(stderr, "Error: no routeesses reported\n"); + ynl_dump_foreach(rsp, route) + rt_route_print(route); + rt_route_getroute_list_free(rsp); + + ynl_sock_destroy(ys); + return 0; + +err_close: + fprintf(stderr, "YNL: %s\n", ys->err.msg); +err_destroy: + ynl_sock_destroy(ys); + return 2; +} diff --git a/tools/net/ynl/samples/tc-filter-add.c b/tools/net/ynl/samples/tc-filter-add.c new file mode 100644 index 000000000000..97871e9e9edc --- /dev/null +++ b/tools/net/ynl/samples/tc-filter-add.c @@ -0,0 +1,335 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <arpa/inet.h> +#include <linux/pkt_sched.h> +#include <linux/tc_act/tc_vlan.h> +#include <linux/tc_act/tc_gact.h> +#include <linux/if_ether.h> +#include <net/if.h> + +#include <ynl.h> + +#include "tc-user.h" + +#define TC_HANDLE (0xFFFF << 16) + +const char *vlan_act_name(struct tc_vlan *p) +{ + switch (p->v_action) { + case TCA_VLAN_ACT_POP: + return "pop"; + case TCA_VLAN_ACT_PUSH: + return "push"; + case TCA_VLAN_ACT_MODIFY: + return "modify"; + default: + break; + } + + return "not supported"; +} + +const char *gact_act_name(struct tc_gact *p) +{ + switch (p->action) { + case TC_ACT_SHOT: + return "drop"; + case TC_ACT_OK: + return "ok"; + case TC_ACT_PIPE: + return "pipe"; + default: + break; + } + + return "not supported"; +} + +static void print_vlan(struct tc_act_vlan_attrs *vlan) +{ + printf("%s ", vlan_act_name(vlan->parms)); + if (vlan->_present.push_vlan_id) + printf("id %u ", vlan->push_vlan_id); + if (vlan->_present.push_vlan_protocol) + printf("protocol %#x ", ntohs(vlan->push_vlan_protocol)); + if (vlan->_present.push_vlan_priority) + printf("priority %u ", vlan->push_vlan_priority); +} + +static void print_gact(struct tc_act_gact_attrs *gact) +{ + struct tc_gact *p = gact->parms; + + printf("%s ", gact_act_name(p)); +} + +static void flower_print(struct tc_flower_attrs *flower, const char *kind) +{ + struct tc_act_attrs *a; + unsigned int i; + + printf("%s:\n", kind); + + if (flower->_present.key_vlan_id) + printf(" vlan_id: %u\n", flower->key_vlan_id); + if (flower->_present.key_vlan_prio) + printf(" vlan_prio: %u\n", flower->key_vlan_prio); + if (flower->_present.key_num_of_vlans) + printf(" num_of_vlans: %u\n", flower->key_num_of_vlans); + + for (i = 0; i < flower->_count.act; i++) { + a = &flower->act[i]; + printf("action order: %i %s ", i + 1, a->kind); + if (a->options._present.vlan) + print_vlan(&a->options.vlan); + else if (a->options._present.gact) + print_gact(&a->options.gact); + printf("\n"); + } + printf("\n"); +} + +static void tc_filter_print(struct tc_gettfilter_rsp *f) +{ + struct tc_options_msg *opt = &f->options; + + if (opt->_present.flower) + flower_print(&opt->flower, f->kind); + else if (f->_len.kind) + printf("%s pref %u proto: %#x\n", f->kind, + (f->_hdr.tcm_info >> 16), + ntohs(TC_H_MIN(f->_hdr.tcm_info))); +} + +static int tc_filter_add(struct ynl_sock *ys, int ifi) +{ + struct tc_newtfilter_req *req; + struct tc_act_attrs *acts; + struct tc_vlan p = { + .action = TC_ACT_PIPE, + .v_action = TCA_VLAN_ACT_PUSH + }; + __u16 flags = NLM_F_REQUEST | NLM_F_EXCL | NLM_F_CREATE; + int ret; + + req = tc_newtfilter_req_alloc(); + if (!req) { + fprintf(stderr, "tc_newtfilter_req_alloc failed\n"); + return -1; + } + memset(req, 0, sizeof(*req)); + + acts = tc_act_attrs_alloc(3); + if (!acts) { + fprintf(stderr, "tc_act_attrs_alloc\n"); + tc_newtfilter_req_free(req); + return -1; + } + memset(acts, 0, sizeof(*acts) * 3); + + req->_hdr.tcm_ifindex = ifi; + req->_hdr.tcm_parent = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_INGRESS); + req->_hdr.tcm_info = TC_H_MAKE(1 << 16, htons(ETH_P_8021Q)); + req->chain = 0; + + tc_newtfilter_req_set_nlflags(req, flags); + tc_newtfilter_req_set_kind(req, "flower"); + tc_newtfilter_req_set_options_flower_key_vlan_id(req, 100); + tc_newtfilter_req_set_options_flower_key_vlan_prio(req, 5); + tc_newtfilter_req_set_options_flower_key_num_of_vlans(req, 3); + + __tc_newtfilter_req_set_options_flower_act(req, acts, 3); + + /* Skip action at index 0 because in TC, the action array + * index starts at 1, with each index defining the action's + * order. In contrast, in YNL indexed arrays start at index 0. + */ + tc_act_attrs_set_kind(&acts[1], "vlan"); + tc_act_attrs_set_options_vlan_parms(&acts[1], &p, sizeof(p)); + tc_act_attrs_set_options_vlan_push_vlan_id(&acts[1], 200); + tc_act_attrs_set_kind(&acts[2], "vlan"); + tc_act_attrs_set_options_vlan_parms(&acts[2], &p, sizeof(p)); + tc_act_attrs_set_options_vlan_push_vlan_id(&acts[2], 300); + + tc_newtfilter_req_set_options_flower_flags(req, 0); + tc_newtfilter_req_set_options_flower_key_eth_type(req, htons(0x8100)); + + ret = tc_newtfilter(ys, req); + if (ret) + fprintf(stderr, "tc_newtfilter: %s\n", ys->err.msg); + + tc_newtfilter_req_free(req); + + return ret; +} + +static int tc_filter_show(struct ynl_sock *ys, int ifi) +{ + struct tc_gettfilter_req_dump *req; + struct tc_gettfilter_list *rsp; + + req = tc_gettfilter_req_dump_alloc(); + if (!req) { + fprintf(stderr, "tc_gettfilter_req_dump_alloc failed\n"); + return -1; + } + memset(req, 0, sizeof(*req)); + + req->_hdr.tcm_ifindex = ifi; + req->_hdr.tcm_parent = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_INGRESS); + req->_present.chain = 1; + req->chain = 0; + + rsp = tc_gettfilter_dump(ys, req); + tc_gettfilter_req_dump_free(req); + if (!rsp) { + fprintf(stderr, "YNL: %s\n", ys->err.msg); + return -1; + } + + if (ynl_dump_empty(rsp)) + fprintf(stderr, "Error: no filters reported\n"); + else + ynl_dump_foreach(rsp, flt) tc_filter_print(flt); + + tc_gettfilter_list_free(rsp); + + return 0; +} + +static int tc_filter_del(struct ynl_sock *ys, int ifi) +{ + struct tc_deltfilter_req *req; + __u16 flags = NLM_F_REQUEST; + int ret; + + req = tc_deltfilter_req_alloc(); + if (!req) { + fprintf(stderr, "tc_deltfilter_req_alloc failed\n"); + return -1; + } + memset(req, 0, sizeof(*req)); + + req->_hdr.tcm_ifindex = ifi; + req->_hdr.tcm_parent = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_INGRESS); + req->_hdr.tcm_info = TC_H_MAKE(1 << 16, htons(ETH_P_8021Q)); + tc_deltfilter_req_set_nlflags(req, flags); + + ret = tc_deltfilter(ys, req); + if (ret) + fprintf(stderr, "tc_deltfilter failed: %s\n", ys->err.msg); + + tc_deltfilter_req_free(req); + + return ret; +} + +static int tc_clsact_add(struct ynl_sock *ys, int ifi) +{ + struct tc_newqdisc_req *req; + __u16 flags = NLM_F_REQUEST | NLM_F_EXCL | NLM_F_CREATE; + int ret; + + req = tc_newqdisc_req_alloc(); + if (!req) { + fprintf(stderr, "tc_newqdisc_req_alloc failed\n"); + return -1; + } + memset(req, 0, sizeof(*req)); + + req->_hdr.tcm_ifindex = ifi; + req->_hdr.tcm_parent = TC_H_CLSACT; + req->_hdr.tcm_handle = TC_HANDLE; + tc_newqdisc_req_set_nlflags(req, flags); + tc_newqdisc_req_set_kind(req, "clsact"); + + ret = tc_newqdisc(ys, req); + if (ret) + fprintf(stderr, "tc_newqdisc failed: %s\n", ys->err.msg); + + tc_newqdisc_req_free(req); + + return ret; +} + +static int tc_clsact_del(struct ynl_sock *ys, int ifi) +{ + struct tc_delqdisc_req *req; + __u16 flags = NLM_F_REQUEST; + int ret; + + req = tc_delqdisc_req_alloc(); + if (!req) { + fprintf(stderr, "tc_delqdisc_req_alloc failed\n"); + return -1; + } + memset(req, 0, sizeof(*req)); + + req->_hdr.tcm_ifindex = ifi; + req->_hdr.tcm_parent = TC_H_CLSACT; + req->_hdr.tcm_handle = TC_HANDLE; + tc_delqdisc_req_set_nlflags(req, flags); + + ret = tc_delqdisc(ys, req); + if (ret) + fprintf(stderr, "tc_delqdisc failed: %s\n", ys->err.msg); + + tc_delqdisc_req_free(req); + + return ret; +} + +static int tc_filter_config(struct ynl_sock *ys, int ifi) +{ + int ret = 0; + + if (tc_filter_add(ys, ifi)) + return -1; + + ret = tc_filter_show(ys, ifi); + + if (tc_filter_del(ys, ifi)) + return -1; + + return ret; +} + +int main(int argc, char **argv) +{ + struct ynl_error yerr; + struct ynl_sock *ys; + int ifi, ret = 0; + + if (argc < 2) { + fprintf(stderr, "Usage: %s <interface_name>\n", argv[0]); + return 1; + } + ifi = if_nametoindex(argv[1]); + if (!ifi) { + perror("if_nametoindex"); + return 1; + } + + ys = ynl_sock_create(&ynl_tc_family, &yerr); + if (!ys) { + fprintf(stderr, "YNL: %s\n", yerr.msg); + return 1; + } + + if (tc_clsact_add(ys, ifi)) { + ret = 2; + goto err_destroy; + } + + if (tc_filter_config(ys, ifi)) + ret = 3; + + if (tc_clsact_del(ys, ifi)) + ret = 4; + +err_destroy: + ynl_sock_destroy(ys); + return ret; +} diff --git a/tools/net/ynl/samples/tc.c b/tools/net/ynl/samples/tc.c new file mode 100644 index 000000000000..0bfff0fdd792 --- /dev/null +++ b/tools/net/ynl/samples/tc.c @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <stdio.h> +#include <string.h> + +#include <ynl.h> + +#include <net/if.h> + +#include "tc-user.h" + +static void tc_qdisc_print(struct tc_getqdisc_rsp *q) +{ + char ifname[IF_NAMESIZE]; + const char *name; + + name = if_indextoname(q->_hdr.tcm_ifindex, ifname); + if (name) + printf("%16s: ", name); + + if (q->_len.kind) { + printf("%s ", q->kind); + + if (q->options._present.fq_codel) { + struct tc_fq_codel_attrs *fq_codel; + struct tc_fq_codel_xstats *stats; + + fq_codel = &q->options.fq_codel; + stats = q->stats2.app.fq_codel; + + if (fq_codel->_present.limit) + printf("limit: %dp ", fq_codel->limit); + if (fq_codel->_present.target) + printf("target: %dms ", + (fq_codel->target + 500) / 1000); + if (q->stats2.app._len.fq_codel) + printf("new_flow_cnt: %d ", + stats->qdisc_stats.new_flow_count); + } + } + + printf("\n"); +} + +int main(int argc, char **argv) +{ + struct tc_getqdisc_req_dump *req; + struct tc_getqdisc_list *rsp; + struct ynl_error yerr; + struct ynl_sock *ys; + + ys = ynl_sock_create(&ynl_tc_family, &yerr); + if (!ys) { + fprintf(stderr, "YNL: %s\n", yerr.msg); + return 1; + } + + req = tc_getqdisc_req_dump_alloc(); + if (!req) + goto err_destroy; + + rsp = tc_getqdisc_dump(ys, req); + tc_getqdisc_req_dump_free(req); + if (!rsp) + goto err_close; + + if (ynl_dump_empty(rsp)) + fprintf(stderr, "Error: no addresses reported\n"); + ynl_dump_foreach(rsp, qdisc) + tc_qdisc_print(qdisc); + tc_getqdisc_list_free(rsp); + + ynl_sock_destroy(ys); + return 0; + +err_close: + fprintf(stderr, "YNL: %s\n", ys->err.msg); +err_destroy: + ynl_sock_destroy(ys); + return 2; +} diff --git a/tools/net/ynl/tests/Makefile b/tools/net/ynl/tests/Makefile new file mode 100644 index 000000000000..c1df2e001255 --- /dev/null +++ b/tools/net/ynl/tests/Makefile @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: GPL-2.0 +# Makefile for YNL tests + +TESTS := \ + test_ynl_cli.sh \ + test_ynl_ethtool.sh \ +# end of TESTS + +all: $(TESTS) + +run_tests: + @for test in $(TESTS); do \ + ./$$test; \ + done + +install: $(TESTS) + @mkdir -p $(DESTDIR)/usr/bin + @mkdir -p $(DESTDIR)/usr/share/kselftest + @cp ../../../testing/selftests/kselftest/ktap_helpers.sh $(DESTDIR)/usr/share/kselftest/ + @for test in $(TESTS); do \ + name=$$(basename $$test .sh); \ + sed -e 's|^ynl=.*|ynl="ynl"|' \ + -e 's|^ynl_ethtool=.*|ynl_ethtool="ynl-ethtool"|' \ + -e 's|KSELFTEST_KTAP_HELPERS=.*|KSELFTEST_KTAP_HELPERS="/usr/share/kselftest/ktap_helpers.sh"|' \ + $$test > $(DESTDIR)/usr/bin/$$name; \ + chmod +x $(DESTDIR)/usr/bin/$$name; \ + done + +clean distclean: + @# Nothing to clean + +.PHONY: all install clean run_tests diff --git a/tools/net/ynl/tests/config b/tools/net/ynl/tests/config new file mode 100644 index 000000000000..339f1309c03f --- /dev/null +++ b/tools/net/ynl/tests/config @@ -0,0 +1,6 @@ +CONFIG_DUMMY=m +CONFIG_INET_DIAG=y +CONFIG_IPV6=y +CONFIG_NET_NS=y +CONFIG_NETDEVSIM=m +CONFIG_VETH=m diff --git a/tools/net/ynl/tests/test_ynl_cli.sh b/tools/net/ynl/tests/test_ynl_cli.sh new file mode 100755 index 000000000000..7c0722a08117 --- /dev/null +++ b/tools/net/ynl/tests/test_ynl_cli.sh @@ -0,0 +1,327 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# Test YNL CLI functionality + +# Load KTAP test helpers +KSELFTEST_KTAP_HELPERS="$(dirname "$(realpath "$0")")/../../../testing/selftests/kselftest/ktap_helpers.sh" +# shellcheck source=../../../testing/selftests/kselftest/ktap_helpers.sh +source "$KSELFTEST_KTAP_HELPERS" + +# Default ynl path for direct execution, can be overridden by make install +ynl="../pyynl/cli.py" + +readonly NSIM_ID="1338" +readonly NSIM_DEV_NAME="nsim${NSIM_ID}" +readonly VETH_A="veth_a" +readonly VETH_B="veth_b" + +testns="ynl-$(mktemp -u XXXXXX)" +TESTS_NO=0 + +# Test listing available families +cli_list_families() +{ + if $ynl --list-families &>/dev/null; then + ktap_test_pass "YNL CLI list families" + else + ktap_test_fail "YNL CLI list families" + fi +} +TESTS_NO=$((TESTS_NO + 1)) + +# Test netdev family operations (dev-get, queue-get) +cli_netdev_ops() +{ + local dev_output + local ifindex + + ifindex=$(ip netns exec "$testns" cat /sys/class/net/"$NSIM_DEV_NAME"/ifindex 2>/dev/null) + + dev_output=$(ip netns exec "$testns" $ynl --family netdev \ + --do dev-get --json "{\"ifindex\": $ifindex}" 2>/dev/null) + + if ! echo "$dev_output" | grep -q "ifindex"; then + ktap_test_fail "YNL CLI netdev operations (netdev dev-get output missing ifindex)" + return + fi + + if ! ip netns exec "$testns" $ynl --family netdev \ + --dump queue-get --json "{\"ifindex\": $ifindex}" &>/dev/null; then + ktap_test_fail "YNL CLI netdev operations (failed to get netdev queue info)" + return + fi + + ktap_test_pass "YNL CLI netdev operations" +} +TESTS_NO=$((TESTS_NO + 1)) + +# Test ethtool family operations (rings-get, linkinfo-get) +cli_ethtool_ops() +{ + local rings_output + local linkinfo_output + + rings_output=$(ip netns exec "$testns" $ynl --family ethtool \ + --do rings-get --json "{\"header\": {\"dev-name\": \"$NSIM_DEV_NAME\"}}" 2>/dev/null) + + if ! echo "$rings_output" | grep -q "header"; then + ktap_test_fail "YNL CLI ethtool operations (ethtool rings-get output missing header)" + return + fi + + linkinfo_output=$(ip netns exec "$testns" $ynl --family ethtool \ + --do linkinfo-get --json "{\"header\": {\"dev-name\": \"$VETH_A\"}}" 2>/dev/null) + + if ! echo "$linkinfo_output" | grep -q "header"; then + ktap_test_fail "YNL CLI ethtool operations (ethtool linkinfo-get output missing header)" + return + fi + + ktap_test_pass "YNL CLI ethtool operations" +} +TESTS_NO=$((TESTS_NO + 1)) + +# Test rt-route family operations +cli_rt_route_ops() +{ + local ifindex + + if ! $ynl --list-families 2>/dev/null | grep -q "rt-route"; then + ktap_test_skip "YNL CLI rt-route operations (rt-route family not available)" + return + fi + + ifindex=$(ip netns exec "$testns" cat /sys/class/net/"$NSIM_DEV_NAME"/ifindex 2>/dev/null) + + # Add route: 192.0.2.0/24 dev $dev scope link + if ! ip netns exec "$testns" $ynl --family rt-route --do newroute --create \ + --json "{\"dst\": \"192.0.2.0\", \"oif\": $ifindex, \"rtm-dst-len\": 24, \"rtm-family\": 2, \"rtm-scope\": 253, \"rtm-type\": 1, \"rtm-protocol\": 3, \"rtm-table\": 254}" &>/dev/null; then + ktap_test_fail "YNL CLI rt-route operations (failed to add route)" + return + fi + + local route_output + route_output=$(ip netns exec "$testns" $ynl --family rt-route --dump getroute 2>/dev/null) + if echo "$route_output" | grep -q "192.0.2.0"; then + ktap_test_pass "YNL CLI rt-route operations" + else + ktap_test_fail "YNL CLI rt-route operations (failed to verify route)" + fi + + ip netns exec "$testns" $ynl --family rt-route --do delroute \ + --json "{\"dst\": \"192.0.2.0\", \"oif\": $ifindex, \"rtm-dst-len\": 24, \"rtm-family\": 2, \"rtm-scope\": 253, \"rtm-type\": 1, \"rtm-protocol\": 3, \"rtm-table\": 254}" &>/dev/null +} +TESTS_NO=$((TESTS_NO + 1)) + +# Test rt-addr family operations +cli_rt_addr_ops() +{ + local ifindex + + if ! $ynl --list-families 2>/dev/null | grep -q "rt-addr"; then + ktap_test_skip "YNL CLI rt-addr operations (rt-addr family not available)" + return + fi + + ifindex=$(ip netns exec "$testns" cat /sys/class/net/"$NSIM_DEV_NAME"/ifindex 2>/dev/null) + + if ! ip netns exec "$testns" $ynl --family rt-addr --do newaddr \ + --json "{\"ifa-index\": $ifindex, \"local\": \"192.0.2.100\", \"ifa-prefixlen\": 24, \"ifa-family\": 2}" &>/dev/null; then + ktap_test_fail "YNL CLI rt-addr operations (failed to add address)" + return + fi + + local addr_output + addr_output=$(ip netns exec "$testns" $ynl --family rt-addr --dump getaddr 2>/dev/null) + if echo "$addr_output" | grep -q "192.0.2.100"; then + ktap_test_pass "YNL CLI rt-addr operations" + else + ktap_test_fail "YNL CLI rt-addr operations (failed to verify address)" + fi + + ip netns exec "$testns" $ynl --family rt-addr --do deladdr \ + --json "{\"ifa-index\": $ifindex, \"local\": \"192.0.2.100\", \"ifa-prefixlen\": 24, \"ifa-family\": 2}" &>/dev/null +} +TESTS_NO=$((TESTS_NO + 1)) + +# Test rt-link family operations +cli_rt_link_ops() +{ + if ! $ynl --list-families 2>/dev/null | grep -q "rt-link"; then + ktap_test_skip "YNL CLI rt-link operations (rt-link family not available)" + return + fi + + if ! ip netns exec "$testns" $ynl --family rt-link --do newlink --create \ + --json "{\"ifname\": \"dummy0\", \"linkinfo\": {\"kind\": \"dummy\"}}" &>/dev/null; then + ktap_test_fail "YNL CLI rt-link operations (failed to add link)" + return + fi + + local link_output + link_output=$(ip netns exec "$testns" $ynl --family rt-link --dump getlink 2>/dev/null) + if echo "$link_output" | grep -q "$NSIM_DEV_NAME" && echo "$link_output" | grep -q "dummy0"; then + ktap_test_pass "YNL CLI rt-link operations" + else + ktap_test_fail "YNL CLI rt-link operations (failed to verify link)" + fi + + ip netns exec "$testns" $ynl --family rt-link --do dellink \ + --json "{\"ifname\": \"dummy0\"}" &>/dev/null +} +TESTS_NO=$((TESTS_NO + 1)) + +# Test rt-neigh family operations +cli_rt_neigh_ops() +{ + local ifindex + + if ! $ynl --list-families 2>/dev/null | grep -q "rt-neigh"; then + ktap_test_skip "YNL CLI rt-neigh operations (rt-neigh family not available)" + return + fi + + ifindex=$(ip netns exec "$testns" cat /sys/class/net/"$NSIM_DEV_NAME"/ifindex 2>/dev/null) + + # Add neighbor: 192.0.2.1 dev nsim1338 lladdr 11:22:33:44:55:66 PERMANENT + if ! ip netns exec "$testns" $ynl --family rt-neigh --do newneigh --create \ + --json "{\"ndm-ifindex\": $ifindex, \"dst\": \"192.0.2.1\", \"lladdr\": \"11:22:33:44:55:66\", \"ndm-family\": 2, \"ndm-state\": 128}" &>/dev/null; then + ktap_test_fail "YNL CLI rt-neigh operations (failed to add neighbor)" + fi + + local neigh_output + neigh_output=$(ip netns exec "$testns" $ynl --family rt-neigh --dump getneigh 2>/dev/null) + if echo "$neigh_output" | grep -q "192.0.2.1"; then + ktap_test_pass "YNL CLI rt-neigh operations" + else + ktap_test_fail "YNL CLI rt-neigh operations (failed to verify neighbor)" + fi + + ip netns exec "$testns" $ynl --family rt-neigh --do delneigh \ + --json "{\"ndm-ifindex\": $ifindex, \"dst\": \"192.0.2.1\", \"lladdr\": \"11:22:33:44:55:66\", \"ndm-family\": 2}" &>/dev/null +} +TESTS_NO=$((TESTS_NO + 1)) + +# Test rt-rule family operations +cli_rt_rule_ops() +{ + if ! $ynl --list-families 2>/dev/null | grep -q "rt-rule"; then + ktap_test_skip "YNL CLI rt-rule operations (rt-rule family not available)" + return + fi + + # Add rule: from 192.0.2.0/24 lookup 100 none + if ! ip netns exec "$testns" $ynl --family rt-rule --do newrule \ + --json "{\"family\": 2, \"src-len\": 24, \"src\": \"192.0.2.0\", \"table\": 100}" &>/dev/null; then + ktap_test_fail "YNL CLI rt-rule operations (failed to add rule)" + return + fi + + local rule_output + rule_output=$(ip netns exec "$testns" $ynl --family rt-rule --dump getrule 2>/dev/null) + if echo "$rule_output" | grep -q "192.0.2.0"; then + ktap_test_pass "YNL CLI rt-rule operations" + else + ktap_test_fail "YNL CLI rt-rule operations (failed to verify rule)" + fi + + ip netns exec "$testns" $ynl --family rt-rule --do delrule \ + --json "{\"family\": 2, \"src-len\": 24, \"src\": \"192.0.2.0\", \"table\": 100}" &>/dev/null +} +TESTS_NO=$((TESTS_NO + 1)) + +# Test nlctrl family operations +cli_nlctrl_ops() +{ + local family_output + + if ! family_output=$($ynl --family nlctrl \ + --do getfamily --json "{\"family-name\": \"netdev\"}" 2>/dev/null); then + ktap_test_fail "YNL CLI nlctrl getfamily (failed to get nlctrl family info)" + return + fi + + if ! echo "$family_output" | grep -q "family-name"; then + ktap_test_fail "YNL CLI nlctrl getfamily (nlctrl getfamily output missing family-name)" + return + fi + + if ! echo "$family_output" | grep -q "family-id"; then + ktap_test_fail "YNL CLI nlctrl getfamily (nlctrl getfamily output missing family-id)" + return + fi + + ktap_test_pass "YNL CLI nlctrl getfamily" +} +TESTS_NO=$((TESTS_NO + 1)) + +setup() +{ + modprobe netdevsim &> /dev/null + if ! [ -f /sys/bus/netdevsim/new_device ]; then + ktap_skip_all "netdevsim module not available" + exit "$KSFT_SKIP" + fi + + if ! ip netns add "$testns" 2>/dev/null; then + ktap_skip_all "failed to create test namespace" + exit "$KSFT_SKIP" + fi + + echo "$NSIM_ID 1" | ip netns exec "$testns" tee /sys/bus/netdevsim/new_device >/dev/null 2>&1 || { + ktap_skip_all "failed to create netdevsim device" + exit "$KSFT_SKIP" + } + + local dev + dev=$(ip netns exec "$testns" ls /sys/bus/netdevsim/devices/netdevsim$NSIM_ID/net 2>/dev/null | head -1) + if [[ -z "$dev" ]]; then + ktap_skip_all "failed to find netdevsim device" + exit "$KSFT_SKIP" + fi + + ip -netns "$testns" link set dev "$dev" name "$NSIM_DEV_NAME" 2>/dev/null || { + ktap_skip_all "failed to rename netdevsim device" + exit "$KSFT_SKIP" + } + + ip -netns "$testns" link set dev "$NSIM_DEV_NAME" up 2>/dev/null + + if ! ip -n "$testns" link add "$VETH_A" type veth peer name "$VETH_B" 2>/dev/null; then + ktap_skip_all "failed to create veth pair" + exit "$KSFT_SKIP" + fi + + ip -n "$testns" link set "$VETH_A" up 2>/dev/null + ip -n "$testns" link set "$VETH_B" up 2>/dev/null +} + +cleanup() +{ + ip netns exec "$testns" bash -c "echo $NSIM_ID > /sys/bus/netdevsim/del_device" 2>/dev/null || true + ip netns del "$testns" 2>/dev/null || true +} + +# Check if ynl command is available +if ! command -v $ynl &>/dev/null && [[ ! -x $ynl ]]; then + ktap_skip_all "ynl command not found: $ynl" + exit "$KSFT_SKIP" +fi + +trap cleanup EXIT + +ktap_print_header +setup +ktap_set_plan "${TESTS_NO}" + +cli_list_families +cli_netdev_ops +cli_ethtool_ops +cli_rt_route_ops +cli_rt_addr_ops +cli_rt_link_ops +cli_rt_neigh_ops +cli_rt_rule_ops +cli_nlctrl_ops + +ktap_finished diff --git a/tools/net/ynl/tests/test_ynl_ethtool.sh b/tools/net/ynl/tests/test_ynl_ethtool.sh new file mode 100755 index 000000000000..b826269017f4 --- /dev/null +++ b/tools/net/ynl/tests/test_ynl_ethtool.sh @@ -0,0 +1,222 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# Test YNL ethtool functionality + +# Load KTAP test helpers +KSELFTEST_KTAP_HELPERS="$(dirname "$(realpath "$0")")/../../../testing/selftests/kselftest/ktap_helpers.sh" +# shellcheck source=../../../testing/selftests/kselftest/ktap_helpers.sh +source "$KSELFTEST_KTAP_HELPERS" + +# Default ynl-ethtool path for direct execution, can be overridden by make install +ynl_ethtool="../pyynl/ethtool.py" + +readonly NSIM_ID="1337" +readonly NSIM_DEV_NAME="nsim${NSIM_ID}" +readonly VETH_A="veth_a" +readonly VETH_B="veth_b" + +testns="ynl-ethtool-$(mktemp -u XXXXXX)" +TESTS_NO=0 + +# Uses veth device as netdevsim doesn't support basic ethtool device info +ethtool_device_info() +{ + local info_output + + info_output=$(ip netns exec "$testns" $ynl_ethtool "$VETH_A" 2>/dev/null) + + if ! echo "$info_output" | grep -q "Settings for"; then + ktap_test_fail "YNL ethtool device info (device info output missing expected content)" + return + fi + + ktap_test_pass "YNL ethtool device info" +} +TESTS_NO=$((TESTS_NO + 1)) + +ethtool_statistics() +{ + local stats_output + + stats_output=$(ip netns exec "$testns" $ynl_ethtool --statistics "$NSIM_DEV_NAME" 2>/dev/null) + + if ! echo "$stats_output" | grep -q -E "(NIC statistics|packets|bytes)"; then + ktap_test_fail "YNL ethtool statistics (statistics output missing expected content)" + return + fi + + ktap_test_pass "YNL ethtool statistics" +} +TESTS_NO=$((TESTS_NO + 1)) + +ethtool_ring_params() +{ + local ring_output + + ring_output=$(ip netns exec "$testns" $ynl_ethtool --show-ring "$NSIM_DEV_NAME" 2>/dev/null) + + if ! echo "$ring_output" | grep -q -E "(Ring parameters|RX|TX)"; then + ktap_test_fail "YNL ethtool ring parameters (ring parameters output missing expected content)" + return + fi + + if ! ip netns exec "$testns" $ynl_ethtool --set-ring "$NSIM_DEV_NAME" rx 64 2>/dev/null; then + ktap_test_fail "YNL ethtool ring parameters (set-ring command failed unexpectedly)" + return + fi + + ktap_test_pass "YNL ethtool ring parameters (show/set)" +} +TESTS_NO=$((TESTS_NO + 1)) + +ethtool_coalesce_params() +{ + if ! ip netns exec "$testns" $ynl_ethtool --show-coalesce "$NSIM_DEV_NAME" &>/dev/null; then + ktap_test_fail "YNL ethtool coalesce parameters (failed to get coalesce parameters)" + return + fi + + if ! ip netns exec "$testns" $ynl_ethtool --set-coalesce "$NSIM_DEV_NAME" rx-usecs 50 2>/dev/null; then + ktap_test_fail "YNL ethtool coalesce parameters (set-coalesce command failed unexpectedly)" + return + fi + + ktap_test_pass "YNL ethtool coalesce parameters (show/set)" +} +TESTS_NO=$((TESTS_NO + 1)) + +ethtool_pause_params() +{ + if ! ip netns exec "$testns" $ynl_ethtool --show-pause "$NSIM_DEV_NAME" &>/dev/null; then + ktap_test_fail "YNL ethtool pause parameters (failed to get pause parameters)" + return + fi + + if ! ip netns exec "$testns" $ynl_ethtool --set-pause "$NSIM_DEV_NAME" tx 1 rx 1 2>/dev/null; then + ktap_test_fail "YNL ethtool pause parameters (set-pause command failed unexpectedly)" + return + fi + + ktap_test_pass "YNL ethtool pause parameters (show/set)" +} +TESTS_NO=$((TESTS_NO + 1)) + +ethtool_features_info() +{ + local features_output + + features_output=$(ip netns exec "$testns" $ynl_ethtool --show-features "$NSIM_DEV_NAME" 2>/dev/null) + + if ! echo "$features_output" | grep -q -E "(Features|offload)"; then + ktap_test_fail "YNL ethtool features info (features output missing expected content)" + return + fi + + ktap_test_pass "YNL ethtool features info (show/set)" +} +TESTS_NO=$((TESTS_NO + 1)) + +ethtool_channels_info() +{ + local channels_output + + channels_output=$(ip netns exec "$testns" $ynl_ethtool --show-channels "$NSIM_DEV_NAME" 2>/dev/null) + + if ! echo "$channels_output" | grep -q -E "(Channel|Combined|RX|TX)"; then + ktap_test_fail "YNL ethtool channels info (channels output missing expected content)" + return + fi + + if ! ip netns exec "$testns" $ynl_ethtool --set-channels "$NSIM_DEV_NAME" combined-count 1 2>/dev/null; then + ktap_test_fail "YNL ethtool channels info (set-channels command failed unexpectedly)" + return + fi + + ktap_test_pass "YNL ethtool channels info (show/set)" +} +TESTS_NO=$((TESTS_NO + 1)) + +ethtool_time_stamping() +{ + local ts_output + + ts_output=$(ip netns exec "$testns" $ynl_ethtool --show-time-stamping "$NSIM_DEV_NAME" 2>/dev/null) + + if ! echo "$ts_output" | grep -q -E "(Time stamping|timestamping|SOF_TIMESTAMPING)"; then + ktap_test_fail "YNL ethtool time stamping (time stamping output missing expected content)" + return + fi + + ktap_test_pass "YNL ethtool time stamping" +} +TESTS_NO=$((TESTS_NO + 1)) + +setup() +{ + modprobe netdevsim &> /dev/null + if ! [ -f /sys/bus/netdevsim/new_device ]; then + ktap_skip_all "netdevsim module not available" + exit "$KSFT_SKIP" + fi + + if ! ip netns add "$testns" 2>/dev/null; then + ktap_skip_all "failed to create test namespace" + exit "$KSFT_SKIP" + fi + + echo "$NSIM_ID 1" | ip netns exec "$testns" tee /sys/bus/netdevsim/new_device >/dev/null 2>&1 || { + ktap_skip_all "failed to create netdevsim device" + exit "$KSFT_SKIP" + } + + local dev + dev=$(ip netns exec "$testns" ls /sys/bus/netdevsim/devices/netdevsim$NSIM_ID/net 2>/dev/null | head -1) + if [[ -z "$dev" ]]; then + ktap_skip_all "failed to find netdevsim device" + exit "$KSFT_SKIP" + fi + + ip -netns "$testns" link set dev "$dev" name "$NSIM_DEV_NAME" 2>/dev/null || { + ktap_skip_all "failed to rename netdevsim device" + exit "$KSFT_SKIP" + } + + ip -netns "$testns" link set dev "$NSIM_DEV_NAME" up 2>/dev/null + + if ! ip -n "$testns" link add "$VETH_A" type veth peer name "$VETH_B" 2>/dev/null; then + ktap_skip_all "failed to create veth pair" + exit "$KSFT_SKIP" + fi + + ip -n "$testns" link set "$VETH_A" up 2>/dev/null + ip -n "$testns" link set "$VETH_B" up 2>/dev/null +} + +cleanup() +{ + ip netns exec "$testns" bash -c "echo $NSIM_ID > /sys/bus/netdevsim/del_device" 2>/dev/null || true + ip netns del "$testns" 2>/dev/null || true +} + +# Check if ynl-ethtool command is available +if ! command -v $ynl_ethtool &>/dev/null && [[ ! -x $ynl_ethtool ]]; then + ktap_skip_all "ynl-ethtool command not found: $ynl_ethtool" + exit "$KSFT_SKIP" +fi + +trap cleanup EXIT + +ktap_print_header +setup +ktap_set_plan "${TESTS_NO}" + +ethtool_device_info +ethtool_statistics +ethtool_ring_params +ethtool_coalesce_params +ethtool_pause_params +ethtool_features_info +ethtool_channels_info +ethtool_time_stamping + +ktap_finished diff --git a/tools/net/ynl/ynl-regen.sh b/tools/net/ynl/ynl-regen.sh index bdba24066cf1..81b4ecd89100 100755 --- a/tools/net/ynl/ynl-regen.sh +++ b/tools/net/ynl/ynl-regen.sh @@ -1,7 +1,7 @@ #!/bin/bash # SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause -TOOL=$(dirname $(realpath $0))/ynl-gen-c.py +TOOL=$(dirname $(realpath $0))/pyynl/ynl_gen_c.py force= search= @@ -30,8 +30,8 @@ for f in $files; do fi echo -e "\tGEN ${params[2]}\t$f" - $TOOL --mode ${params[2]} --${params[3]} --spec $KDIR/${params[0]} \ - $args -o $f + $TOOL --cmp-out --mode ${params[2]} --${params[3]} \ + --spec $KDIR/${params[0]} $args -o $f done popd >>/dev/null diff --git a/tools/net/ynl/ynltool/.gitignore b/tools/net/ynl/ynltool/.gitignore new file mode 100644 index 000000000000..690d399c921a --- /dev/null +++ b/tools/net/ynl/ynltool/.gitignore @@ -0,0 +1,2 @@ +ynltool +*.d diff --git a/tools/net/ynl/ynltool/Makefile b/tools/net/ynl/ynltool/Makefile new file mode 100644 index 000000000000..f5b1de32daa5 --- /dev/null +++ b/tools/net/ynl/ynltool/Makefile @@ -0,0 +1,55 @@ +# SPDX-License-Identifier: GPL-2.0-only + +include ../Makefile.deps + +INSTALL ?= install +prefix ?= /usr + +CC := gcc +CFLAGS := -Wall -Wextra -Werror -O2 +ifeq ("$(DEBUG)","1") + CFLAGS += -g -fsanitize=address -fsanitize=leak -static-libasan +endif +CFLAGS += -I../lib -I../generated -I../../../include/uapi/ + +SRC_VERSION := \ + $(shell make --no-print-directory -sC ../../../.. kernelversion || \ + echo "unknown") + +CFLAGS += -DSRC_VERSION='"$(SRC_VERSION)"' + +SRCS := $(wildcard *.c) +OBJS := $(patsubst %.c,$(OUTPUT)%.o,$(SRCS)) + +YNLTOOL := $(OUTPUT)ynltool + +include $(wildcard *.d) + +all: $(YNLTOOL) + +Q = @ + +$(YNLTOOL): ../libynl.a $(OBJS) + $(Q)echo -e "\tLINK $@" + $(Q)$(CC) $(CFLAGS) -o $@ $(OBJS) ../libynl.a -lm + +%.o: %.c ../libynl.a + $(Q)echo -e "\tCC $@" + $(Q)$(COMPILE.c) -MMD -c -o $@ $< + +../libynl.a: + $(Q)$(MAKE) -C ../ + +clean: + rm -f *.o *.d *~ + +distclean: clean + rm -f $(YNLTOOL) + +bindir ?= /usr/bin + +install: $(YNLTOOL) + $(INSTALL) -m 0755 $(YNLTOOL) $(DESTDIR)$(bindir)/$(YNLTOOL) + +.PHONY: all clean distclean +.DEFAULT_GOAL=all diff --git a/tools/net/ynl/ynltool/json_writer.c b/tools/net/ynl/ynltool/json_writer.c new file mode 100644 index 000000000000..c8685e592cd3 --- /dev/null +++ b/tools/net/ynl/ynltool/json_writer.c @@ -0,0 +1,288 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) +/* + * Simple streaming JSON writer + * + * This takes care of the annoying bits of JSON syntax like the commas + * after elements + * + * Authors: Stephen Hemminger <stephen@networkplumber.org> + */ + +#include <stdio.h> +#include <stdbool.h> +#include <stdarg.h> +#include <assert.h> +#include <malloc.h> +#include <inttypes.h> +#include <stdint.h> + +#include "json_writer.h" + +struct json_writer { + FILE *out; + unsigned depth; + bool pretty; + char sep; +}; + +static void jsonw_indent(json_writer_t *self) +{ + unsigned i; + for (i = 0; i < self->depth; ++i) + fputs(" ", self->out); +} + +static void jsonw_eol(json_writer_t *self) +{ + if (!self->pretty) + return; + + putc('\n', self->out); + jsonw_indent(self); +} + +static void jsonw_eor(json_writer_t *self) +{ + if (self->sep != '\0') + putc(self->sep, self->out); + self->sep = ','; +} + +static void jsonw_puts(json_writer_t *self, const char *str) +{ + putc('"', self->out); + for (; *str; ++str) + switch (*str) { + case '\t': + fputs("\\t", self->out); + break; + case '\n': + fputs("\\n", self->out); + break; + case '\r': + fputs("\\r", self->out); + break; + case '\f': + fputs("\\f", self->out); + break; + case '\b': + fputs("\\b", self->out); + break; + case '\\': + fputs("\\\\", self->out); + break; + case '"': + fputs("\\\"", self->out); + break; + default: + putc(*str, self->out); + } + putc('"', self->out); +} + +json_writer_t *jsonw_new(FILE *f) +{ + json_writer_t *self = malloc(sizeof(*self)); + if (self) { + self->out = f; + self->depth = 0; + self->pretty = false; + self->sep = '\0'; + } + return self; +} + +void jsonw_destroy(json_writer_t **self_p) +{ + json_writer_t *self = *self_p; + + assert(self->depth == 0); + fputs("\n", self->out); + fflush(self->out); + free(self); + *self_p = NULL; +} + +void jsonw_pretty(json_writer_t *self, bool on) +{ + self->pretty = on; +} + +void jsonw_reset(json_writer_t *self) +{ + assert(self->depth == 0); + self->sep = '\0'; +} + +static void jsonw_begin(json_writer_t *self, int c) +{ + jsonw_eor(self); + putc(c, self->out); + ++self->depth; + self->sep = '\0'; +} + +static void jsonw_end(json_writer_t *self, int c) +{ + assert(self->depth > 0); + + --self->depth; + if (self->sep != '\0') + jsonw_eol(self); + putc(c, self->out); + self->sep = ','; +} + +void jsonw_name(json_writer_t *self, const char *name) +{ + jsonw_eor(self); + jsonw_eol(self); + self->sep = '\0'; + jsonw_puts(self, name); + putc(':', self->out); + if (self->pretty) + putc(' ', self->out); +} + +void jsonw_vprintf_enquote(json_writer_t *self, const char *fmt, va_list ap) +{ + jsonw_eor(self); + putc('"', self->out); + vfprintf(self->out, fmt, ap); + putc('"', self->out); +} + +void jsonw_printf(json_writer_t *self, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + jsonw_eor(self); + vfprintf(self->out, fmt, ap); + va_end(ap); +} + +void jsonw_start_object(json_writer_t *self) +{ + jsonw_begin(self, '{'); +} + +void jsonw_end_object(json_writer_t *self) +{ + jsonw_end(self, '}'); +} + +void jsonw_start_array(json_writer_t *self) +{ + jsonw_begin(self, '['); +} + +void jsonw_end_array(json_writer_t *self) +{ + jsonw_end(self, ']'); +} + +void jsonw_string(json_writer_t *self, const char *value) +{ + jsonw_eor(self); + jsonw_puts(self, value); +} + +void jsonw_bool(json_writer_t *self, bool val) +{ + jsonw_printf(self, "%s", val ? "true" : "false"); +} + +void jsonw_null(json_writer_t *self) +{ + jsonw_printf(self, "null"); +} + +void jsonw_float_fmt(json_writer_t *self, const char *fmt, double num) +{ + jsonw_printf(self, fmt, num); +} + +void jsonw_float(json_writer_t *self, double num) +{ + jsonw_printf(self, "%g", num); +} + +void jsonw_hu(json_writer_t *self, unsigned short num) +{ + jsonw_printf(self, "%hu", num); +} + +void jsonw_uint(json_writer_t *self, uint64_t num) +{ + jsonw_printf(self, "%"PRIu64, num); +} + +void jsonw_lluint(json_writer_t *self, unsigned long long int num) +{ + jsonw_printf(self, "%llu", num); +} + +void jsonw_int(json_writer_t *self, int64_t num) +{ + jsonw_printf(self, "%"PRId64, num); +} + +void jsonw_string_field(json_writer_t *self, const char *prop, const char *val) +{ + jsonw_name(self, prop); + jsonw_string(self, val); +} + +void jsonw_bool_field(json_writer_t *self, const char *prop, bool val) +{ + jsonw_name(self, prop); + jsonw_bool(self, val); +} + +void jsonw_float_field(json_writer_t *self, const char *prop, double val) +{ + jsonw_name(self, prop); + jsonw_float(self, val); +} + +void jsonw_float_field_fmt(json_writer_t *self, + const char *prop, + const char *fmt, + double val) +{ + jsonw_name(self, prop); + jsonw_float_fmt(self, fmt, val); +} + +void jsonw_uint_field(json_writer_t *self, const char *prop, uint64_t num) +{ + jsonw_name(self, prop); + jsonw_uint(self, num); +} + +void jsonw_hu_field(json_writer_t *self, const char *prop, unsigned short num) +{ + jsonw_name(self, prop); + jsonw_hu(self, num); +} + +void jsonw_lluint_field(json_writer_t *self, + const char *prop, + unsigned long long int num) +{ + jsonw_name(self, prop); + jsonw_lluint(self, num); +} + +void jsonw_int_field(json_writer_t *self, const char *prop, int64_t num) +{ + jsonw_name(self, prop); + jsonw_int(self, num); +} + +void jsonw_null_field(json_writer_t *self, const char *prop) +{ + jsonw_name(self, prop); + jsonw_null(self); +} diff --git a/tools/net/ynl/ynltool/json_writer.h b/tools/net/ynl/ynltool/json_writer.h new file mode 100644 index 000000000000..0f1e63c88f6a --- /dev/null +++ b/tools/net/ynl/ynltool/json_writer.h @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Simple streaming JSON writer + * + * This takes care of the annoying bits of JSON syntax like the commas + * after elements + * + * Authors: Stephen Hemminger <stephen@networkplumber.org> + */ + +#ifndef _JSON_WRITER_H_ +#define _JSON_WRITER_H_ + +#include <stdbool.h> +#include <stdint.h> +#include <stdarg.h> +#include <stdio.h> + +/* Opaque class structure */ +typedef struct json_writer json_writer_t; + +/* Create a new JSON stream */ +json_writer_t *jsonw_new(FILE *f); +/* End output to JSON stream */ +void jsonw_destroy(json_writer_t **self_p); + +/* Cause output to have pretty whitespace */ +void jsonw_pretty(json_writer_t *self, bool on); + +/* Reset separator to create new JSON */ +void jsonw_reset(json_writer_t *self); + +/* Add property name */ +void jsonw_name(json_writer_t *self, const char *name); + +/* Add value */ +void __attribute__((format(printf, 2, 0))) jsonw_vprintf_enquote(json_writer_t *self, + const char *fmt, + va_list ap); +void __attribute__((format(printf, 2, 3))) jsonw_printf(json_writer_t *self, + const char *fmt, ...); +void jsonw_string(json_writer_t *self, const char *value); +void jsonw_bool(json_writer_t *self, bool value); +void jsonw_float(json_writer_t *self, double number); +void jsonw_float_fmt(json_writer_t *self, const char *fmt, double num); +void jsonw_uint(json_writer_t *self, uint64_t number); +void jsonw_hu(json_writer_t *self, unsigned short number); +void jsonw_int(json_writer_t *self, int64_t number); +void jsonw_null(json_writer_t *self); +void jsonw_lluint(json_writer_t *self, unsigned long long int num); + +/* Useful Combinations of name and value */ +void jsonw_string_field(json_writer_t *self, const char *prop, const char *val); +void jsonw_bool_field(json_writer_t *self, const char *prop, bool value); +void jsonw_float_field(json_writer_t *self, const char *prop, double num); +void jsonw_uint_field(json_writer_t *self, const char *prop, uint64_t num); +void jsonw_hu_field(json_writer_t *self, const char *prop, unsigned short num); +void jsonw_int_field(json_writer_t *self, const char *prop, int64_t num); +void jsonw_null_field(json_writer_t *self, const char *prop); +void jsonw_lluint_field(json_writer_t *self, const char *prop, + unsigned long long int num); +void jsonw_float_field_fmt(json_writer_t *self, const char *prop, + const char *fmt, double val); + +/* Collections */ +void jsonw_start_object(json_writer_t *self); +void jsonw_end_object(json_writer_t *self); + +void jsonw_start_array(json_writer_t *self); +void jsonw_end_array(json_writer_t *self); + +/* Override default exception handling */ +typedef void (jsonw_err_handler_fn)(const char *); + +#endif /* _JSON_WRITER_H_ */ diff --git a/tools/net/ynl/ynltool/main.c b/tools/net/ynl/ynltool/main.c new file mode 100644 index 000000000000..5d0f428eed0a --- /dev/null +++ b/tools/net/ynl/ynltool/main.c @@ -0,0 +1,242 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2017-2018 Netronome Systems, Inc. */ +/* Copyright Meta Platforms, Inc. and affiliates */ + +#include <ctype.h> +#include <errno.h> +#include <getopt.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> + +#include "main.h" + +const char *bin_name; +static int last_argc; +static char **last_argv; +static int (*last_do_help)(int argc, char **argv); +json_writer_t *json_wtr; +bool pretty_output; +bool json_output; + +static void __attribute__((noreturn)) clean_and_exit(int i) +{ + if (json_output) + jsonw_destroy(&json_wtr); + + exit(i); +} + +void usage(void) +{ + last_do_help(last_argc - 1, last_argv + 1); + + clean_and_exit(-1); +} + +static int do_help(int argc __attribute__((unused)), + char **argv __attribute__((unused))) +{ + if (json_output) { + jsonw_null(json_wtr); + return 0; + } + + fprintf(stderr, + "Usage: %s [OPTIONS] OBJECT { COMMAND | help }\n" + " %s version\n" + "\n" + " OBJECT := { page-pool | qstats }\n" + " " HELP_SPEC_OPTIONS "\n" + "", + bin_name, bin_name); + + return 0; +} + +static int do_version(int argc __attribute__((unused)), + char **argv __attribute__((unused))) +{ + if (json_output) { + jsonw_start_object(json_wtr); + jsonw_name(json_wtr, "version"); + jsonw_printf(json_wtr, SRC_VERSION); + jsonw_end_object(json_wtr); + } else { + printf("%s " SRC_VERSION "\n", bin_name); + } + return 0; +} + +static const struct cmd commands[] = { + { "help", do_help }, + { "page-pool", do_page_pool }, + { "qstats", do_qstats }, + { "version", do_version }, + { 0 } +}; + +int cmd_select(const struct cmd *cmds, int argc, char **argv, + int (*help)(int argc, char **argv)) +{ + unsigned int i; + + last_argc = argc; + last_argv = argv; + last_do_help = help; + + if (argc < 1 && cmds[0].func) + return cmds[0].func(argc, argv); + + for (i = 0; cmds[i].cmd; i++) { + if (is_prefix(*argv, cmds[i].cmd)) { + if (!cmds[i].func) { + p_err("command '%s' is not available", cmds[i].cmd); + return -1; + } + return cmds[i].func(argc - 1, argv + 1); + } + } + + help(argc - 1, argv + 1); + + return -1; +} + +bool is_prefix(const char *pfx, const char *str) +{ + if (!pfx) + return false; + if (strlen(str) < strlen(pfx)) + return false; + + return !memcmp(str, pfx, strlen(pfx)); +} + +/* Last argument MUST be NULL pointer */ +int detect_common_prefix(const char *arg, ...) +{ + unsigned int count = 0; + const char *ref; + char msg[256]; + va_list ap; + + snprintf(msg, sizeof(msg), "ambiguous prefix: '%s' could be '", arg); + va_start(ap, arg); + while ((ref = va_arg(ap, const char *))) { + if (!is_prefix(arg, ref)) + continue; + count++; + if (count > 1) + strncat(msg, "' or '", sizeof(msg) - strlen(msg) - 1); + strncat(msg, ref, sizeof(msg) - strlen(msg) - 1); + } + va_end(ap); + strncat(msg, "'", sizeof(msg) - strlen(msg) - 1); + + if (count >= 2) { + p_err("%s", msg); + return -1; + } + + return 0; +} + +void p_err(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + if (json_output) { + jsonw_start_object(json_wtr); + jsonw_name(json_wtr, "error"); + jsonw_vprintf_enquote(json_wtr, fmt, ap); + jsonw_end_object(json_wtr); + } else { + fprintf(stderr, "Error: "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + } + va_end(ap); +} + +void p_info(const char *fmt, ...) +{ + va_list ap; + + if (json_output) + return; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); +} + +int main(int argc, char **argv) +{ + static const struct option options[] = { + { "json", no_argument, NULL, 'j' }, + { "help", no_argument, NULL, 'h' }, + { "pretty", no_argument, NULL, 'p' }, + { "version", no_argument, NULL, 'V' }, + { 0 } + }; + bool version_requested = false; + int opt, ret; + + setlinebuf(stdout); + + last_do_help = do_help; + pretty_output = false; + json_output = false; + bin_name = "ynltool"; + + opterr = 0; + while ((opt = getopt_long(argc, argv, "Vhjp", + options, NULL)) >= 0) { + switch (opt) { + case 'V': + version_requested = true; + break; + case 'h': + return do_help(argc, argv); + case 'p': + pretty_output = true; + /* fall through */ + case 'j': + if (!json_output) { + json_wtr = jsonw_new(stdout); + if (!json_wtr) { + p_err("failed to create JSON writer"); + return -1; + } + json_output = true; + } + jsonw_pretty(json_wtr, pretty_output); + break; + default: + p_err("unrecognized option '%s'", argv[optind - 1]); + if (json_output) + clean_and_exit(-1); + else + usage(); + } + } + + argc -= optind; + argv += optind; + if (argc < 0) + usage(); + + if (version_requested) + ret = do_version(argc, argv); + else + ret = cmd_select(commands, argc, argv, do_help); + + if (json_output) + jsonw_destroy(&json_wtr); + + return ret; +} diff --git a/tools/net/ynl/ynltool/main.h b/tools/net/ynl/ynltool/main.h new file mode 100644 index 000000000000..c7039f9ac55a --- /dev/null +++ b/tools/net/ynl/ynltool/main.h @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* Copyright (C) 2017-2018 Netronome Systems, Inc. */ +/* Copyright Meta Platforms, Inc. and affiliates */ + +#ifndef __YNLTOOL_H +#define __YNLTOOL_H + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> + +#include "json_writer.h" + +#define NEXT_ARG() ({ argc--; argv++; if (argc < 0) usage(); }) +#define NEXT_ARGP() ({ (*argc)--; (*argv)++; if (*argc < 0) usage(); }) +#define BAD_ARG() ({ p_err("what is '%s'?", *argv); -1; }) +#define GET_ARG() ({ argc--; *argv++; }) +#define REQ_ARGS(cnt) \ + ({ \ + int _cnt = (cnt); \ + bool _res; \ + \ + if (argc < _cnt) { \ + p_err("'%s' needs at least %d arguments, %d found", \ + argv[-1], _cnt, argc); \ + _res = false; \ + } else { \ + _res = true; \ + } \ + _res; \ + }) + +#define HELP_SPEC_OPTIONS \ + "OPTIONS := { {-j|--json} [{-p|--pretty}] }" + +extern const char *bin_name; + +extern json_writer_t *json_wtr; +extern bool json_output; +extern bool pretty_output; + +void __attribute__((format(printf, 1, 2))) p_err(const char *fmt, ...); +void __attribute__((format(printf, 1, 2))) p_info(const char *fmt, ...); + +bool is_prefix(const char *pfx, const char *str); +int detect_common_prefix(const char *arg, ...); +void usage(void) __attribute__((noreturn)); + +struct cmd { + const char *cmd; + int (*func)(int argc, char **argv); +}; + +int cmd_select(const struct cmd *cmds, int argc, char **argv, + int (*help)(int argc, char **argv)); + +/* subcommands */ +int do_page_pool(int argc, char **argv); +int do_qstats(int argc, char **argv); + +#endif /* __YNLTOOL_H */ diff --git a/tools/net/ynl/ynltool/page-pool.c b/tools/net/ynl/ynltool/page-pool.c new file mode 100644 index 000000000000..4b24492abab7 --- /dev/null +++ b/tools/net/ynl/ynltool/page-pool.c @@ -0,0 +1,461 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <net/if.h> + +#include <ynl.h> +#include "netdev-user.h" + +#include "main.h" + +struct pp_stat { + unsigned int ifc; + + struct { + unsigned int cnt; + size_t refs, bytes; + } live[2]; + + size_t alloc_slow, alloc_fast, recycle_ring, recycle_cache; +}; + +struct pp_stats_array { + unsigned int i, max; + struct pp_stat *s; +}; + +static struct pp_stat *find_ifc(struct pp_stats_array *a, unsigned int ifindex) +{ + unsigned int i; + + for (i = 0; i < a->i; i++) { + if (a->s[i].ifc == ifindex) + return &a->s[i]; + } + + a->i++; + if (a->i == a->max) { + a->max *= 2; + a->s = reallocarray(a->s, a->max, sizeof(*a->s)); + } + a->s[i].ifc = ifindex; + return &a->s[i]; +} + +static void count_pool(struct pp_stat *s, unsigned int l, + struct netdev_page_pool_get_rsp *pp) +{ + s->live[l].cnt++; + if (pp->_present.inflight) + s->live[l].refs += pp->inflight; + if (pp->_present.inflight_mem) + s->live[l].bytes += pp->inflight_mem; +} + +/* We don't know how many pages are sitting in cache and ring + * so we will under-count the recycling rate a bit. + */ +static void print_json_recycling_stats(struct pp_stat *s) +{ + double recycle; + + if (s->alloc_fast + s->alloc_slow) { + recycle = (double)(s->recycle_ring + s->recycle_cache) / + (s->alloc_fast + s->alloc_slow) * 100; + jsonw_float_field(json_wtr, "recycling_pct", recycle); + } + + jsonw_name(json_wtr, "alloc"); + jsonw_start_object(json_wtr); + jsonw_uint_field(json_wtr, "slow", s->alloc_slow); + jsonw_uint_field(json_wtr, "fast", s->alloc_fast); + jsonw_end_object(json_wtr); + + jsonw_name(json_wtr, "recycle"); + jsonw_start_object(json_wtr); + jsonw_uint_field(json_wtr, "ring", s->recycle_ring); + jsonw_uint_field(json_wtr, "cache", s->recycle_cache); + jsonw_end_object(json_wtr); +} + +static void print_plain_recycling_stats(struct pp_stat *s) +{ + double recycle; + + if (s->alloc_fast + s->alloc_slow) { + recycle = (double)(s->recycle_ring + s->recycle_cache) / + (s->alloc_fast + s->alloc_slow) * 100; + printf("recycling: %.1lf%% (alloc: %zu:%zu recycle: %zu:%zu)", + recycle, s->alloc_slow, s->alloc_fast, + s->recycle_ring, s->recycle_cache); + } +} + +static void print_json_stats(struct pp_stats_array *a) +{ + jsonw_start_array(json_wtr); + + for (unsigned int i = 0; i < a->i; i++) { + char ifname[IF_NAMESIZE]; + struct pp_stat *s = &a->s[i]; + const char *name; + + jsonw_start_object(json_wtr); + + if (!s->ifc) { + jsonw_string_field(json_wtr, "ifname", "<orphan>"); + jsonw_uint_field(json_wtr, "ifindex", 0); + } else { + name = if_indextoname(s->ifc, ifname); + if (name) + jsonw_string_field(json_wtr, "ifname", name); + jsonw_uint_field(json_wtr, "ifindex", s->ifc); + } + + jsonw_uint_field(json_wtr, "page_pools", s->live[1].cnt); + jsonw_uint_field(json_wtr, "zombies", s->live[0].cnt); + + jsonw_name(json_wtr, "live"); + jsonw_start_object(json_wtr); + jsonw_uint_field(json_wtr, "refs", s->live[1].refs); + jsonw_uint_field(json_wtr, "bytes", s->live[1].bytes); + jsonw_end_object(json_wtr); + + jsonw_name(json_wtr, "zombie"); + jsonw_start_object(json_wtr); + jsonw_uint_field(json_wtr, "refs", s->live[0].refs); + jsonw_uint_field(json_wtr, "bytes", s->live[0].bytes); + jsonw_end_object(json_wtr); + + if (s->alloc_fast || s->alloc_slow) + print_json_recycling_stats(s); + + jsonw_end_object(json_wtr); + } + + jsonw_end_array(json_wtr); +} + +static void print_plain_stats(struct pp_stats_array *a) +{ + for (unsigned int i = 0; i < a->i; i++) { + char ifname[IF_NAMESIZE]; + struct pp_stat *s = &a->s[i]; + const char *name; + + if (!s->ifc) { + printf("<orphan>\t"); + } else { + name = if_indextoname(s->ifc, ifname); + if (name) + printf("%8s", name); + printf("[%u]\t", s->ifc); + } + + printf("page pools: %u (zombies: %u)\n", + s->live[1].cnt, s->live[0].cnt); + printf("\t\trefs: %zu bytes: %zu (refs: %zu bytes: %zu)\n", + s->live[1].refs, s->live[1].bytes, + s->live[0].refs, s->live[0].bytes); + + if (s->alloc_fast || s->alloc_slow) { + printf("\t\t"); + print_plain_recycling_stats(s); + printf("\n"); + } + } +} + +static bool +find_pool_stat_in_list(struct netdev_page_pool_stats_get_list *pp_stats, + __u64 pool_id, struct pp_stat *pstat) +{ + ynl_dump_foreach(pp_stats, pp) { + if (!pp->_present.info || !pp->info._present.id) + continue; + if (pp->info.id != pool_id) + continue; + + memset(pstat, 0, sizeof(*pstat)); + if (pp->_present.alloc_fast) + pstat->alloc_fast = pp->alloc_fast; + if (pp->_present.alloc_refill) + pstat->alloc_fast += pp->alloc_refill; + if (pp->_present.alloc_slow) + pstat->alloc_slow = pp->alloc_slow; + if (pp->_present.recycle_ring) + pstat->recycle_ring = pp->recycle_ring; + if (pp->_present.recycle_cached) + pstat->recycle_cache = pp->recycle_cached; + return true; + } + return false; +} + +static void +print_json_pool_list(struct netdev_page_pool_get_list *pools, + struct netdev_page_pool_stats_get_list *pp_stats, + bool zombies_only) +{ + jsonw_start_array(json_wtr); + + ynl_dump_foreach(pools, pp) { + char ifname[IF_NAMESIZE]; + struct pp_stat pstat; + const char *name; + + if (zombies_only && !pp->_present.detach_time) + continue; + + jsonw_start_object(json_wtr); + + jsonw_uint_field(json_wtr, "id", pp->id); + + if (pp->_present.ifindex) { + name = if_indextoname(pp->ifindex, ifname); + if (name) + jsonw_string_field(json_wtr, "ifname", name); + jsonw_uint_field(json_wtr, "ifindex", pp->ifindex); + } + + if (pp->_present.napi_id) + jsonw_uint_field(json_wtr, "napi_id", pp->napi_id); + + if (pp->_present.inflight) + jsonw_uint_field(json_wtr, "refs", pp->inflight); + + if (pp->_present.inflight_mem) + jsonw_uint_field(json_wtr, "bytes", pp->inflight_mem); + + if (pp->_present.detach_time) + jsonw_uint_field(json_wtr, "detach_time", pp->detach_time); + + if (pp->_present.dmabuf) + jsonw_uint_field(json_wtr, "dmabuf", pp->dmabuf); + + if (find_pool_stat_in_list(pp_stats, pp->id, &pstat) && + (pstat.alloc_fast || pstat.alloc_slow)) + print_json_recycling_stats(&pstat); + + jsonw_end_object(json_wtr); + } + + jsonw_end_array(json_wtr); +} + +static void +print_plain_pool_list(struct netdev_page_pool_get_list *pools, + struct netdev_page_pool_stats_get_list *pp_stats, + bool zombies_only) +{ + ynl_dump_foreach(pools, pp) { + char ifname[IF_NAMESIZE]; + struct pp_stat pstat; + const char *name; + + if (zombies_only && !pp->_present.detach_time) + continue; + + printf("pool id: %llu", pp->id); + + if (pp->_present.ifindex) { + name = if_indextoname(pp->ifindex, ifname); + if (name) + printf(" dev: %s", name); + printf("[%u]", pp->ifindex); + } + + if (pp->_present.napi_id) + printf(" napi: %llu", pp->napi_id); + + printf("\n"); + + if (pp->_present.inflight || pp->_present.inflight_mem) { + printf(" inflight:"); + if (pp->_present.inflight) + printf(" %llu pages", pp->inflight); + if (pp->_present.inflight_mem) + printf(" %llu bytes", pp->inflight_mem); + printf("\n"); + } + + if (pp->_present.detach_time) + printf(" detached: %llu\n", pp->detach_time); + + if (pp->_present.dmabuf) + printf(" dmabuf: %u\n", pp->dmabuf); + + if (find_pool_stat_in_list(pp_stats, pp->id, &pstat) && + (pstat.alloc_fast || pstat.alloc_slow)) { + printf(" "); + print_plain_recycling_stats(&pstat); + printf("\n"); + } + } +} + +static void aggregate_device_stats(struct pp_stats_array *a, + struct netdev_page_pool_get_list *pools, + struct netdev_page_pool_stats_get_list *pp_stats) +{ + ynl_dump_foreach(pools, pp) { + struct pp_stat *s = find_ifc(a, pp->ifindex); + + count_pool(s, 1, pp); + if (pp->_present.detach_time) + count_pool(s, 0, pp); + } + + ynl_dump_foreach(pp_stats, pp) { + struct pp_stat *s = find_ifc(a, pp->info.ifindex); + + if (pp->_present.alloc_fast) + s->alloc_fast += pp->alloc_fast; + if (pp->_present.alloc_refill) + s->alloc_fast += pp->alloc_refill; + if (pp->_present.alloc_slow) + s->alloc_slow += pp->alloc_slow; + if (pp->_present.recycle_ring) + s->recycle_ring += pp->recycle_ring; + if (pp->_present.recycle_cached) + s->recycle_cache += pp->recycle_cached; + } +} + +static int do_stats(int argc, char **argv) +{ + struct netdev_page_pool_stats_get_list *pp_stats; + struct netdev_page_pool_get_list *pools; + enum { + GROUP_BY_DEVICE, + GROUP_BY_POOL, + } group_by = GROUP_BY_DEVICE; + bool zombies_only = false; + struct pp_stats_array a = {}; + struct ynl_error yerr; + struct ynl_sock *ys; + int ret = 0; + + /* Parse options */ + while (argc > 0) { + if (is_prefix(*argv, "group-by")) { + NEXT_ARG(); + + if (!REQ_ARGS(1)) + return -1; + + if (is_prefix(*argv, "device")) { + group_by = GROUP_BY_DEVICE; + } else if (is_prefix(*argv, "pp") || + is_prefix(*argv, "page-pool") || + is_prefix(*argv, "none")) { + group_by = GROUP_BY_POOL; + } else { + p_err("invalid group-by value '%s'", *argv); + return -1; + } + NEXT_ARG(); + } else if (is_prefix(*argv, "zombies")) { + zombies_only = true; + group_by = GROUP_BY_POOL; + NEXT_ARG(); + } else { + p_err("unknown option '%s'", *argv); + return -1; + } + } + + ys = ynl_sock_create(&ynl_netdev_family, &yerr); + if (!ys) { + p_err("YNL: %s", yerr.msg); + return -1; + } + + pools = netdev_page_pool_get_dump(ys); + if (!pools) { + p_err("failed to get page pools: %s", ys->err.msg); + ret = -1; + goto exit_close; + } + + pp_stats = netdev_page_pool_stats_get_dump(ys); + if (!pp_stats) { + p_err("failed to get page pool stats: %s", ys->err.msg); + ret = -1; + goto exit_free_pp_list; + } + + /* If grouping by pool, print individual pools */ + if (group_by == GROUP_BY_POOL) { + if (json_output) + print_json_pool_list(pools, pp_stats, zombies_only); + else + print_plain_pool_list(pools, pp_stats, zombies_only); + } else { + /* Aggregated stats mode (group-by device) */ + a.max = 64; + a.s = calloc(a.max, sizeof(*a.s)); + if (!a.s) { + p_err("failed to allocate stats array"); + ret = -1; + goto exit_free_stats_list; + } + + aggregate_device_stats(&a, pools, pp_stats); + + if (json_output) + print_json_stats(&a); + else + print_plain_stats(&a); + + free(a.s); + } + +exit_free_stats_list: + netdev_page_pool_stats_get_list_free(pp_stats); +exit_free_pp_list: + netdev_page_pool_get_list_free(pools); +exit_close: + ynl_sock_destroy(ys); + return ret; +} + +static int do_help(int argc __attribute__((unused)), + char **argv __attribute__((unused))) +{ + if (json_output) { + jsonw_null(json_wtr); + return 0; + } + + fprintf(stderr, + "Usage: %s page-pool { COMMAND | help }\n" + " %s page-pool stats [ OPTIONS ]\n" + "\n" + " OPTIONS := { group-by { device | page-pool | none } | zombies }\n" + "\n" + " stats - Display page pool statistics\n" + " stats group-by device - Group statistics by network device (default)\n" + " stats group-by page-pool | pp | none\n" + " - Show individual page pool details (no grouping)\n" + " stats zombies - Show only zombie page pools (detached but with\n" + " pages in flight). Implies group-by page-pool.\n" + "", + bin_name, bin_name); + + return 0; +} + +static const struct cmd page_pool_cmds[] = { + { "help", do_help }, + { "stats", do_stats }, + { 0 } +}; + +int do_page_pool(int argc, char **argv) +{ + return cmd_select(page_pool_cmds, argc, argv, do_help); +} diff --git a/tools/net/ynl/ynltool/qstats.c b/tools/net/ynl/ynltool/qstats.c new file mode 100644 index 000000000000..31fb45709ffa --- /dev/null +++ b/tools/net/ynl/ynltool/qstats.c @@ -0,0 +1,621 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <net/if.h> +#include <math.h> + +#include <ynl.h> +#include "netdev-user.h" + +#include "main.h" + +static enum netdev_qstats_scope scope; /* default - device */ + +struct queue_balance { + unsigned int ifindex; + enum netdev_queue_type type; + unsigned int queue_count; + __u64 *rx_packets; + __u64 *rx_bytes; + __u64 *tx_packets; + __u64 *tx_bytes; +}; + +static void print_json_qstats(struct netdev_qstats_get_list *qstats) +{ + jsonw_start_array(json_wtr); + + ynl_dump_foreach(qstats, qs) { + char ifname[IF_NAMESIZE]; + const char *name; + + jsonw_start_object(json_wtr); + + name = if_indextoname(qs->ifindex, ifname); + if (name) + jsonw_string_field(json_wtr, "ifname", name); + jsonw_uint_field(json_wtr, "ifindex", qs->ifindex); + + if (qs->_present.queue_type) + jsonw_string_field(json_wtr, "queue-type", + netdev_queue_type_str(qs->queue_type)); + if (qs->_present.queue_id) + jsonw_uint_field(json_wtr, "queue-id", qs->queue_id); + + if (qs->_present.rx_packets || qs->_present.rx_bytes || + qs->_present.rx_alloc_fail || qs->_present.rx_hw_drops || + qs->_present.rx_csum_complete || qs->_present.rx_hw_gro_packets) { + jsonw_name(json_wtr, "rx"); + jsonw_start_object(json_wtr); + if (qs->_present.rx_packets) + jsonw_uint_field(json_wtr, "packets", qs->rx_packets); + if (qs->_present.rx_bytes) + jsonw_uint_field(json_wtr, "bytes", qs->rx_bytes); + if (qs->_present.rx_alloc_fail) + jsonw_uint_field(json_wtr, "alloc-fail", qs->rx_alloc_fail); + if (qs->_present.rx_hw_drops) + jsonw_uint_field(json_wtr, "hw-drops", qs->rx_hw_drops); + if (qs->_present.rx_hw_drop_overruns) + jsonw_uint_field(json_wtr, "hw-drop-overruns", qs->rx_hw_drop_overruns); + if (qs->_present.rx_hw_drop_ratelimits) + jsonw_uint_field(json_wtr, "hw-drop-ratelimits", qs->rx_hw_drop_ratelimits); + if (qs->_present.rx_csum_complete) + jsonw_uint_field(json_wtr, "csum-complete", qs->rx_csum_complete); + if (qs->_present.rx_csum_unnecessary) + jsonw_uint_field(json_wtr, "csum-unnecessary", qs->rx_csum_unnecessary); + if (qs->_present.rx_csum_none) + jsonw_uint_field(json_wtr, "csum-none", qs->rx_csum_none); + if (qs->_present.rx_csum_bad) + jsonw_uint_field(json_wtr, "csum-bad", qs->rx_csum_bad); + if (qs->_present.rx_hw_gro_packets) + jsonw_uint_field(json_wtr, "hw-gro-packets", qs->rx_hw_gro_packets); + if (qs->_present.rx_hw_gro_bytes) + jsonw_uint_field(json_wtr, "hw-gro-bytes", qs->rx_hw_gro_bytes); + if (qs->_present.rx_hw_gro_wire_packets) + jsonw_uint_field(json_wtr, "hw-gro-wire-packets", qs->rx_hw_gro_wire_packets); + if (qs->_present.rx_hw_gro_wire_bytes) + jsonw_uint_field(json_wtr, "hw-gro-wire-bytes", qs->rx_hw_gro_wire_bytes); + jsonw_end_object(json_wtr); + } + + if (qs->_present.tx_packets || qs->_present.tx_bytes || + qs->_present.tx_hw_drops || qs->_present.tx_csum_none || + qs->_present.tx_hw_gso_packets) { + jsonw_name(json_wtr, "tx"); + jsonw_start_object(json_wtr); + if (qs->_present.tx_packets) + jsonw_uint_field(json_wtr, "packets", qs->tx_packets); + if (qs->_present.tx_bytes) + jsonw_uint_field(json_wtr, "bytes", qs->tx_bytes); + if (qs->_present.tx_hw_drops) + jsonw_uint_field(json_wtr, "hw-drops", qs->tx_hw_drops); + if (qs->_present.tx_hw_drop_errors) + jsonw_uint_field(json_wtr, "hw-drop-errors", qs->tx_hw_drop_errors); + if (qs->_present.tx_hw_drop_ratelimits) + jsonw_uint_field(json_wtr, "hw-drop-ratelimits", qs->tx_hw_drop_ratelimits); + if (qs->_present.tx_csum_none) + jsonw_uint_field(json_wtr, "csum-none", qs->tx_csum_none); + if (qs->_present.tx_needs_csum) + jsonw_uint_field(json_wtr, "needs-csum", qs->tx_needs_csum); + if (qs->_present.tx_hw_gso_packets) + jsonw_uint_field(json_wtr, "hw-gso-packets", qs->tx_hw_gso_packets); + if (qs->_present.tx_hw_gso_bytes) + jsonw_uint_field(json_wtr, "hw-gso-bytes", qs->tx_hw_gso_bytes); + if (qs->_present.tx_hw_gso_wire_packets) + jsonw_uint_field(json_wtr, "hw-gso-wire-packets", qs->tx_hw_gso_wire_packets); + if (qs->_present.tx_hw_gso_wire_bytes) + jsonw_uint_field(json_wtr, "hw-gso-wire-bytes", qs->tx_hw_gso_wire_bytes); + if (qs->_present.tx_stop) + jsonw_uint_field(json_wtr, "stop", qs->tx_stop); + if (qs->_present.tx_wake) + jsonw_uint_field(json_wtr, "wake", qs->tx_wake); + jsonw_end_object(json_wtr); + } + + jsonw_end_object(json_wtr); + } + + jsonw_end_array(json_wtr); +} + +static void print_one(bool present, const char *name, unsigned long long val, + int *line) +{ + if (!present) + return; + + if (!*line) { + printf(" "); + ++(*line); + } + + /* Don't waste space on tx- and rx- prefix, its implied by queue type */ + if (scope == NETDEV_QSTATS_SCOPE_QUEUE && + (name[0] == 'r' || name[0] == 't') && + name[1] == 'x' && name[2] == '-') + name += 3; + + printf(" %15s: %15llu", name, val); + + if (++(*line) == 3) { + printf("\n"); + *line = 0; + } +} + +static void print_plain_qstats(struct netdev_qstats_get_list *qstats) +{ + ynl_dump_foreach(qstats, qs) { + char ifname[IF_NAMESIZE]; + const char *name; + int n; + + name = if_indextoname(qs->ifindex, ifname); + if (name) + printf("%s", name); + else + printf("ifindex:%u", qs->ifindex); + + if (qs->_present.queue_type && qs->_present.queue_id) + printf("\t%s-%-3u", + netdev_queue_type_str(qs->queue_type), + qs->queue_id); + else + printf("\t "); + + n = 1; + + /* Basic counters */ + print_one(qs->_present.rx_packets, "rx-packets", qs->rx_packets, &n); + print_one(qs->_present.rx_bytes, "rx-bytes", qs->rx_bytes, &n); + print_one(qs->_present.tx_packets, "tx-packets", qs->tx_packets, &n); + print_one(qs->_present.tx_bytes, "tx-bytes", qs->tx_bytes, &n); + + /* RX error/drop counters */ + print_one(qs->_present.rx_alloc_fail, "rx-alloc-fail", + qs->rx_alloc_fail, &n); + print_one(qs->_present.rx_hw_drops, "rx-hw-drops", + qs->rx_hw_drops, &n); + print_one(qs->_present.rx_hw_drop_overruns, "rx-hw-drop-overruns", + qs->rx_hw_drop_overruns, &n); + print_one(qs->_present.rx_hw_drop_ratelimits, "rx-hw-drop-ratelimits", + qs->rx_hw_drop_ratelimits, &n); + + /* RX checksum counters */ + print_one(qs->_present.rx_csum_complete, "rx-csum-complete", + qs->rx_csum_complete, &n); + print_one(qs->_present.rx_csum_unnecessary, "rx-csum-unnecessary", + qs->rx_csum_unnecessary, &n); + print_one(qs->_present.rx_csum_none, "rx-csum-none", + qs->rx_csum_none, &n); + print_one(qs->_present.rx_csum_bad, "rx-csum-bad", + qs->rx_csum_bad, &n); + + /* RX GRO counters */ + print_one(qs->_present.rx_hw_gro_packets, "rx-hw-gro-packets", + qs->rx_hw_gro_packets, &n); + print_one(qs->_present.rx_hw_gro_bytes, "rx-hw-gro-bytes", + qs->rx_hw_gro_bytes, &n); + print_one(qs->_present.rx_hw_gro_wire_packets, "rx-hw-gro-wire-packets", + qs->rx_hw_gro_wire_packets, &n); + print_one(qs->_present.rx_hw_gro_wire_bytes, "rx-hw-gro-wire-bytes", + qs->rx_hw_gro_wire_bytes, &n); + + /* TX error/drop counters */ + print_one(qs->_present.tx_hw_drops, "tx-hw-drops", + qs->tx_hw_drops, &n); + print_one(qs->_present.tx_hw_drop_errors, "tx-hw-drop-errors", + qs->tx_hw_drop_errors, &n); + print_one(qs->_present.tx_hw_drop_ratelimits, "tx-hw-drop-ratelimits", + qs->tx_hw_drop_ratelimits, &n); + + /* TX checksum counters */ + print_one(qs->_present.tx_csum_none, "tx-csum-none", + qs->tx_csum_none, &n); + print_one(qs->_present.tx_needs_csum, "tx-needs-csum", + qs->tx_needs_csum, &n); + + /* TX GSO counters */ + print_one(qs->_present.tx_hw_gso_packets, "tx-hw-gso-packets", + qs->tx_hw_gso_packets, &n); + print_one(qs->_present.tx_hw_gso_bytes, "tx-hw-gso-bytes", + qs->tx_hw_gso_bytes, &n); + print_one(qs->_present.tx_hw_gso_wire_packets, "tx-hw-gso-wire-packets", + qs->tx_hw_gso_wire_packets, &n); + print_one(qs->_present.tx_hw_gso_wire_bytes, "tx-hw-gso-wire-bytes", + qs->tx_hw_gso_wire_bytes, &n); + + /* TX queue control */ + print_one(qs->_present.tx_stop, "tx-stop", qs->tx_stop, &n); + print_one(qs->_present.tx_wake, "tx-wake", qs->tx_wake, &n); + + if (n) + printf("\n"); + } +} + +static int do_show(int argc, char **argv) +{ + struct netdev_qstats_get_list *qstats; + struct netdev_qstats_get_req *req; + struct ynl_error yerr; + struct ynl_sock *ys; + int ret = 0; + + /* Parse options */ + while (argc > 0) { + if (is_prefix(*argv, "scope") || is_prefix(*argv, "group-by")) { + NEXT_ARG(); + + if (!REQ_ARGS(1)) + return -1; + + if (is_prefix(*argv, "queue")) { + scope = NETDEV_QSTATS_SCOPE_QUEUE; + } else if (is_prefix(*argv, "device")) { + scope = 0; + } else { + p_err("invalid scope value '%s'", *argv); + return -1; + } + NEXT_ARG(); + } else { + p_err("unknown option '%s'", *argv); + return -1; + } + } + + ys = ynl_sock_create(&ynl_netdev_family, &yerr); + if (!ys) { + p_err("YNL: %s", yerr.msg); + return -1; + } + + req = netdev_qstats_get_req_alloc(); + if (!req) { + p_err("failed to allocate qstats request"); + ret = -1; + goto exit_close; + } + + if (scope) + netdev_qstats_get_req_set_scope(req, scope); + + qstats = netdev_qstats_get_dump(ys, req); + netdev_qstats_get_req_free(req); + if (!qstats) { + p_err("failed to get queue stats: %s", ys->err.msg); + ret = -1; + goto exit_close; + } + + /* Print the stats as returned by the kernel */ + if (json_output) + print_json_qstats(qstats); + else + print_plain_qstats(qstats); + + netdev_qstats_get_list_free(qstats); +exit_close: + ynl_sock_destroy(ys); + return ret; +} + +static void compute_stats(__u64 *values, unsigned int count, + double *mean, double *stddev, __u64 *min, __u64 *max) +{ + double sum = 0.0, variance = 0.0; + unsigned int i; + + *min = ~0ULL; + *max = 0; + + if (count == 0) { + *mean = 0; + *stddev = 0; + *min = 0; + return; + } + + for (i = 0; i < count; i++) { + sum += values[i]; + if (values[i] < *min) + *min = values[i]; + if (values[i] > *max) + *max = values[i]; + } + + *mean = sum / count; + + if (count > 1) { + for (i = 0; i < count; i++) { + double diff = values[i] - *mean; + + variance += diff * diff; + } + *stddev = sqrt(variance / (count - 1)); + } else { + *stddev = 0; + } +} + +static void print_balance_stats(const char *name, enum netdev_queue_type type, + __u64 *values, unsigned int count) +{ + double mean, stddev, cv, ns; + __u64 min, max; + + if ((name[0] == 'r' && type != NETDEV_QUEUE_TYPE_RX) || + (name[0] == 't' && type != NETDEV_QUEUE_TYPE_TX)) + return; + + compute_stats(values, count, &mean, &stddev, &min, &max); + + cv = mean > 0 ? (stddev / mean) * 100.0 : 0.0; + ns = min + max > 0 ? (double)2 * (max - min) / (max + min) * 100 : 0.0; + + printf(" %-12s: cv=%.1f%% ns=%.1f%% stddev=%.0f\n", + name, cv, ns, stddev); + printf(" %-12s min=%llu max=%llu mean=%.0f\n", + "", min, max, mean); +} + +static void +print_balance_stats_json(const char *name, enum netdev_queue_type type, + __u64 *values, unsigned int count) +{ + double mean, stddev, cv, ns; + __u64 min, max; + + if ((name[0] == 'r' && type != NETDEV_QUEUE_TYPE_RX) || + (name[0] == 't' && type != NETDEV_QUEUE_TYPE_TX)) + return; + + compute_stats(values, count, &mean, &stddev, &min, &max); + + cv = mean > 0 ? (stddev / mean) * 100.0 : 0.0; + ns = min + max > 0 ? (double)2 * (max - min) / (max + min) * 100 : 0.0; + + jsonw_name(json_wtr, name); + jsonw_start_object(json_wtr); + jsonw_uint_field(json_wtr, "queue-count", count); + jsonw_uint_field(json_wtr, "min", min); + jsonw_uint_field(json_wtr, "max", max); + jsonw_float_field(json_wtr, "mean", mean); + jsonw_float_field(json_wtr, "stddev", stddev); + jsonw_float_field(json_wtr, "coefficient-of-variation", cv); + jsonw_float_field(json_wtr, "normalized-spread", ns); + jsonw_end_object(json_wtr); +} + +static int cmp_ifindex_type(const void *a, const void *b) +{ + const struct netdev_qstats_get_rsp *qa = a; + const struct netdev_qstats_get_rsp *qb = b; + + if (qa->ifindex != qb->ifindex) + return qa->ifindex - qb->ifindex; + if (qa->queue_type != qb->queue_type) + return qa->queue_type - qb->queue_type; + return qa->queue_id - qb->queue_id; +} + +static int do_balance(int argc, char **argv __attribute__((unused))) +{ + struct netdev_qstats_get_list *qstats; + struct netdev_qstats_get_req *req; + struct netdev_qstats_get_rsp **sorted; + struct ynl_error yerr; + struct ynl_sock *ys; + unsigned int count = 0; + unsigned int i, j; + int ret = 0; + + if (argc > 0) { + p_err("balance command takes no arguments"); + return -1; + } + + ys = ynl_sock_create(&ynl_netdev_family, &yerr); + if (!ys) { + p_err("YNL: %s", yerr.msg); + return -1; + } + + req = netdev_qstats_get_req_alloc(); + if (!req) { + p_err("failed to allocate qstats request"); + ret = -1; + goto exit_close; + } + + /* Always use queue scope for balance analysis */ + netdev_qstats_get_req_set_scope(req, NETDEV_QSTATS_SCOPE_QUEUE); + + qstats = netdev_qstats_get_dump(ys, req); + netdev_qstats_get_req_free(req); + if (!qstats) { + p_err("failed to get queue stats: %s", ys->err.msg); + ret = -1; + goto exit_close; + } + + /* Count and sort queues */ + ynl_dump_foreach(qstats, qs) + count++; + + if (count == 0) { + if (json_output) + jsonw_start_array(json_wtr); + else + printf("No queue statistics available\n"); + goto exit_free_qstats; + } + + sorted = calloc(count, sizeof(*sorted)); + if (!sorted) { + p_err("failed to allocate sorted array"); + ret = -1; + goto exit_free_qstats; + } + + i = 0; + ynl_dump_foreach(qstats, qs) + sorted[i++] = qs; + + qsort(sorted, count, sizeof(*sorted), cmp_ifindex_type); + + if (json_output) + jsonw_start_array(json_wtr); + + /* Process each device/queue-type combination */ + i = 0; + while (i < count) { + __u64 *rx_packets, *rx_bytes, *tx_packets, *tx_bytes; + enum netdev_queue_type type = sorted[i]->queue_type; + unsigned int ifindex = sorted[i]->ifindex; + unsigned int queue_count = 0; + char ifname[IF_NAMESIZE]; + const char *name; + + /* Count queues for this device/type */ + for (j = i; j < count && sorted[j]->ifindex == ifindex && + sorted[j]->queue_type == type; j++) + queue_count++; + + /* Skip if no packets/bytes (inactive queues) */ + if (!sorted[i]->_present.rx_packets && + !sorted[i]->_present.rx_bytes && + !sorted[i]->_present.tx_packets && + !sorted[i]->_present.tx_bytes) + goto next_ifc; + + /* Allocate arrays for statistics */ + rx_packets = calloc(queue_count, sizeof(*rx_packets)); + rx_bytes = calloc(queue_count, sizeof(*rx_bytes)); + tx_packets = calloc(queue_count, sizeof(*tx_packets)); + tx_bytes = calloc(queue_count, sizeof(*tx_bytes)); + + if (!rx_packets || !rx_bytes || !tx_packets || !tx_bytes) { + p_err("failed to allocate statistics arrays"); + free(rx_packets); + free(rx_bytes); + free(tx_packets); + free(tx_bytes); + ret = -1; + goto exit_free_sorted; + } + + /* Collect statistics */ + for (j = 0; j < queue_count; j++) { + rx_packets[j] = sorted[i + j]->_present.rx_packets ? + sorted[i + j]->rx_packets : 0; + rx_bytes[j] = sorted[i + j]->_present.rx_bytes ? + sorted[i + j]->rx_bytes : 0; + tx_packets[j] = sorted[i + j]->_present.tx_packets ? + sorted[i + j]->tx_packets : 0; + tx_bytes[j] = sorted[i + j]->_present.tx_bytes ? + sorted[i + j]->tx_bytes : 0; + } + + name = if_indextoname(ifindex, ifname); + + if (json_output) { + jsonw_start_object(json_wtr); + if (name) + jsonw_string_field(json_wtr, "ifname", name); + jsonw_uint_field(json_wtr, "ifindex", ifindex); + jsonw_string_field(json_wtr, "queue-type", + netdev_queue_type_str(type)); + + print_balance_stats_json("rx-packets", type, + rx_packets, queue_count); + print_balance_stats_json("rx-bytes", type, + rx_bytes, queue_count); + print_balance_stats_json("tx-packets", type, + tx_packets, queue_count); + print_balance_stats_json("tx-bytes", type, + tx_bytes, queue_count); + + jsonw_end_object(json_wtr); + } else { + if (name) + printf("%s", name); + else + printf("ifindex:%u", ifindex); + printf(" %s %d queues:\n", + netdev_queue_type_str(type), queue_count); + + print_balance_stats("rx-packets", type, + rx_packets, queue_count); + print_balance_stats("rx-bytes", type, + rx_bytes, queue_count); + print_balance_stats("tx-packets", type, + tx_packets, queue_count); + print_balance_stats("tx-bytes", type, + tx_bytes, queue_count); + printf("\n"); + } + + free(rx_packets); + free(rx_bytes); + free(tx_packets); + free(tx_bytes); + +next_ifc: + i += queue_count; + } + + if (json_output) + jsonw_end_array(json_wtr); + +exit_free_sorted: + free(sorted); +exit_free_qstats: + netdev_qstats_get_list_free(qstats); +exit_close: + ynl_sock_destroy(ys); + return ret; +} + +static int do_help(int argc __attribute__((unused)), + char **argv __attribute__((unused))) +{ + if (json_output) { + jsonw_null(json_wtr); + return 0; + } + + fprintf(stderr, + "Usage: %s qstats { COMMAND | help }\n" + " %s qstats [ show ] [ OPTIONS ]\n" + " %s qstats balance\n" + "\n" + " OPTIONS := { scope queue | group-by { device | queue } }\n" + "\n" + " show - Display queue statistics (default)\n" + " Statistics are aggregated for the entire device.\n" + " show scope queue - Display per-queue statistics\n" + " show group-by device - Display device-aggregated statistics (default)\n" + " show group-by queue - Display per-queue statistics\n" + " balance - Analyze traffic distribution balance.\n" + "", + bin_name, bin_name, bin_name); + + return 0; +} + +static const struct cmd qstats_cmds[] = { + { "show", do_show }, + { "balance", do_balance }, + { "help", do_help }, + { 0 } +}; + +int do_qstats(int argc, char **argv) +{ + return cmd_select(qstats_cmds, argc, argv, do_help); +} |
