aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/gpio/lsgpio.c2
-rw-r--r--tools/include/linux/coresight-pmu.h13
-rw-r--r--tools/include/uapi/asm-generic/socket.h3
-rw-r--r--tools/include/uapi/linux/bpf.h1
-rw-r--r--tools/include/uapi/linux/in.h1
-rw-r--r--tools/lib/bpf/libbpf.c3
-rw-r--r--tools/lib/bpf/libbpf_probes.c2
-rw-r--r--tools/net/ynl/Makefile19
-rw-r--r--tools/net/ynl/Makefile.deps20
-rw-r--r--tools/net/ynl/generated/Makefile50
-rw-r--r--tools/net/ynl/generated/devlink-user.c721
-rw-r--r--tools/net/ynl/generated/devlink-user.h210
-rw-r--r--tools/net/ynl/generated/ethtool-user.c6353
-rw-r--r--tools/net/ynl/generated/ethtool-user.h5531
-rw-r--r--tools/net/ynl/generated/fou-user.c328
-rw-r--r--tools/net/ynl/generated/fou-user.h337
-rw-r--r--tools/net/ynl/generated/handshake-user.c331
-rw-r--r--tools/net/ynl/generated/handshake-user.h145
-rw-r--r--tools/net/ynl/generated/netdev-user.c200
-rw-r--r--tools/net/ynl/generated/netdev-user.h85
-rw-r--r--tools/net/ynl/lib/Makefile28
-rw-r--r--tools/net/ynl/lib/nlspec.py30
-rw-r--r--tools/net/ynl/lib/ynl.c901
-rw-r--r--tools/net/ynl/lib/ynl.h237
-rw-r--r--tools/net/ynl/lib/ynl.py5
-rw-r--r--tools/net/ynl/samples/.gitignore3
-rw-r--r--tools/net/ynl/samples/Makefile30
-rw-r--r--tools/net/ynl/samples/devlink.c60
-rw-r--r--tools/net/ynl/samples/ethtool.c65
-rw-r--r--tools/net/ynl/samples/netdev.c108
-rwxr-xr-xtools/net/ynl/ynl-gen-c.py741
-rwxr-xr-xtools/net/ynl/ynl-regen.sh6
-rw-r--r--tools/perf/Makefile.config1
-rw-r--r--tools/perf/Makefile.perf3
-rw-r--r--tools/perf/arch/arm/util/pmu.c2
-rw-r--r--tools/perf/builtin-ftrace.c2
-rw-r--r--tools/perf/util/Build2
-rw-r--r--tools/perf/util/bpf_skel/sample_filter.bpf.c4
-rw-r--r--tools/perf/util/cs-etm.h13
-rw-r--r--tools/perf/util/evsel.c1
-rw-r--r--tools/perf/util/evsel.h6
-rw-r--r--tools/perf/util/symbol-elf.c27
-rw-r--r--tools/testing/cxl/Kbuild1
-rw-r--r--tools/testing/cxl/test/mem.c1
-rw-r--r--tools/testing/cxl/test/mock.c15
-rw-r--r--tools/testing/radix-tree/Makefile5
-rw-r--r--tools/testing/selftests/alsa/pcm-test.c10
-rw-r--r--tools/testing/selftests/bpf/prog_tests/inner_array_lookup.c31
-rw-r--r--tools/testing/selftests/bpf/prog_tests/sockopt_sk.c2
-rw-r--r--tools/testing/selftests/bpf/prog_tests/subprogs_extable.c29
-rw-r--r--tools/testing/selftests/bpf/progs/inner_array_lookup.c45
-rw-r--r--tools/testing/selftests/bpf/progs/test_subprogs_extable.c51
-rw-r--r--tools/testing/selftests/bpf/progs/verifier_spill_fill.c79
-rwxr-xr-xtools/testing/selftests/drivers/net/mlxsw/egress_vid_classification.sh5
-rwxr-xr-xtools/testing/selftests/drivers/net/mlxsw/extack.sh24
-rwxr-xr-xtools/testing/selftests/drivers/net/mlxsw/ingress_rif_conf_1d.sh5
-rw-r--r--tools/testing/selftests/drivers/net/mlxsw/mirror_gre_scale.sh1
-rwxr-xr-xtools/testing/selftests/drivers/net/mlxsw/one_armed_router.sh3
-rwxr-xr-xtools/testing/selftests/drivers/net/mlxsw/q_in_q_veto.sh8
-rwxr-xr-xtools/testing/selftests/drivers/net/mlxsw/qos_dscp_bridge.sh1
-rwxr-xr-xtools/testing/selftests/drivers/net/mlxsw/qos_ets_strict.sh8
-rwxr-xr-xtools/testing/selftests/drivers/net/mlxsw/qos_mc_aware.sh2
-rwxr-xr-xtools/testing/selftests/drivers/net/mlxsw/spectrum/q_in_vni_veto.sh1
-rwxr-xr-xtools/testing/selftests/drivers/net/mlxsw/vxlan.sh41
-rw-r--r--tools/testing/selftests/ftrace/test.d/filter/event-filter-function.tc45
-rw-r--r--tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-synthetic-event-stack-legacy.tc24
-rw-r--r--tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-synthetic-event-stack.tc5
-rwxr-xr-xtools/testing/selftests/gpio/gpio-sim.sh3
-rw-r--r--tools/testing/selftests/kselftest_harness.h6
-rw-r--r--tools/testing/selftests/kvm/Makefile1
-rw-r--r--tools/testing/selftests/kvm/x86_64/recalc_apic_map_test.c74
-rw-r--r--tools/testing/selftests/mm/Makefile13
-rw-r--r--tools/testing/selftests/net/.gitignore4
-rw-r--r--tools/testing/selftests/net/af_unix/Makefile3
-rw-r--r--tools/testing/selftests/net/af_unix/scm_pidfd.c430
-rwxr-xr-xtools/testing/selftests/net/fcnal-test.sh27
-rw-r--r--tools/testing/selftests/net/forwarding/Makefile2
-rwxr-xr-xtools/testing/selftests/net/forwarding/dual_vxlan_bridge.sh1
-rwxr-xr-xtools/testing/selftests/net/forwarding/hw_stats_l3.sh11
-rwxr-xr-xtools/testing/selftests/net/forwarding/mirror_gre_bound.sh1
-rwxr-xr-xtools/testing/selftests/net/forwarding/mirror_gre_bridge_1d.sh7
-rwxr-xr-xtools/testing/selftests/net/forwarding/mirror_gre_bridge_1d_vlan.sh3
-rwxr-xr-xtools/testing/selftests/net/forwarding/mirror_gre_bridge_1q.sh4
-rwxr-xr-xtools/testing/selftests/net/forwarding/mirror_gre_bridge_1q_lag.sh3
-rw-r--r--tools/testing/selftests/net/forwarding/mirror_topo_lib.sh1
-rwxr-xr-xtools/testing/selftests/net/forwarding/pedit_dsfield.sh4
-rwxr-xr-xtools/testing/selftests/net/forwarding/q_in_vni.sh1
-rwxr-xr-xtools/testing/selftests/net/forwarding/router_bridge.sh3
-rwxr-xr-xtools/testing/selftests/net/forwarding/router_bridge_vlan.sh24
-rwxr-xr-xtools/testing/selftests/net/forwarding/skbedit_priority.sh4
-rwxr-xr-xtools/testing/selftests/net/forwarding/tc_flower_cfm.sh206
-rwxr-xr-xtools/testing/selftests/net/forwarding/tc_flower_l2_miss.sh350
-rw-r--r--tools/testing/selftests/net/mptcp/Makefile2
-rw-r--r--tools/testing/selftests/net/mptcp/config1
-rwxr-xr-xtools/testing/selftests/net/mptcp/diag.sh46
-rwxr-xr-xtools/testing/selftests/net/mptcp/mptcp_connect.sh24
-rwxr-xr-xtools/testing/selftests/net/mptcp/mptcp_join.sh569
-rw-r--r--tools/testing/selftests/net/mptcp/mptcp_lib.sh104
-rw-r--r--tools/testing/selftests/net/mptcp/mptcp_sockopt.c138
-rwxr-xr-xtools/testing/selftests/net/mptcp/mptcp_sockopt.sh24
-rwxr-xr-xtools/testing/selftests/net/mptcp/pm_netlink.sh31
-rwxr-xr-xtools/testing/selftests/net/mptcp/simult_flows.sh4
-rwxr-xr-xtools/testing/selftests/net/mptcp/userspace_pm.sh17
-rwxr-xr-xtools/testing/selftests/net/test_vxlan_nolocalbypass.sh6
-rw-r--r--tools/testing/selftests/net/tls.c155
-rwxr-xr-xtools/testing/selftests/net/vrf-xfrm-tests.sh32
-rw-r--r--tools/testing/selftests/ptp/testptp.c35
-rw-r--r--tools/testing/selftests/tc-testing/config6
-rw-r--r--tools/testing/selftests/tc-testing/tc-tests/infra/filter.json25
-rw-r--r--tools/testing/selftests/tc-testing/tc-tests/qdiscs/mq.json25
-rw-r--r--tools/testing/selftests/tc-testing/tc-tests/qdiscs/sfb.json4
-rwxr-xr-xtools/testing/selftests/tc-testing/tdc.sh1
-rw-r--r--tools/testing/selftests/user_events/dyn_test.c177
-rw-r--r--tools/testing/selftests/user_events/ftrace_test.c88
-rw-r--r--tools/testing/selftests/user_events/perf_test.c82
-rw-r--r--tools/virtio/ringtest/.gitignore7
-rw-r--r--tools/virtio/ringtest/main.h11
-rw-r--r--tools/virtio/virtio-trace/README2
-rw-r--r--tools/virtio/virtio-trace/trace-agent.c12
119 files changed, 19184 insertions, 702 deletions
diff --git a/tools/gpio/lsgpio.c b/tools/gpio/lsgpio.c
index c61d061247e1..52a0be45410c 100644
--- a/tools/gpio/lsgpio.c
+++ b/tools/gpio/lsgpio.c
@@ -94,7 +94,7 @@ static void print_attributes(struct gpio_v2_line_info *info)
for (i = 0; i < info->num_attrs; i++) {
if (info->attrs[i].id == GPIO_V2_LINE_ATTR_ID_DEBOUNCE)
fprintf(stdout, ", debounce_period=%dusec",
- info->attrs[0].debounce_period_us);
+ info->attrs[i].debounce_period_us);
}
}
diff --git a/tools/include/linux/coresight-pmu.h b/tools/include/linux/coresight-pmu.h
index cef3b1c25335..51ac441a37c3 100644
--- a/tools/include/linux/coresight-pmu.h
+++ b/tools/include/linux/coresight-pmu.h
@@ -21,19 +21,6 @@
*/
#define CORESIGHT_LEGACY_CPU_TRACE_ID(cpu) (0x10 + (cpu * 2))
-/* CoreSight trace ID is currently the bottom 7 bits of the value */
-#define CORESIGHT_TRACE_ID_VAL_MASK GENMASK(6, 0)
-
-/*
- * perf record will set the legacy meta data values as unused initially.
- * This allows perf report to manage the decoders created when dynamic
- * allocation in operation.
- */
-#define CORESIGHT_TRACE_ID_UNUSED_FLAG BIT(31)
-
-/* Value to set for unused trace ID values */
-#define CORESIGHT_TRACE_ID_UNUSED_VAL 0x7F
-
/*
* Below are the definition of bit offsets for perf option, and works as
* arbitrary values for all ETM versions.
diff --git a/tools/include/uapi/asm-generic/socket.h b/tools/include/uapi/asm-generic/socket.h
index 8756df13be50..54d9c8bf7c55 100644
--- a/tools/include/uapi/asm-generic/socket.h
+++ b/tools/include/uapi/asm-generic/socket.h
@@ -121,6 +121,9 @@
#define SO_RCVMARK 75
+#define SO_PASSPIDFD 76
+#define SO_PEERPIDFD 77
+
#if !defined(__KERNEL__)
#if __BITS_PER_LONG == 64 || (defined(__x86_64__) && defined(__ILP32__))
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index a7b5e91dd768..60a9d59beeab 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -1035,6 +1035,7 @@ enum bpf_attach_type {
BPF_TRACE_KPROBE_MULTI,
BPF_LSM_CGROUP,
BPF_STRUCT_OPS,
+ BPF_NETFILTER,
__MAX_BPF_ATTACH_TYPE
};
diff --git a/tools/include/uapi/linux/in.h b/tools/include/uapi/linux/in.h
index 4b7f2df66b99..e682ab628dfa 100644
--- a/tools/include/uapi/linux/in.h
+++ b/tools/include/uapi/linux/in.h
@@ -163,6 +163,7 @@ struct in_addr {
#define IP_MULTICAST_ALL 49
#define IP_UNICAST_IF 50
#define IP_LOCAL_PORT_RANGE 51
+#define IP_PROTOCOL 52
#define MCAST_EXCLUDE 0
#define MCAST_INCLUDE 1
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 47632606b06d..214f828ece6b 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -117,6 +117,7 @@ static const char * const attach_type_name[] = {
[BPF_PERF_EVENT] = "perf_event",
[BPF_TRACE_KPROBE_MULTI] = "trace_kprobe_multi",
[BPF_STRUCT_OPS] = "struct_ops",
+ [BPF_NETFILTER] = "netfilter",
};
static const char * const link_type_name[] = {
@@ -8736,7 +8737,7 @@ static const struct bpf_sec_def section_defs[] = {
SEC_DEF("struct_ops+", STRUCT_OPS, 0, SEC_NONE),
SEC_DEF("struct_ops.s+", STRUCT_OPS, 0, SEC_SLEEPABLE),
SEC_DEF("sk_lookup", SK_LOOKUP, BPF_SK_LOOKUP, SEC_ATTACHABLE),
- SEC_DEF("netfilter", NETFILTER, 0, SEC_NONE),
+ SEC_DEF("netfilter", NETFILTER, BPF_NETFILTER, SEC_NONE),
};
static size_t custom_sec_def_cnt;
diff --git a/tools/lib/bpf/libbpf_probes.c b/tools/lib/bpf/libbpf_probes.c
index 5f78a023b474..9c4db90b92b6 100644
--- a/tools/lib/bpf/libbpf_probes.c
+++ b/tools/lib/bpf/libbpf_probes.c
@@ -180,7 +180,9 @@ static int probe_prog_load(enum bpf_prog_type prog_type,
case BPF_PROG_TYPE_SK_REUSEPORT:
case BPF_PROG_TYPE_FLOW_DISSECTOR:
case BPF_PROG_TYPE_CGROUP_SYSCTL:
+ break;
case BPF_PROG_TYPE_NETFILTER:
+ opts.expected_attach_type = BPF_NETFILTER;
break;
default:
return -EOPNOTSUPP;
diff --git a/tools/net/ynl/Makefile b/tools/net/ynl/Makefile
new file mode 100644
index 000000000000..d664b36deb5b
--- /dev/null
+++ b/tools/net/ynl/Makefile
@@ -0,0 +1,19 @@
+# SPDX-License-Identifier: GPL-2.0
+
+SUBDIRS = lib generated samples
+
+all: $(SUBDIRS)
+
+$(SUBDIRS):
+ @if [ -f "$@/Makefile" ] ; then \
+ $(MAKE) -C $@ ; \
+ fi
+
+clean hardclean:
+ @for dir in $(SUBDIRS) ; do \
+ if [ -f "$$dir/Makefile" ] ; then \
+ $(MAKE) -C $$dir $@; \
+ fi \
+ done
+
+.PHONY: clean all $(SUBDIRS)
diff --git a/tools/net/ynl/Makefile.deps b/tools/net/ynl/Makefile.deps
new file mode 100644
index 000000000000..f842bc66b967
--- /dev/null
+++ b/tools/net/ynl/Makefile.deps
@@ -0,0 +1,20 @@
+# SPDX-License-Identifier: GPL-2.0
+
+# Try to include uAPI headers from the kernel uapi/ path.
+# Most code under tools/ requires the respective kernel uAPI headers
+# to be copied to tools/include. The duplication is annoying.
+# All the family headers should be self-contained. We avoid the copying
+# by selectively including just the uAPI header of the family directly
+# from the kernel sources.
+
+UAPI_PATH:=../../../../include/uapi/
+
+# scripts/headers_install.sh strips "_UAPI" from header guards so we
+# need the explicit -D matching what's in /usr, to avoid multiple definitions.
+
+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_handshake:=$(call get_hdr_inc,_LINUX_HANDSHAKE_H,handshake.h)
+CFLAGS_netdev:=$(call get_hdr_inc,_LINUX_NETDEV_H,netdev.h)
diff --git a/tools/net/ynl/generated/Makefile b/tools/net/ynl/generated/Makefile
new file mode 100644
index 000000000000..f8817d2e56e4
--- /dev/null
+++ b/tools/net/ynl/generated/Makefile
@@ -0,0 +1,50 @@
+# SPDX-License-Identifier: GPL-2.0
+
+CC=gcc
+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
+
+include ../Makefile.deps
+
+YNL_GEN_ARG_ethtool:=--user-header linux/ethtool_netlink.h \
+ --exclude-op stats-get
+
+TOOL:=../ynl-gen-c.py
+
+GENS:=ethtool devlink handshake fou netdev
+SRCS=$(patsubst %,%-user.c,${GENS})
+HDRS=$(patsubst %,%-user.h,${GENS})
+OBJS=$(patsubst %,%-user.o,${GENS})
+
+all: protos.a $(HDRS) $(SRCS) $(KHDRS) $(KSRCS) $(UAPI) regen
+
+protos.a: $(OBJS)
+ @echo -e "\tAR $@"
+ @ar rcs $@ $(OBJS)
+
+%-user.h: ../../../../Documentation/netlink/specs/%.yaml $(TOOL)
+ @echo -e "\tGEN $@"
+ @$(TOOL) --mode user --header --spec $< $(YNL_GEN_ARG_$*) > $@
+
+%-user.c: ../../../../Documentation/netlink/specs/%.yaml $(TOOL)
+ @echo -e "\tGEN $@"
+ @$(TOOL) --mode user --source --spec $< $(YNL_GEN_ARG_$*) > $@
+
+%-user.o: %-user.c %-user.h
+ @echo -e "\tCC $@"
+ @$(COMPILE.c) $(CFLAGS_$*) -o $@ $<
+
+clean:
+ rm -f *.o
+
+hardclean: clean
+ rm -f *.c *.h *.a
+
+regen:
+ @../ynl-regen.sh
+
+.PHONY: all clean hardclean regen
+.DEFAULT_GOAL: all
diff --git a/tools/net/ynl/generated/devlink-user.c b/tools/net/ynl/generated/devlink-user.c
new file mode 100644
index 000000000000..939bd45feaca
--- /dev/null
+++ b/tools/net/ynl/generated/devlink-user.c
@@ -0,0 +1,721 @@
+// 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",
+ [DEVLINK_CMD_INFO_GET] = "info-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];
+}
+
+/* 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_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_RELOAD_FAILED] = { .name = "reload-failed", .type = YNL_PT_U8, },
+ [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, },
+};
+
+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_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;
+}
+
+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
new file mode 100644
index 000000000000..a008b99b6e24
--- /dev/null
+++ b/tools/net/ynl/generated/devlink-user.h
@@ -0,0 +1,210 @@
+/* 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);
+
+/* 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_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);
+
+#endif /* _LINUX_DEVLINK_GEN_H */
diff --git a/tools/net/ynl/generated/ethtool-user.c b/tools/net/ynl/generated/ethtool-user.c
new file mode 100644
index 000000000000..74b883a14958
--- /dev/null
+++ b/tools/net/ynl/generated/ethtool-user.c
@@ -0,0 +1,6353 @@
+// 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 = &ethtool_cable_result_nest, },
+ [ETHTOOL_A_CABLE_NEST_FAULT_LENGTH] = { .name = "fault-length", .type = YNL_PT_NEST, .nest = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_bitset_nest, },
+ [ETHTOOL_A_TUNNEL_UDP_TABLE_ENTRY] = { .name = "entry", .type = YNL_PT_NEST, .nest = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_header_nest, },
+ [ETHTOOL_A_STRSET_STRINGSETS] = { .name = "stringsets", .type = YNL_PT_NEST, .nest = &ethtool_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 = &ethtool_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 = &ethtool_header_nest, },
+ [ETHTOOL_A_LINKMODES_AUTONEG] = { .name = "autoneg", .type = YNL_PT_U8, },
+ [ETHTOOL_A_LINKMODES_OURS] = { .name = "ours", .type = YNL_PT_NEST, .nest = &ethtool_bitset_nest, },
+ [ETHTOOL_A_LINKMODES_PEER] = { .name = "peer", .type = YNL_PT_NEST, .nest = &ethtool_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 = &ethtool_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 = &ethtool_header_nest, },
+ [ETHTOOL_A_DEBUG_MSGMASK] = { .name = "msgmask", .type = YNL_PT_NEST, .nest = &ethtool_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 = &ethtool_header_nest, },
+ [ETHTOOL_A_WOL_MODES] = { .name = "modes", .type = YNL_PT_NEST, .nest = &ethtool_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 = &ethtool_header_nest, },
+ [ETHTOOL_A_FEATURES_HW] = { .name = "hw", .type = YNL_PT_NEST, .nest = &ethtool_bitset_nest, },
+ [ETHTOOL_A_FEATURES_WANTED] = { .name = "wanted", .type = YNL_PT_NEST, .nest = &ethtool_bitset_nest, },
+ [ETHTOOL_A_FEATURES_ACTIVE] = { .name = "active", .type = YNL_PT_NEST, .nest = &ethtool_bitset_nest, },
+ [ETHTOOL_A_FEATURES_NOCHANGE] = { .name = "nochange", .type = YNL_PT_NEST, .nest = &ethtool_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 = &ethtool_header_nest, },
+ [ETHTOOL_A_PRIVFLAGS_FLAGS] = { .name = "flags", .type = YNL_PT_NEST, .nest = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_header_nest, },
+ [ETHTOOL_A_EEE_MODES_OURS] = { .name = "modes-ours", .type = YNL_PT_NEST, .nest = &ethtool_bitset_nest, },
+ [ETHTOOL_A_EEE_MODES_PEER] = { .name = "modes-peer", .type = YNL_PT_NEST, .nest = &ethtool_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 = &ethtool_header_nest, },
+ [ETHTOOL_A_TSINFO_TIMESTAMPING] = { .name = "timestamping", .type = YNL_PT_NEST, .nest = &ethtool_bitset_nest, },
+ [ETHTOOL_A_TSINFO_TX_TYPES] = { .name = "tx-types", .type = YNL_PT_NEST, .nest = &ethtool_bitset_nest, },
+ [ETHTOOL_A_TSINFO_RX_FILTERS] = { .name = "rx-filters", .type = YNL_PT_NEST, .nest = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_header_nest, },
+ [ETHTOOL_A_CABLE_TEST_TDR_CFG] = { .name = "cfg", .type = YNL_PT_NEST, .nest = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_header_nest, },
+ [ETHTOOL_A_TUNNEL_INFO_UDP_PORTS] = { .name = "udp-ports", .type = YNL_PT_NEST, .nest = &ethtool_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 = &ethtool_header_nest, },
+ [ETHTOOL_A_FEC_MODES] = { .name = "modes", .type = YNL_PT_NEST, .nest = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_strset_nest;
+ yrs.yarg.rsp_policy = &ethtool_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 = &ethtool_strset_nest;
+
+ nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_STRSET_GET, 1);
+ ys->req_policy = &ethtool_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 = &ethtool_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 = &ethtool_linkinfo_nest;
+ yrs.yarg.rsp_policy = &ethtool_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 = &ethtool_linkinfo_nest;
+
+ nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_LINKINFO_GET, 1);
+ ys->req_policy = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_linkmodes_nest;
+ yrs.yarg.rsp_policy = &ethtool_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 = &ethtool_linkmodes_nest;
+
+ nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_LINKMODES_GET, 1);
+ ys->req_policy = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_linkstate_nest;
+ yrs.yarg.rsp_policy = &ethtool_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 = &ethtool_linkstate_nest;
+
+ nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_LINKSTATE_GET, 1);
+ ys->req_policy = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_debug_nest;
+ yrs.yarg.rsp_policy = &ethtool_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 = &ethtool_debug_nest;
+
+ nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_DEBUG_GET, 1);
+ ys->req_policy = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_wol_nest;
+ yrs.yarg.rsp_policy = &ethtool_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 = &ethtool_wol_nest;
+
+ nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_WOL_GET, 1);
+ ys->req_policy = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_features_nest;
+ yrs.yarg.rsp_policy = &ethtool_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 = &ethtool_features_nest;
+
+ nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_FEATURES_GET, 1);
+ ys->req_policy = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_features_nest;
+ yrs.yarg.rsp_policy = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_privflags_nest;
+ yrs.yarg.rsp_policy = &ethtool_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 = &ethtool_privflags_nest;
+
+ nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_PRIVFLAGS_GET, 1);
+ ys->req_policy = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_rings_nest;
+ yrs.yarg.rsp_policy = &ethtool_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 = &ethtool_rings_nest;
+
+ nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_RINGS_GET, 1);
+ ys->req_policy = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_channels_nest;
+ yrs.yarg.rsp_policy = &ethtool_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 = &ethtool_channels_nest;
+
+ nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_CHANNELS_GET, 1);
+ ys->req_policy = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_coalesce_nest;
+ yrs.yarg.rsp_policy = &ethtool_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 = &ethtool_coalesce_nest;
+
+ nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_COALESCE_GET, 1);
+ ys->req_policy = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_pause_nest;
+ yrs.yarg.rsp_policy = &ethtool_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 = &ethtool_pause_nest;
+
+ nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_PAUSE_GET, 1);
+ ys->req_policy = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_eee_nest;
+ yrs.yarg.rsp_policy = &ethtool_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 = &ethtool_eee_nest;
+
+ nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_EEE_GET, 1);
+ ys->req_policy = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_tsinfo_nest;
+ yrs.yarg.rsp_policy = &ethtool_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 = &ethtool_tsinfo_nest;
+
+ nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_TSINFO_GET, 1);
+ ys->req_policy = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_tunnel_info_nest;
+ yrs.yarg.rsp_policy = &ethtool_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 = &ethtool_tunnel_info_nest;
+
+ nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_TUNNEL_INFO_GET, 1);
+ ys->req_policy = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_fec_nest;
+ yrs.yarg.rsp_policy = &ethtool_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 = &ethtool_fec_nest;
+
+ nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_FEC_GET, 1);
+ ys->req_policy = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_module_eeprom_nest;
+ yrs.yarg.rsp_policy = &ethtool_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 = &ethtool_module_eeprom_nest;
+
+ nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_MODULE_EEPROM_GET, 1);
+ ys->req_policy = &ethtool_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 = &ethtool_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 = &ethtool_phc_vclocks_nest;
+ yrs.yarg.rsp_policy = &ethtool_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 = &ethtool_phc_vclocks_nest;
+
+ nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_PHC_VCLOCKS_GET, 1);
+ ys->req_policy = &ethtool_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 = &ethtool_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 = &ethtool_module_nest;
+ yrs.yarg.rsp_policy = &ethtool_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 = &ethtool_module_nest;
+
+ nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_MODULE_GET, 1);
+ ys->req_policy = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_pse_nest;
+ yrs.yarg.rsp_policy = &ethtool_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 = &ethtool_pse_nest;
+
+ nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_PSE_GET, 1);
+ ys->req_policy = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_rss_nest;
+ yrs.yarg.rsp_policy = &ethtool_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 = &ethtool_rss_nest;
+
+ nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_RSS_GET, 1);
+ ys->req_policy = &ethtool_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 = &ethtool_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 = &ethtool_plca_nest;
+ yrs.yarg.rsp_policy = &ethtool_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 = &ethtool_plca_nest;
+
+ nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_PLCA_GET_CFG, 1);
+ ys->req_policy = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_plca_nest;
+ yrs.yarg.rsp_policy = &ethtool_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 = &ethtool_plca_nest;
+
+ nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_PLCA_GET_STATUS, 1);
+ ys->req_policy = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_mm_nest;
+ yrs.yarg.rsp_policy = &ethtool_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 = &ethtool_mm_nest;
+
+ nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_MM_GET, 1);
+ ys->req_policy = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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 = &ethtool_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
new file mode 100644
index 000000000000..d7d4ba855f43
--- /dev/null
+++ b/tools/net/ynl/generated/ethtool-user.h
@@ -0,0 +1,5531 @@
+/* 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->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.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.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.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
new file mode 100644
index 000000000000..4271b5d43c58
--- /dev/null
+++ b/tools/net/ynl/generated/fou-user.c
@@ -0,0 +1,328 @@
+// 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
new file mode 100644
index 000000000000..d8ab50579cd1
--- /dev/null
+++ b/tools/net/ynl/generated/fou-user.h
@@ -0,0 +1,337 @@
+/* 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->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->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->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->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->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->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
new file mode 100644
index 000000000000..7c67765daf90
--- /dev/null
+++ b/tools/net/ynl/generated/handshake-user.c
@@ -0,0 +1,331 @@
+// 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
new file mode 100644
index 000000000000..47646bb91cea
--- /dev/null
+++ b/tools/net/ynl/generated/handshake-user.h
@@ -0,0 +1,145 @@
+/* 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
new file mode 100644
index 000000000000..4eb8aefef0cd
--- /dev/null
+++ b/tools/net/ynl/generated/netdev-user.c
@@ -0,0 +1,200 @@
+// 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, },
+};
+
+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);
+ }
+ }
+
+ 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
new file mode 100644
index 000000000000..5554dc69bb9c
--- /dev/null
+++ b/tools/net/ynl/generated/netdev-user.h
@@ -0,0 +1,85 @@
+/* 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;
+ } _present;
+
+ __u32 ifindex;
+ __u64 xdp_features;
+};
+
+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/Makefile b/tools/net/ynl/lib/Makefile
new file mode 100644
index 000000000000..d2e50fd0a52d
--- /dev/null
+++ b/tools/net/ynl/lib/Makefile
@@ -0,0 +1,28 @@
+# SPDX-License-Identifier: GPL-2.0
+
+CC=gcc
+CFLAGS=-std=gnu11 -O2 -W -Wall -Wextra -Wno-unused-parameter -Wshadow
+ifeq ("$(DEBUG)","1")
+ CFLAGS += -g -fsanitize=address -fsanitize=leak -static-libasan
+endif
+
+SRCS=$(wildcard *.c)
+OBJS=$(patsubst %.c,%.o,${SRCS})
+
+include $(wildcard *.d)
+
+all: ynl.a
+
+ynl.a: $(OBJS)
+ ar rcs $@ $(OBJS)
+clean:
+ rm -f *.o *.d *~
+
+hardclean: clean
+ rm -f *.a
+
+%.o: %.c
+ $(COMPILE.c) -MMD -c -o $@ $<
+
+.PHONY: all clean
+.DEFAULT_GOAL=all
diff --git a/tools/net/ynl/lib/nlspec.py b/tools/net/ynl/lib/nlspec.py
index ada22b073aa2..1ba572cae27b 100644
--- a/tools/net/ynl/lib/nlspec.py
+++ b/tools/net/ynl/lib/nlspec.py
@@ -324,16 +324,17 @@ class SpecFamily(SpecElement):
Attributes:
proto protocol type (e.g. genetlink)
+ msg_id_model enum-model for operations (unified, directional etc.)
license spec license (loaded from an SPDX tag on the spec)
attr_sets dict of attribute sets
msgs dict of all messages (index by name)
- msgs_by_value dict of all messages (indexed 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
"""
- def __init__(self, spec_path, schema_path=None):
+ def __init__(self, spec_path, schema_path=None, exclude_ops=None):
with open(spec_path, "r") as stream:
prefix = '# SPDX-License-Identifier: '
first = stream.readline().strip()
@@ -348,7 +349,10 @@ class SpecFamily(SpecElement):
super().__init__(self, spec)
+ self._exclude_ops = exclude_ops if exclude_ops else []
+
self.proto = self.yaml.get('protocol', 'genetlink')
+ self.msg_id_model = self.yaml['operations'].get('enum-model', 'unified')
if schema_path is None:
schema_path = os.path.dirname(os.path.dirname(spec_path)) + f'/{self.proto}.yaml'
@@ -368,6 +372,7 @@ class SpecFamily(SpecElement):
self.req_by_value = collections.OrderedDict()
self.rsp_by_value = collections.OrderedDict()
self.ops = collections.OrderedDict()
+ self.ntfs = collections.OrderedDict()
self.consts = collections.OrderedDict()
last_exception = None
@@ -420,7 +425,7 @@ class SpecFamily(SpecElement):
self.fixed_header = self.yaml['operations'].get('fixed-header')
req_val = rsp_val = 1
for elem in self.yaml['operations']['list']:
- if 'notify' in elem:
+ if 'notify' in elem or 'event' in elem:
if 'value' in elem:
rsp_val = elem['value']
req_val_next = req_val
@@ -442,7 +447,17 @@ class SpecFamily(SpecElement):
else:
raise Exception("Can't parse directional ops")
- op = self.new_operation(elem, req_val, rsp_val)
+ if req_val == req_val_next:
+ req_val = None
+ if rsp_val == rsp_val_next:
+ rsp_val = None
+
+ skip = False
+ for exclude in self._exclude_ops:
+ skip |= bool(exclude.match(elem['name']))
+ if not skip:
+ op = self.new_operation(elem, req_val, rsp_val)
+
req_val = req_val_next
rsp_val = rsp_val_next
@@ -473,10 +488,9 @@ class SpecFamily(SpecElement):
attr_set = self.new_attr_set(elem)
self.attr_sets[elem['name']] = attr_set
- msg_id_model = self.yaml['operations'].get('enum-model', 'unified')
- if msg_id_model == 'unified':
+ if self.msg_id_model == 'unified':
self._dictify_ops_unified()
- elif msg_id_model == 'directional':
+ elif self.msg_id_model == 'directional':
self._dictify_ops_directional()
for op in self.msgs.values():
@@ -486,3 +500,5 @@ class SpecFamily(SpecElement):
self.rsp_by_value[op.rsp_value] = op
if not op.is_async and 'attribute-set' in op:
self.ops[op.name] = op
+ elif op.is_async:
+ self.ntfs[op.name] = op
diff --git a/tools/net/ynl/lib/ynl.c b/tools/net/ynl/lib/ynl.c
new file mode 100644
index 000000000000..514e0d69e731
--- /dev/null
+++ b/tools/net/ynl/lib/ynl.c
@@ -0,0 +1,901 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+#include <errno.h>
+#include <poll.h>
+#include <string.h>
+#include <stdlib.h>
+#include <linux/types.h>
+
+#include <libmnl/libmnl.h>
+#include <linux/genetlink.h>
+
+#include "ynl.h"
+
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(*arr))
+
+#define __yerr_msg(yse, _msg...) \
+ ({ \
+ struct ynl_error *_yse = (yse); \
+ \
+ if (_yse) { \
+ snprintf(_yse->msg, sizeof(_yse->msg) - 1, _msg); \
+ _yse->msg[sizeof(_yse->msg) - 1] = 0; \
+ } \
+ })
+
+#define __yerr_code(yse, _code...) \
+ ({ \
+ struct ynl_error *_yse = (yse); \
+ \
+ if (_yse) { \
+ _yse->code = _code; \
+ } \
+ })
+
+#define __yerr(yse, _code, _msg...) \
+ ({ \
+ __yerr_msg(yse, _msg); \
+ __yerr_code(yse, _code); \
+ })
+
+#define __perr(yse, _msg) __yerr(yse, errno, _msg)
+
+#define yerr_msg(_ys, _msg...) __yerr_msg(&(_ys)->err, _msg)
+#define yerr(_ys, _code, _msg...) __yerr(&(_ys)->err, _code, _msg)
+#define perr(_ys, _msg) __yerr(&(_ys)->err, errno, _msg)
+
+/* -- Netlink boiler plate */
+static int
+ynl_err_walk_report_one(struct ynl_policy_nest *policy, unsigned int type,
+ char *str, int str_sz, int *n)
+{
+ if (!policy) {
+ if (*n < str_sz)
+ *n += snprintf(str, str_sz, "!policy");
+ return 1;
+ }
+
+ if (type > policy->max_attr) {
+ if (*n < str_sz)
+ *n += snprintf(str, str_sz, "!oob");
+ return 1;
+ }
+
+ if (!policy->table[type].name) {
+ if (*n < str_sz)
+ *n += snprintf(str, str_sz, "!name");
+ return 1;
+ }
+
+ if (*n < str_sz)
+ *n += snprintf(str, str_sz - *n,
+ ".%s", policy->table[type].name);
+ 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)
+{
+ unsigned int astart_off, aend_off;
+ const struct nlattr *attr;
+ unsigned int data_len;
+ unsigned int type;
+ bool found = false;
+ int n = 0;
+
+ if (!policy) {
+ if (n < str_sz)
+ n += snprintf(str, str_sz, "!policy");
+ return n;
+ }
+
+ data_len = end - start;
+
+ mnl_attr_for_each_payload(start, data_len) {
+ astart_off = (char *)attr - (char *)start;
+ aend_off = astart_off + mnl_attr_get_payload_len(attr);
+ if (aend_off <= off)
+ continue;
+
+ found = true;
+ break;
+ }
+ if (!found)
+ return 0;
+
+ off -= astart_off;
+
+ type = mnl_attr_get_type(attr);
+
+ if (ynl_err_walk_report_one(policy, type, str, str_sz, &n))
+ return n;
+
+ if (!off) {
+ if (nest_pol)
+ *nest_pol = policy->table[type].nest;
+ return n;
+ }
+
+ if (!policy->table[type].nest) {
+ 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);
+
+ return n + ynl_err_walk(ys, start, end, off, policy->table[type].nest,
+ &str[n], str_sz - n, nest_pol);
+}
+
+#define NLMSGERR_ATTR_MISS_TYPE (NLMSGERR_ATTR_POLICY + 1)
+#define NLMSGERR_ATTR_MISS_NEST (NLMSGERR_ATTR_POLICY + 2)
+#define NLMSGERR_ATTR_MAX (NLMSGERR_ATTR_MAX + 2)
+
+static int
+ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh,
+ unsigned int hlen)
+{
+ const struct nlattr *tb[NLMSGERR_ATTR_MAX + 1] = {};
+ char miss_attr[sizeof(ys->err.msg)];
+ char bad_attr[sizeof(ys->err.msg)];
+ const struct nlattr *attr;
+ const char *str = NULL;
+
+ if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS))
+ return MNL_CB_OK;
+
+ mnl_attr_for_each(attr, nlh, hlen) {
+ unsigned int len, type;
+
+ len = mnl_attr_get_payload_len(attr);
+ type = mnl_attr_get_type(attr);
+
+ if (type > NLMSGERR_ATTR_MAX)
+ continue;
+
+ tb[type] = attr;
+
+ switch (type) {
+ case NLMSGERR_ATTR_OFFS:
+ case NLMSGERR_ATTR_MISS_TYPE:
+ case NLMSGERR_ATTR_MISS_NEST:
+ if (len != sizeof(__u32))
+ return MNL_CB_ERROR;
+ break;
+ case NLMSGERR_ATTR_MSG:
+ str = mnl_attr_get_payload(attr);
+ if (str[len - 1])
+ return MNL_CB_ERROR;
+ break;
+ default:
+ break;
+ }
+ }
+
+ bad_attr[0] = '\0';
+ miss_attr[0] = '\0';
+
+ if (tb[NLMSGERR_ATTR_OFFS]) {
+ unsigned int n, off;
+ void *start, *end;
+
+ ys->err.attr_offs = mnl_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);
+
+ off = ys->err.attr_offs;
+ off -= sizeof(struct nlmsghdr);
+ off -= sizeof(struct genlmsghdr);
+
+ n += ynl_err_walk(ys, start, end, off, ys->req_policy,
+ &bad_attr[n], sizeof(bad_attr) - n, NULL);
+
+ if (n >= sizeof(bad_attr))
+ n = sizeof(bad_attr) - 1;
+ bad_attr[n] = '\0';
+ }
+ if (tb[NLMSGERR_ATTR_MISS_TYPE]) {
+ 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]);
+
+ 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);
+
+ nest_pol = ys->req_policy;
+ if (tb[NLMSGERR_ATTR_MISS_NEST]) {
+ off = mnl_attr_get_u32(tb[NLMSGERR_ATTR_MISS_NEST]);
+ off -= sizeof(struct nlmsghdr);
+ off -= sizeof(struct genlmsghdr);
+
+ n += ynl_err_walk(ys, start, end, off, ys->req_policy,
+ &miss_attr[n], sizeof(miss_attr) - n,
+ &nest_pol);
+ }
+
+ n2 = 0;
+ ynl_err_walk_report_one(nest_pol, type, &miss_attr[n],
+ sizeof(miss_attr) - n, &n2);
+ n += n2;
+
+ if (n >= sizeof(miss_attr))
+ n = sizeof(miss_attr) - 1;
+ miss_attr[n] = '\0';
+ }
+
+ /* Implicitly depend on ys->err.code already set */
+ if (str)
+ yerr_msg(ys, "Kernel %s: '%s'%s%s%s",
+ ys->err.code ? "error" : "warning",
+ str, bad_attr, miss_attr,
+ bad_attr[0] || miss_attr[0] ? ")" : "");
+ else if (bad_attr[0] || miss_attr[0])
+ yerr_msg(ys, "Kernel %s: %s%s",
+ ys->err.code ? "error" : "warning",
+ bad_attr, miss_attr);
+
+ return MNL_CB_OK;
+}
+
+static int ynl_cb_error(const struct nlmsghdr *nlh, void *data)
+{
+ const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh);
+ struct ynl_parse_arg *yarg = data;
+ unsigned int hlen;
+ int code;
+
+ code = err->error >= 0 ? err->error : -err->error;
+ yarg->ys->err.code = code;
+ errno = code;
+
+ hlen = sizeof(*err);
+ if (!(nlh->nlmsg_flags & NLM_F_CAPPED))
+ hlen += mnl_nlmsg_get_payload_len(&err->msg);
+
+ ynl_ext_ack_check(yarg->ys, nlh, hlen);
+
+ return code ? MNL_CB_ERROR : MNL_CB_STOP;
+}
+
+static int ynl_cb_done(const struct nlmsghdr *nlh, void *data)
+{
+ struct ynl_parse_arg *yarg = data;
+ int err;
+
+ err = *(int *)NLMSG_DATA(nlh);
+ if (err < 0) {
+ yarg->ys->err.code = -err;
+ errno = -err;
+
+ ynl_ext_ack_check(yarg->ys, nlh, sizeof(int));
+
+ return MNL_CB_ERROR;
+ }
+ return MNL_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)
+{
+ struct ynl_policy_attr *policy;
+ unsigned int type, len;
+ unsigned char *data;
+
+ data = mnl_attr_get_payload(attr);
+ len = mnl_attr_get_payload_len(attr);
+ type = mnl_attr_get_type(attr);
+ if (type > yarg->rsp_policy->max_attr) {
+ yerr(yarg->ys, YNL_ERROR_INTERNAL,
+ "Internal error, validating unknown attribute");
+ return -1;
+ }
+
+ policy = &yarg->rsp_policy->table[type];
+
+ switch (policy->type) {
+ case YNL_PT_REJECT:
+ yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
+ "Rejected attribute (%s)", policy->name);
+ return -1;
+ case YNL_PT_IGNORE:
+ break;
+ case YNL_PT_U8:
+ if (len == sizeof(__u8))
+ break;
+ yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
+ "Invalid attribute (u8 %s)", policy->name);
+ return -1;
+ case YNL_PT_U16:
+ if (len == sizeof(__u16))
+ break;
+ yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
+ "Invalid attribute (u16 %s)", policy->name);
+ return -1;
+ case YNL_PT_U32:
+ if (len == sizeof(__u32))
+ break;
+ yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
+ "Invalid attribute (u32 %s)", policy->name);
+ return -1;
+ case YNL_PT_U64:
+ if (len == sizeof(__u64))
+ break;
+ yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
+ "Invalid attribute (u64 %s)", policy->name);
+ return -1;
+ case YNL_PT_FLAG:
+ /* Let flags grow into real attrs, why not.. */
+ break;
+ case YNL_PT_NEST:
+ if (!len || len >= sizeof(*attr))
+ break;
+ yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
+ "Invalid attribute (nest %s)", policy->name);
+ return -1;
+ case YNL_PT_BINARY:
+ if (!policy->len || len == policy->len)
+ break;
+ yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
+ "Invalid attribute (binary %s)", policy->name);
+ return -1;
+ case YNL_PT_NUL_STR:
+ if ((!policy->len || len <= policy->len) && !data[len - 1])
+ break;
+ yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
+ "Invalid attribute (string %s)", policy->name);
+ return -1;
+ default:
+ yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
+ "Invalid attribute (unknown %s)", policy->name);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Generic code */
+
+static void ynl_err_reset(struct ynl_sock *ys)
+{
+ ys->err.code = 0;
+ ys->err.attr_offs = 0;
+ ys->err.msg[0] = 0;
+}
+
+struct nlmsghdr *ynl_msg_start(struct ynl_sock *ys, __u32 id, __u16 flags)
+{
+ struct nlmsghdr *nlh;
+
+ ynl_err_reset(ys);
+
+ nlh = ys->nlh = mnl_nlmsg_put_header(ys->tx_buf);
+ nlh->nlmsg_type = id;
+ nlh->nlmsg_flags = flags;
+ nlh->nlmsg_seq = ++ys->seq;
+
+ return nlh;
+}
+
+struct nlmsghdr *
+ynl_gemsg_start(struct ynl_sock *ys, __u32 id, __u16 flags,
+ __u8 cmd, __u8 version)
+{
+ struct genlmsghdr gehdr;
+ struct nlmsghdr *nlh;
+ void *data;
+
+ nlh = ynl_msg_start(ys, id, flags);
+
+ memset(&gehdr, 0, sizeof(gehdr));
+ gehdr.cmd = cmd;
+ gehdr.version = version;
+
+ data = mnl_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)
+{
+ ynl_msg_start(ys, id, NLM_F_REQUEST | NLM_F_ACK);
+}
+
+void ynl_msg_start_dump(struct ynl_sock *ys, __u32 id)
+{
+ ynl_msg_start(ys, id, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP);
+}
+
+struct nlmsghdr *
+ynl_gemsg_start_req(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version)
+{
+ return ynl_gemsg_start(ys, id, NLM_F_REQUEST | NLM_F_ACK, cmd, version);
+}
+
+struct nlmsghdr *
+ynl_gemsg_start_dump(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version)
+{
+ return ynl_gemsg_start(ys, id, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP,
+ cmd, version);
+}
+
+int ynl_recv_ack(struct ynl_sock *ys, int ret)
+{
+ if (!ret) {
+ yerr(ys, YNL_ERROR_EXPECT_ACK,
+ "Expecting an ACK but nothing received");
+ return -1;
+ }
+
+ ret = mnl_socket_recvfrom(ys->sock, ys->rx_buf, MNL_SOCKET_BUFFER_SIZE);
+ if (ret < 0) {
+ perr(ys, "Socket receive failed");
+ return ret;
+ }
+ return mnl_cb_run(ys->rx_buf, ret, ys->seq, ys->portid,
+ ynl_cb_null, ys);
+}
+
+int ynl_cb_null(const struct nlmsghdr *nlh, void *data)
+{
+ struct ynl_parse_arg *yarg = data;
+
+ yerr(yarg->ys, YNL_ERROR_UNEXPECT_MSG,
+ "Received a message when none were expected");
+
+ return MNL_CB_ERROR;
+}
+
+/* Init/fini and genetlink boiler plate */
+static int
+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)
+ ys->n_mcast_groups++;
+
+ if (!ys->n_mcast_groups)
+ return 0;
+
+ ys->mcast_groups = calloc(ys->n_mcast_groups,
+ sizeof(*ys->mcast_groups));
+ if (!ys->mcast_groups)
+ return MNL_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) {
+ strncpy(ys->mcast_groups[i].name,
+ mnl_attr_get_str(attr),
+ GENL_NAMSIZ - 1);
+ ys->mcast_groups[i].name[GENL_NAMSIZ - 1] = 0;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int ynl_get_family_info_cb(const struct nlmsghdr *nlh, void *data)
+{
+ 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)
+ if (ynl_get_family_info_mcast(ys, attr))
+ return MNL_CB_ERROR;
+
+ if (mnl_attr_get_type(attr) != CTRL_ATTR_FAMILY_ID)
+ continue;
+
+ if (mnl_attr_get_payload_len(attr) != sizeof(__u16)) {
+ yerr(ys, YNL_ERROR_ATTR_INVALID, "Invalid family ID");
+ return MNL_CB_ERROR;
+ }
+
+ ys->family_id = mnl_attr_get_u16(attr);
+ found_id = true;
+ }
+
+ if (!found_id) {
+ yerr(ys, YNL_ERROR_ATTR_MISSING, "Family ID missing");
+ return MNL_CB_ERROR;
+ }
+ return MNL_CB_OK;
+}
+
+static int ynl_sock_read_family(struct ynl_sock *ys, const char *family_name)
+{
+ struct ynl_parse_arg yarg = { .ys = ys, };
+ struct nlmsghdr *nlh;
+ 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);
+
+ err = mnl_socket_sendto(ys->sock, nlh, nlh->nlmsg_len);
+ 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");
+ 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));
+ 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);
+}
+
+struct ynl_sock *
+ynl_sock_create(const struct ynl_family *yf, struct ynl_error *yse)
+{
+ struct ynl_sock *ys;
+ int one = 1;
+
+ ys = malloc(sizeof(*ys) + 2 * MNL_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->ntf_last_next = &ys->ntf_first;
+
+ ys->sock = mnl_socket_open(NETLINK_GENERIC);
+ if (!ys->sock) {
+ __perr(yse, "failed to create a netlink socket");
+ goto err_free_sock;
+ }
+
+ if (mnl_socket_setsockopt(ys->sock, 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))) {
+ __perr(yse, "failed to enable netlink ext ACK");
+ goto err_close_sock;
+ }
+
+ ys->seq = random();
+ ys->portid = mnl_socket_get_portid(ys->sock);
+
+ if (ynl_sock_read_family(ys, yf->name)) {
+ if (yse)
+ memcpy(yse, &ys->err, sizeof(*yse));
+ goto err_close_sock;
+ }
+
+ return ys;
+
+err_close_sock:
+ mnl_socket_close(ys->sock);
+err_free_sock:
+ free(ys);
+ return NULL;
+}
+
+void ynl_sock_destroy(struct ynl_sock *ys)
+{
+ struct ynl_ntf_base_type *ntf;
+
+ mnl_socket_close(ys->sock);
+ while ((ntf = ynl_ntf_dequeue(ys)))
+ ynl_ntf_free(ntf);
+ free(ys->mcast_groups);
+ free(ys);
+}
+
+/* YNL multicast handling */
+
+void ynl_ntf_free(struct ynl_ntf_base_type *ntf)
+{
+ ntf->free(ntf);
+}
+
+int ynl_subscribe(struct ynl_sock *ys, const char *grp_name)
+{
+ unsigned int i;
+ int err;
+
+ for (i = 0; i < ys->n_mcast_groups; i++)
+ if (!strcmp(ys->mcast_groups[i].name, grp_name))
+ break;
+ if (i == ys->n_mcast_groups) {
+ yerr(ys, ENOENT, "Multicast group '%s' not found", grp_name);
+ return -1;
+ }
+
+ err = mnl_socket_setsockopt(ys->sock, 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;
+ }
+
+ return 0;
+}
+
+int ynl_socket_get_fd(struct ynl_sock *ys)
+{
+ return mnl_socket_get_fd(ys->sock);
+}
+
+struct ynl_ntf_base_type *ynl_ntf_dequeue(struct ynl_sock *ys)
+{
+ struct ynl_ntf_base_type *ntf;
+
+ if (!ynl_has_ntf(ys))
+ return NULL;
+
+ ntf = ys->ntf_first;
+ ys->ntf_first = ntf->next;
+ if (ys->ntf_last_next == &ntf->next)
+ ys->ntf_last_next = &ys->ntf_first;
+
+ return ntf;
+}
+
+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;
+ 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 (!info->cb)
+ return MNL_CB_ERROR;
+
+ rsp = calloc(1, info->alloc_sz);
+ rsp->free = info->free;
+ yarg.data = rsp->data;
+ yarg.rsp_policy = info->policy;
+
+ ret = info->cb(nlh, &yarg);
+ if (ret <= MNL_CB_STOP)
+ goto err_free;
+
+ rsp->family = nlh->nlmsg_type;
+ rsp->cmd = gehdr->cmd;
+
+ *ys->ntf_last_next = rsp;
+ ys->ntf_last_next = &rsp->next;
+
+ return MNL_CB_OK;
+
+err_free:
+ info->free(rsp);
+ return MNL_CB_ERROR;
+}
+
+static int ynl_ntf_trampoline(const struct nlmsghdr *nlh, void *data)
+{
+ return ynl_ntf_parse((struct ynl_sock *)data, nlh);
+}
+
+int ynl_ntf_check(struct ynl_sock *ys)
+{
+ ssize_t len;
+ 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);
+ if (err < 0)
+ return err;
+ } while (err > 0);
+
+ return 0;
+}
+
+/* YNL specific helpers used by the auto-generated code */
+
+struct ynl_dump_list_type *YNL_LIST_END = (void *)(0xb4d123);
+
+void ynl_error_unknown_notification(struct ynl_sock *ys, __u8 cmd)
+{
+ yerr(ys, YNL_ERROR_UNKNOWN_NTF,
+ "Unknown notification message type '%d'", 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;
+}
+
+static int
+ynl_check_alien(struct ynl_sock *ys, const struct nlmsghdr *nlh, __u32 rsp_cmd)
+{
+ struct genlmsghdr *gehdr;
+
+ if (mnl_nlmsg_get_payload_len(nlh) < sizeof(*gehdr)) {
+ yerr(ys, YNL_ERROR_INV_RESP,
+ "Kernel responded with truncated message");
+ return -1;
+ }
+
+ 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)
+{
+ struct ynl_req_state *yrs = data;
+ 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 yrs->cb(nlh, &yrs->yarg);
+}
+
+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);
+ 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;
+ } while (err > 0);
+
+ return 0;
+}
+
+static int ynl_dump_trampoline(const struct nlmsghdr *nlh, void *data)
+{
+ struct ynl_dump_state *ds = data;
+ struct ynl_dump_list_type *obj;
+ struct ynl_parse_arg yarg = {};
+ int ret;
+
+ ret = ynl_check_alien(ds->ys, nlh, ds->rsp_cmd);
+ if (ret)
+ return ret < 0 ? MNL_CB_ERROR : MNL_CB_OK;
+
+ obj = calloc(1, ds->alloc_sz);
+ if (!obj)
+ return MNL_CB_ERROR;
+
+ if (!ds->first)
+ ds->first = obj;
+ if (ds->last)
+ ds->last->next = obj;
+ ds->last = obj;
+
+ yarg.ys = ds->ys;
+ yarg.rsp_policy = ds->rsp_policy;
+ yarg.data = &obj->data;
+
+ return ds->cb(nlh, &yarg);
+}
+
+static void *ynl_dump_end(struct ynl_dump_state *ds)
+{
+ if (!ds->first)
+ return YNL_LIST_END;
+
+ ds->last->next = YNL_LIST_END;
+ return ds->first;
+}
+
+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);
+ 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 = mnl_cb_run2(ys->rx_buf, len, ys->seq, ys->portid,
+ ynl_dump_trampoline, yds,
+ ynl_cb_array, NLMSG_MIN_TYPE);
+ if (err < 0)
+ goto err_close_list;
+ } while (err > 0);
+
+ yds->first = ynl_dump_end(yds);
+ return 0;
+
+err_close_list:
+ yds->first = ynl_dump_end(yds);
+ return -1;
+}
diff --git a/tools/net/ynl/lib/ynl.h b/tools/net/ynl/lib/ynl.h
new file mode 100644
index 000000000000..9eafa3552c16
--- /dev/null
+++ b/tools/net/ynl/lib/ynl.h
@@ -0,0 +1,237 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+#ifndef __YNL_C_H
+#define __YNL_C_H 1
+
+#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;
+
+enum ynl_error_code {
+ YNL_ERROR_NONE = 0,
+ __YNL_ERRNO_END = 4096,
+ YNL_ERROR_INTERNAL,
+ YNL_ERROR_EXPECT_ACK,
+ YNL_ERROR_EXPECT_MSG,
+ YNL_ERROR_UNEXPECT_MSG,
+ YNL_ERROR_ATTR_MISSING,
+ YNL_ERROR_ATTR_INVALID,
+ YNL_ERROR_UNKNOWN_NTF,
+ YNL_ERROR_INV_RESP,
+};
+
+/**
+ * struct ynl_error - error encountered by YNL
+ * @code: errno (low values) or YNL error code (enum ynl_error_code)
+ * @attr_offs: offset of bad attribute (for very advanced users)
+ * @msg: error message
+ *
+ * Error information for when YNL operations fail.
+ * Users should interact with the err member of struct ynl_sock directly.
+ * The main exception to that rule is ynl_sock_create().
+ */
+struct ynl_error {
+ enum ynl_error_code code;
+ unsigned int attr_offs;
+ char msg[512];
+};
+
+/**
+ * struct ynl_family - YNL family info
+ * Family description generated by codegen. Pass to ynl_sock_create().
+ */
+struct ynl_family {
+/* private: */
+ const char *name;
+ const struct ynl_ntf_info *ntf_info;
+ unsigned int ntf_info_size;
+};
+
+/**
+ * struct ynl_sock - YNL wrapped netlink socket
+ * @err: YNL error descriptor, cleared on every request.
+ */
+struct ynl_sock {
+ struct ynl_error err;
+
+/* private: */
+ const struct ynl_family *family;
+ struct mnl_socket *sock;
+ __u32 seq;
+ __u32 portid;
+ __u16 family_id;
+
+ unsigned int n_mcast_groups;
+ struct {
+ unsigned int id;
+ char name[GENL_NAMSIZ];
+ } *mcast_groups;
+
+ struct ynl_ntf_base_type *ntf_first;
+ struct ynl_ntf_base_type **ntf_last_next;
+
+ struct nlmsghdr *nlh;
+ struct ynl_policy_nest *req_policy;
+ unsigned char *tx_buf;
+ unsigned char *rx_buf;
+ unsigned char raw_buf[];
+};
+
+struct ynl_sock *
+ynl_sock_create(const struct ynl_family *yf, struct ynl_error *e);
+void ynl_sock_destroy(struct ynl_sock *ys);
+
+#define ynl_dump_foreach(dump, iter) \
+ for (typeof(dump->obj) *iter = &dump->obj; \
+ !ynl_dump_obj_is_last(iter); \
+ iter = ynl_dump_obj_next(iter))
+
+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);
+
+/**
+ * ynl_has_ntf() - check if socket has *parsed* notifications
+ * @ys: active YNL socket
+ *
+ * Note that this does not take into account notifications sitting
+ * in netlink socket, just the notifications which have already been
+ * read and parsed (e.g. during a ynl_ntf_check() call).
+ */
+static inline bool ynl_has_ntf(struct ynl_sock *ys)
+{
+ return ys->ntf_last_next != &ys->ntf_first;
+}
+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
index 0692293447ad..3b343d6cbbc0 100644
--- a/tools/net/ynl/lib/ynl.py
+++ b/tools/net/ynl/lib/ynl.py
@@ -582,8 +582,9 @@ class YnlFamily(SpecFamily):
print('Unexpected message: ' + repr(gm))
continue
- rsp.append(self._decode(gm.raw_attrs, op.attr_set.name)
- | gm.fixed_header_attrs)
+ rsp_msg = self._decode(gm.raw_attrs, op.attr_set.name)
+ rsp_msg.update(gm.fixed_header_attrs)
+ rsp.append(rsp_msg)
if not rsp:
return None
diff --git a/tools/net/ynl/samples/.gitignore b/tools/net/ynl/samples/.gitignore
new file mode 100644
index 000000000000..2aae60c4829f
--- /dev/null
+++ b/tools/net/ynl/samples/.gitignore
@@ -0,0 +1,3 @@
+ethtool
+devlink
+netdev
diff --git a/tools/net/ynl/samples/Makefile b/tools/net/ynl/samples/Makefile
new file mode 100644
index 000000000000..f2db8bb78309
--- /dev/null
+++ b/tools/net/ynl/samples/Makefile
@@ -0,0 +1,30 @@
+# SPDX-License-Identifier: GPL-2.0
+
+include ../Makefile.deps
+
+CC=gcc
+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
+
+SRCS=$(wildcard *.c)
+BINS=$(patsubst %.c,%,${SRCS})
+
+include $(wildcard *.d)
+
+all: $(BINS)
+
+$(BINS): ../lib/ynl.a ../generated/protos.a
+
+clean:
+ rm -f *.o *.d *~
+
+hardclean: clean
+ rm -f $(BINS)
+
+.PHONY: all clean
+.DEFAULT_GOAL=all
diff --git a/tools/net/ynl/samples/devlink.c b/tools/net/ynl/samples/devlink.c
new file mode 100644
index 000000000000..d2611d7ebab4
--- /dev/null
+++ b/tools/net/ynl/samples/devlink.c
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <stdio.h>
+#include <string.h>
+
+#include <ynl.h>
+
+#include "devlink-user.h"
+
+int main(int argc, char **argv)
+{
+ struct devlink_get_list *devs;
+ struct ynl_sock *ys;
+
+ ys = ynl_sock_create(&ynl_devlink_family, NULL);
+ if (!ys)
+ return 1;
+
+ devs = devlink_get_dump(ys);
+ if (!devs)
+ goto err_close;
+
+ ynl_dump_foreach(devs, d) {
+ struct devlink_info_get_req *info_req;
+ struct devlink_info_get_rsp *info_rsp;
+
+ printf("%s/%s:\n", d->bus_name, d->dev_name);
+
+ info_req = devlink_info_get_req_alloc();
+ devlink_info_get_req_set_bus_name(info_req, d->bus_name);
+ devlink_info_get_req_set_dev_name(info_req, d->dev_name);
+
+ info_rsp = devlink_info_get(ys, info_req);
+ devlink_info_get_req_free(info_req);
+ if (!info_rsp)
+ goto err_free_devs;
+
+ if (info_rsp->_present.info_driver_name_len)
+ printf(" driver: %s\n", info_rsp->info_driver_name);
+ if (info_rsp->n_info_version_running)
+ printf(" running fw:\n");
+ for (unsigned i = 0; i < info_rsp->n_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);
+ printf(" ...\n");
+ devlink_info_get_rsp_free(info_rsp);
+ }
+ devlink_get_list_free(devs);
+
+ ynl_sock_destroy(ys);
+
+ return 0;
+
+err_free_devs:
+ devlink_get_list_free(devs);
+err_close:
+ fprintf(stderr, "YNL: %s\n", ys->err.msg);
+ ynl_sock_destroy(ys);
+ return 2;
+}
diff --git a/tools/net/ynl/samples/ethtool.c b/tools/net/ynl/samples/ethtool.c
new file mode 100644
index 000000000000..a7ebbd1b98db
--- /dev/null
+++ b/tools/net/ynl/samples/ethtool.c
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <stdio.h>
+#include <string.h>
+
+#include <ynl.h>
+
+#include <net/if.h>
+
+#include "ethtool-user.h"
+
+int main(int argc, char **argv)
+{
+ struct ethtool_channels_get_req_dump creq = {};
+ struct ethtool_rings_get_req_dump rreq = {};
+ struct ethtool_channels_get_list *channels;
+ struct ethtool_rings_get_list *rings;
+ struct ynl_sock *ys;
+
+ ys = ynl_sock_create(&ynl_ethtool_family, NULL);
+ if (!ys)
+ return 1;
+
+ creq._present.header = 1; /* ethtool needs an empty nest, sigh */
+ channels = ethtool_channels_get_dump(ys, &creq);
+ if (!channels)
+ goto err_close;
+
+ printf("Channels:\n");
+ ynl_dump_foreach(channels, dev) {
+ printf(" %8s: ", dev->header.dev_name);
+ if (dev->_present.rx_count)
+ printf("rx %d ", dev->rx_count);
+ if (dev->_present.tx_count)
+ printf("tx %d ", dev->tx_count);
+ if (dev->_present.combined_count)
+ printf("combined %d ", dev->combined_count);
+ printf("\n");
+ }
+ ethtool_channels_get_list_free(channels);
+
+ rreq._present.header = 1; /* ethtool needs an empty nest.. */
+ rings = ethtool_rings_get_dump(ys, &rreq);
+ if (!rings)
+ goto err_close;
+
+ printf("Rings:\n");
+ ynl_dump_foreach(rings, dev) {
+ printf(" %8s: ", dev->header.dev_name);
+ if (dev->_present.rx)
+ printf("rx %d ", dev->rx);
+ if (dev->_present.tx)
+ printf("tx %d ", dev->tx);
+ printf("\n");
+ }
+ ethtool_rings_get_list_free(rings);
+
+ 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/netdev.c b/tools/net/ynl/samples/netdev.c
new file mode 100644
index 000000000000..d31268aa47c5
--- /dev/null
+++ b/tools/net/ynl/samples/netdev.c
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <stdio.h>
+#include <string.h>
+
+#include <ynl.h>
+
+#include <net/if.h>
+
+#include "netdev-user.h"
+
+/* netdev genetlink family code sample
+ * This sample shows off basics of the netdev family but also notification
+ * handling, hence the somewhat odd UI. We subscribe to notifications first
+ * then wait for ifc selection, so the socket may already accumulate
+ * notifications as we wait. This allows us to test that YNL can handle
+ * requests and notifications getting interleaved.
+ */
+
+static void netdev_print_device(struct netdev_dev_get_rsp *d, unsigned int op)
+{
+ char ifname[IF_NAMESIZE];
+ const char *name;
+
+ if (!d->_present.ifindex)
+ return;
+
+ name = if_indextoname(d->ifindex, ifname);
+ if (name)
+ printf("%8s", name);
+ printf("[%d]\t", d->ifindex);
+
+ if (!d->_present.xdp_features)
+ return;
+
+ printf("%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));
+ }
+
+ name = netdev_op_str(op);
+ if (name)
+ printf(" (ntf: %s)", name);
+ printf("\n");
+}
+
+int main(int argc, char **argv)
+{
+ struct netdev_dev_get_list *devs;
+ struct ynl_ntf_base_type *ntf;
+ struct ynl_error yerr;
+ struct ynl_sock *ys;
+ int ifindex = 0;
+
+ if (argc > 1)
+ ifindex = strtol(argv[1], NULL, 0);
+
+ ys = ynl_sock_create(&ynl_netdev_family, &yerr);
+ if (!ys) {
+ fprintf(stderr, "YNL: %s\n", yerr.msg);
+ return 1;
+ }
+
+ if (ynl_subscribe(ys, "mgmt"))
+ goto err_close;
+
+ printf("Select ifc ($ifindex; or 0 = dump; or -2 ntf check): ");
+ scanf("%d", &ifindex);
+
+ if (ifindex > 0) {
+ struct netdev_dev_get_req *req;
+ struct netdev_dev_get_rsp *d;
+
+ req = netdev_dev_get_req_alloc();
+ netdev_dev_get_req_set_ifindex(req, ifindex);
+
+ d = netdev_dev_get(ys, req);
+ netdev_dev_get_req_free(req);
+ if (!d)
+ goto err_close;
+
+ netdev_print_device(d, 0);
+ netdev_dev_get_rsp_free(d);
+ } else if (!ifindex) {
+ devs = netdev_dev_get_dump(ys);
+ if (!devs)
+ goto err_close;
+
+ ynl_dump_foreach(devs, d)
+ netdev_print_device(d, 0);
+ netdev_dev_get_list_free(devs);
+ } else if (ifindex == -2) {
+ ynl_ntf_check(ys);
+ }
+ while ((ntf = ynl_ntf_dequeue(ys))) {
+ netdev_print_device((struct netdev_dev_get_rsp *)&ntf->data,
+ ntf->cmd);
+ ynl_ntf_free(ntf);
+ }
+
+ ynl_sock_destroy(ys);
+ return 0;
+
+err_close:
+ fprintf(stderr, "YNL: %s\n", ys->err.msg);
+ ynl_sock_destroy(ys);
+ return 2;
+}
diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py
index be664510f484..71c5e79e877f 100755
--- a/tools/net/ynl/ynl-gen-c.py
+++ b/tools/net/ynl/ynl-gen-c.py
@@ -4,6 +4,7 @@
import argparse
import collections
import os
+import re
import yaml
from lib import SpecFamily, SpecAttrSet, SpecAttr, SpecOperation, SpecEnumSet, SpecEnumEntry
@@ -48,6 +49,11 @@ class Type(SpecAttr):
else:
self.nested_render_name = f"{family.name}_{c_lower(self.nested_attrs)}"
+ if self.nested_attrs in self.family.consts:
+ self.nested_struct_type = 'struct ' + self.nested_render_name + '_'
+ else:
+ self.nested_struct_type = 'struct ' + self.nested_render_name
+
self.c_name = c_lower(self.name)
if self.c_name in _C_KW:
self.c_name += '_'
@@ -57,8 +63,11 @@ class Type(SpecAttr):
delattr(self, "enum_name")
def resolve(self):
- self.enum_name = f"{self.attr_set.name_prefix}{self.name}"
- self.enum_name = c_upper(self.enum_name)
+ if '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)
def is_multi_val(self):
return None
@@ -94,7 +103,10 @@ class Type(SpecAttr):
def arg_member(self, ri):
member = self._complex_member_type(ri)
if member:
- return [member + ' *' + self.c_name]
+ arg = [member + ' *' + 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):
@@ -150,7 +162,7 @@ class Type(SpecAttr):
init_lines = [init_lines]
kw = 'if' if first else 'else if'
- ri.cw.block_start(line=f"{kw} (mnl_attr_get_type(attr) == {self.enum_name})")
+ ri.cw.block_start(line=f"{kw} (type == {self.enum_name})")
if local_vars:
for local in local_vars:
ri.cw.p(local)
@@ -170,6 +182,7 @@ class Type(SpecAttr):
for line in lines:
ri.cw.p(line)
ri.cw.block_end()
+ return True
def _setter_lines(self, ri, member, presence):
raise Exception(f"Setter not implemented for class type {self.type}")
@@ -187,9 +200,12 @@ class Type(SpecAttr):
code.append(presence + ' = 1;')
code += self._setter_lines(ri, member, presence)
- ri.cw.write_func('static inline void',
- f"{op_prefix(ri, direction, deref=deref)}_set_{'_'.join(ref)}",
- body=code,
+ func_name = f"{op_prefix(ri, direction, deref=deref)}_set_{'_'.join(ref)}"
+ free = bool([x for x in code if 'free(' in x])
+ 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,
args=[f'{type_name(ri, direction, deref=deref)} *{var}'] + self.arg_member(ri))
@@ -197,6 +213,12 @@ class TypeUnused(Type):
def presence_type(self):
return ''
+ def arg_member(self, ri):
+ return []
+
+ def _attr_get(self, ri, var):
+ return ['return MNL_CB_ERROR;'], None, None
+
def _attr_typol(self):
return '.type = YNL_PT_REJECT, '
@@ -208,12 +230,24 @@ class TypePad(Type):
def presence_type(self):
return ''
+ def arg_member(self, ri):
+ return []
+
def _attr_typol(self):
- return '.type = YNL_PT_REJECT, '
+ return '.type = YNL_PT_IGNORE, '
+
+ def attr_put(self, ri, var):
+ pass
+
+ def attr_get(self, ri, var, first):
+ pass
def attr_policy(self, cw):
pass
+ def setter(self, ri, space, direction, deref=False, ref=None):
+ pass
+
class TypeScalar(Type):
def __init__(self, family, attr_set, attr, value):
@@ -239,7 +273,8 @@ class TypeScalar(Type):
else:
self.is_bitfield = False
- if 'enum' in self.attr and not self.is_bitfield:
+ 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'])}"
else:
self.type_name = '__' + self.type
@@ -265,8 +300,10 @@ class TypeScalar(Type):
return f"NLA_POLICY_MIN({policy}, {self.checks['min']})"
elif 'enum' in self.attr:
enum = self.family.consts[self.attr['enum']]
- cnt = len(enum['entries'])
- return f"NLA_POLICY_MAX({policy}, {cnt - 1})"
+ low, high = enum.value_range()
+ if low == 0:
+ return f"NLA_POLICY_MAX({policy}, {high})"
+ return f"NLA_POLICY_RANGE({policy}, {low}, {high})"
return super()._attr_policy(policy)
def _attr_typol(self):
@@ -395,7 +432,7 @@ class TypeBinary(Type):
class TypeNest(Type):
def _complex_member_type(self, ri):
- return f"struct {self.nested_render_name}"
+ 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});')
@@ -411,7 +448,8 @@ class TypeNest(Type):
f"{self.enum_name}, &{var}->{self.c_name})")
def _attr_get(self, ri, var):
- get_lines = [f"{self.nested_render_name}_parse(&parg, attr);"]
+ get_lines = [f"if ({self.nested_render_name}_parse(&parg, attr))",
+ "return MNL_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
@@ -424,15 +462,27 @@ class TypeNest(Type):
class TypeMultiAttr(Type):
+ def __init__(self, family, attr_set, attr, value, base_type):
+ super().__init__(family, attr_set, attr, value)
+
+ self.base_type = base_type
+
def is_multi_val(self):
return True
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 f"struct {self.nested_render_name}"
+ return self.nested_struct_type
elif self.attr['type'] in scalars:
scalar_pfx = '__' if ri.ku_space == 'user' else ''
return scalar_pfx + self.attr['type']
@@ -443,20 +493,42 @@ class TypeMultiAttr(Type):
return 'type' not in self.attr or self.attr['type'] == 'nest'
def free(self, ri, var, ref):
- if 'type' not in self.attr or self.attr['type'] == 'nest':
+ if self.attr['type'] in scalars:
+ ri.cw.p(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});")
+ else:
+ raise Exception(f"Free of MultiAttr sub-type {self.attr['type']} not supported yet")
+
+ def _attr_policy(self, policy):
+ return self.base_type._attr_policy(policy)
def _attr_typol(self):
- if 'type' not in self.attr or self.attr['type'] == 'nest':
- return f'.type = YNL_PT_NEST, .nest = &{self.nested_render_name}_nest, '
- elif self.attr['type'] in scalars:
- return f".type = YNL_PT_U{self.attr['type'][1:]}, "
- else:
- raise Exception(f"Sub-type {self.attr['type']} not supported yet")
+ return self.base_type._attr_typol()
def _attr_get(self, ri, var):
- return f'{var}->n_{self.c_name}++;', None, None
+ return f'n_{self.c_name}++;', None, None
+
+ 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]);")
+ 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++)")
+ 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};",
+ f"{presence} = n_{self.c_name};"]
class TypeArrayNest(Type):
@@ -468,7 +540,7 @@ class TypeArrayNest(Type):
def _complex_member_type(self, ri):
if 'sub-type' not in self.attr or self.attr['sub-type'] == 'nest':
- return f"struct {self.nested_render_name}"
+ return self.nested_struct_type
elif self.attr['sub-type'] in scalars:
scalar_pfx = '__' if ri.ku_space == 'user' else ''
return scalar_pfx + self.attr['sub-type']
@@ -488,7 +560,7 @@ class TypeArrayNest(Type):
class TypeNestTypeValue(Type):
def _complex_member_type(self, ri):
- return f"struct {self.nested_render_name}"
+ return self.nested_struct_type
def _attr_typol(self):
return f'.type = YNL_PT_NEST, .nest = &{self.nested_render_name}_nest, '
@@ -531,6 +603,8 @@ class Struct:
else:
self.render_name = f"{family.name}_{c_lower(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 + ' *'
self.request = False
@@ -591,7 +665,14 @@ class EnumEntry(SpecEnumEntry):
class EnumSet(SpecEnumSet):
def __init__(self, family, yaml):
self.render_name = c_lower(family.name + '-' + yaml['name'])
- self.enum_name = 'enum ' + self.render_name
+
+ if 'enum-name' in yaml:
+ if yaml['enum-name']:
+ self.enum_name = 'enum ' + c_lower(yaml['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']}-")
@@ -600,6 +681,15 @@ class EnumSet(SpecEnumSet):
def new_entry(self, entry, prev_entry, value_start):
return EnumEntry(self, entry, prev_entry, value_start)
+ def value_range(self):
+ low = min([x.value for x in self.entries.values()])
+ 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 low, high
+
class AttrSet(SpecAttrSet):
def __init__(self, family, yaml):
@@ -630,42 +720,44 @@ class AttrSet(SpecAttrSet):
self.c_name = ''
def new_attr(self, elem, value):
- if 'multi-attr' in elem and elem['multi-attr']:
- return TypeMultiAttr(self.family, self, elem, value)
- elif elem['type'] in scalars:
- return TypeScalar(self.family, self, elem, value)
+ if elem['type'] in scalars:
+ t = TypeScalar(self.family, self, elem, value)
elif elem['type'] == 'unused':
- return TypeUnused(self.family, self, elem, value)
+ t = TypeUnused(self.family, self, elem, value)
elif elem['type'] == 'pad':
- return TypePad(self.family, self, elem, value)
+ t = TypePad(self.family, self, elem, value)
elif elem['type'] == 'flag':
- return TypeFlag(self.family, self, elem, value)
+ t = TypeFlag(self.family, self, elem, value)
elif elem['type'] == 'string':
- return TypeString(self.family, self, elem, value)
+ t = TypeString(self.family, self, elem, value)
elif elem['type'] == 'binary':
- return TypeBinary(self.family, self, elem, value)
+ t = TypeBinary(self.family, self, elem, value)
elif elem['type'] == 'nest':
- return TypeNest(self.family, self, elem, value)
+ t = TypeNest(self.family, self, elem, value)
elif elem['type'] == 'array-nest':
- return TypeArrayNest(self.family, self, elem, value)
+ t = TypeArrayNest(self.family, self, elem, value)
elif elem['type'] == 'nest-type-value':
- return TypeNestTypeValue(self.family, self, elem, value)
+ t = TypeNestTypeValue(self.family, self, elem, value)
else:
raise Exception(f"No typed class for type {elem['type']}")
+ if 'multi-attr' in elem and elem['multi-attr']:
+ t = TypeMultiAttr(self.family, self, elem, value, t)
+
+ return t
+
class Operation(SpecOperation):
def __init__(self, family, yaml, req_value, rsp_value):
super().__init__(family, yaml, req_value, rsp_value)
- if req_value != rsp_value:
- raise Exception("Directional messages not supported by codegen")
-
self.render_name = family.name + '_' + c_lower(self.name)
self.dual_policy = ('do' in yaml and 'request' in yaml['do']) and \
('dump' in yaml and 'request' in yaml['dump'])
+ self.has_ntf = False
+
# Added by resolve:
self.enum_name = None
delattr(self, "enum_name")
@@ -678,16 +770,12 @@ class Operation(SpecOperation):
else:
self.enum_name = self.family.async_op_prefix + c_upper(self.name)
- def add_notification(self, op):
- if 'notify' not in self.yaml:
- self.yaml['notify'] = dict()
- self.yaml['notify']['reply'] = self.yaml['do']['reply']
- self.yaml['notify']['cmds'] = []
- self.yaml['notify']['cmds'].append(op)
+ def mark_has_ntf(self):
+ self.has_ntf = True
class Family(SpecFamily):
- def __init__(self, file_name):
+ def __init__(self, file_name, exclude_ops):
# Added by resolve:
self.c_name = None
delattr(self, "c_name")
@@ -702,7 +790,7 @@ class Family(SpecFamily):
self.hooks = None
delattr(self, "hooks")
- super().__init__(file_name)
+ super().__init__(file_name, exclude_ops=exclude_ops)
self.fam_key = c_upper(self.yaml.get('c-family-name', self.yaml["name"] + '_FAMILY_NAME'))
self.ver_key = c_upper(self.yaml.get('c-version-name', self.yaml["name"] + '_FAMILY_VERSION'))
@@ -745,14 +833,12 @@ class Family(SpecFamily):
self.root_sets = dict()
# dict space-name -> set('request', 'reply')
self.pure_nested_structs = dict()
- self.all_notify = dict()
+ self._mark_notify()
self._mock_up_events()
- self._dictify()
self._load_root_sets()
self._load_nested_sets()
- self._load_all_notify()
self._load_hooks()
self.kernel_policy = self.yaml.get('kernel-policy', 'split')
@@ -768,6 +854,11 @@ class Family(SpecFamily):
def new_operation(self, elem, req_value, rsp_value):
return Operation(self, elem, req_value, rsp_value)
+ def _mark_notify(self):
+ for op in self.msgs.values():
+ if 'notify' in op:
+ self.ops[op['notify']].mark_has_ntf()
+
# Fake a 'do' equivalent of all events, so that we can render their response parsing
def _mock_up_events(self):
for op in self.yaml['operations']['list']:
@@ -778,16 +869,8 @@ class Family(SpecFamily):
}
}
- def _dictify(self):
- ntf = []
- for msg in self.msgs.values():
- if 'notify' in msg:
- ntf.append(msg)
- for n in ntf:
- self.ops[n['notify']].add_notification(n)
-
def _load_root_sets(self):
- for op_name, op in self.ops.items():
+ for op_name, op in self.msgs.items():
if 'attribute-set' not in op:
continue
@@ -798,6 +881,8 @@ class Family(SpecFamily):
req_attrs.update(set(op[op_mode]['request']['attributes']))
if op_mode in op and 'reply' in op[op_mode]:
rsp_attrs.update(set(op[op_mode]['reply']['attributes']))
+ if 'event' in op:
+ rsp_attrs.update(set(op['event']['attributes']))
if op['attribute-set'] not in self.root_sets:
self.root_sets[op['attribute-set']] = {'request': req_attrs, 'reply': rsp_attrs}
@@ -806,33 +891,73 @@ class Family(SpecFamily):
self.root_sets[op['attribute-set']]['reply'].update(rsp_attrs)
def _load_nested_sets(self):
+ attr_set_queue = list(self.root_sets.keys())
+ attr_set_seen = set(self.root_sets.keys())
+
+ 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:
+ 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:
- inherit = set()
nested = spec['nested-attributes']
- if nested not in self.root_sets:
- self.pure_nested_structs[nested] = Struct(self, nested, inherited=inherit)
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
- 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)
-
- def _load_all_notify(self):
- for op_name, op in self.ops.items():
- if not op:
- continue
-
- if 'notify' in op:
- self.all_notify[op_name] = op['notify']['cmds']
+ # 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
+ for attr_set, struct in reversed(self.pure_nested_structs.items()):
+ for _, spec in self.attr_sets[attr_set].items():
+ if 'nested-attributes' in spec:
+ child = self.pure_nested_structs.get(spec['nested-attributes'])
+ if child:
+ child.request |= struct.request
+ child.reply |= struct.reply
def _load_global_policy(self):
global_set = set()
@@ -874,33 +999,38 @@ class Family(SpecFamily):
class RenderInfo:
- def __init__(self, cw, family, ku_space, op, op_name, op_mode, attr_set=None):
+ def __init__(self, cw, family, ku_space, op, op_mode, attr_set=None):
self.family = family
self.nl = cw.nlib
self.ku_space = ku_space
- self.op = op
- self.op_name = op_name
self.op_mode = op_mode
+ self.op = op
# 'do' and 'dump' response parsing is identical
- if op_mode != 'do' and 'dump' in op and 'do' in op and 'reply' in op['do'] and \
- op["do"]["reply"] == op["dump"]["reply"]:
- self.type_consistent = True
- else:
- self.type_consistent = op_mode == 'event'
+ 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.attr_set = attr_set
if not self.attr_set:
self.attr_set = op['attribute-set']
+ self.type_name_conflict = False
if op:
- self.type_name = c_lower(op_name)
+ self.type_name = c_lower(op.name)
else:
self.type_name = c_lower(attr_set)
+ if attr_set in family.consts:
+ self.type_name_conflict = True
self.cw = cw
self.struct = dict()
+ if op_mode == 'notify':
+ op_mode = 'do'
for op_dir in ['request', 'reply']:
if op and op_dir in op[op_mode]:
self.struct[op_dir] = Struct(family, self.attr_set,
@@ -914,6 +1044,7 @@ class CodeWriter:
self.nlib = nlib
self._nl = False
+ self._block_end = False
self._silent_block = False
self._ind = 0
self._out = out_file
@@ -923,9 +1054,17 @@ class CodeWriter:
return line.startswith('if') or line.startswith('while') or line.startswith('for')
def p(self, line, add_ind=0):
+ if self._block_end:
+ self._block_end = False
+ if line.startswith('else'):
+ line = '} ' + line
+ else:
+ self._out.write('\t' * self._ind + '}\n')
+
if self._nl:
self._out.write('\n')
self._nl = False
+
ind = self._ind
if line[-1] == ':':
ind -= 1
@@ -949,7 +1088,14 @@ class CodeWriter:
if line and line[0] not in {';', ','}:
line = ' ' + line
self._ind -= 1
- self.p('}' + line)
+ self._nl = False
+ if not line:
+ # Delay printing closing bracket in case "else" comes next
+ if self._block_end:
+ self._out.write('\t' * (self._ind + 1) + '}\n')
+ self._block_end = True
+ else:
+ self.p('}' + line)
def write_doc_line(self, doc, indent=True):
words = doc.split()
@@ -1068,7 +1214,40 @@ op_mode_to_wrapper = {
}
_C_KW = {
- 'do'
+ 'auto',
+ 'bool',
+ 'break',
+ 'case',
+ 'char',
+ 'const',
+ 'continue',
+ 'default',
+ 'do',
+ 'double',
+ 'else',
+ 'enum',
+ 'extern',
+ 'float',
+ 'for',
+ 'goto',
+ 'if',
+ 'inline',
+ 'int',
+ 'long',
+ 'register',
+ 'return',
+ 'short',
+ 'signed',
+ 'sizeof',
+ 'static',
+ 'struct',
+ 'switch',
+ 'typedef',
+ 'union',
+ 'unsigned',
+ 'void',
+ 'volatile',
+ 'while'
}
@@ -1131,10 +1310,6 @@ def print_dump_prototype(ri):
print_prototype(ri, "request")
-def put_typol_fwd(cw, struct):
- cw.p(f'extern struct ynl_policy_nest {struct.render_name}_nest;')
-
-
def put_typol(cw, struct):
type_max = struct.attr_set.max_name
cw.block_start(line=f'struct ynl_policy_attr {struct.render_name}_policy[{type_max} + 1] =')
@@ -1152,6 +1327,58 @@ def put_typol(cw, struct):
cw.nl()
+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}']
+ 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('return NULL;')
+ cw.p(f'return {map_name}[{arg_name}];')
+ cw.block_end()
+ cw.nl()
+
+
+def put_op_name_fwd(family, cw):
+ cw.write_func_prot('const char *', f'{family.name}_op_str', ['int op'], suffix=';')
+
+
+def put_op_name(family, cw):
+ map_name = f'{family.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:
+ if op.req_value == op.rsp_value:
+ cw.p(f'[{op.enum_name}] = "{op_name}",')
+ else:
+ cw.p(f'[{op.rsp_value}] = "{op_name}",')
+ cw.block_end(line=';')
+ cw.nl()
+
+ _put_enum_to_str_helper(cw, family.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']
+ cw.write_func_prot('const char *', f'{enum.render_name}_str', args, suffix=';')
+
+
+def put_enum_to_str(family, cw, enum):
+ map_name = f'{enum.render_name}_strmap'
+ cw.block_start(line=f"static const char * const {map_name}[] =")
+ for entry in enum.entries.values():
+ cw.p(f'[{entry.value}] = "{entry.name}",')
+ cw.block_end(line=';')
+ cw.nl()
+
+ _put_enum_to_str_helper(cw, enum.render_name, map_name, 'value', enum=enum)
+
+
def put_req_nested(ri, struct):
func_args = ['struct nlmsghdr *nlh',
'unsigned int attr_type',
@@ -1196,6 +1423,11 @@ def _multi_parse(ri, struct, init_lines, local_vars):
local_vars.append('struct ynl_parse_arg parg;')
init_lines.append('parg.ys = yarg->ys;')
+ all_multi = array_nests | multi_attrs
+
+ for anest in sorted(all_multi):
+ local_vars.append(f"unsigned int n_{struct[anest].c_name} = 0;")
+
ri.cw.block_start()
ri.cw.write_func_lvar(local_vars)
@@ -1206,13 +1438,21 @@ 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]
+ 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.nl()
first = True
for _, arg in struct.member_list():
- arg.attr_get(ri, 'dst', first=first)
- first = False
+ good = arg.attr_get(ri, 'dst', first=first)
+ # First may be 'unused' or 'pad', ignore those
+ first &= not good
ri.cw.block_end()
ri.cw.nl()
@@ -1220,8 +1460,9 @@ def _multi_parse(ri, struct, init_lines, local_vars):
for anest in sorted(array_nests):
aspec = struct[anest]
- ri.cw.block_start(line=f"if (dst->n_{aspec.c_name})")
- ri.cw.p(f"dst->{aspec.c_name} = calloc(dst->n_{aspec.c_name}, sizeof(*dst->{aspec.c_name}));")
+ ri.cw.block_start(line=f"if (n_{aspec.c_name})")
+ ri.cw.p(f"dst->{aspec.c_name} = calloc({aspec.c_name}, sizeof(*dst->{aspec.c_name}));")
+ ri.cw.p(f"dst->n_{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})")
@@ -1235,8 +1476,9 @@ def _multi_parse(ri, struct, init_lines, local_vars):
for anest in sorted(multi_attrs):
aspec = struct[anest]
- ri.cw.block_start(line=f"if (dst->n_{aspec.c_name})")
- ri.cw.p(f"dst->{aspec.c_name} = calloc(dst->n_{aspec.c_name}, sizeof(*dst->{aspec.c_name}));")
+ 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('i = 0;')
if 'nested-attributes' in aspec:
ri.cw.p(f"parg.rsp_policy = &{aspec.nested_render_name}_nest;")
@@ -1304,13 +1546,13 @@ def print_req(ri):
ret_err = '-1'
direction = "request"
local_vars = ['struct nlmsghdr *nlh;',
- 'int len, err;']
+ '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_parse_arg yarg = { .ys = ys, };']
+ 'struct ynl_req_state yrs = { .yarg = { .ys = ys, }, };']
print_prototype(ri, direction, terminate=False)
ri.cw.block_start()
@@ -1320,41 +1562,39 @@ def print_req(ri):
ri.cw.p(f"ys->req_policy = &{ri.struct['request'].render_name}_nest;")
if 'reply' in ri.op[ri.op_mode]:
- ri.cw.p(f"yarg.rsp_policy = &{ri.struct['reply'].render_name}_nest;")
+ ri.cw.p(f"yrs.yarg.rsp_policy = &{ri.struct['reply'].render_name}_nest;")
ri.cw.nl()
for _, attr in ri.struct["request"].member_list():
attr.attr_put(ri, "req")
ri.cw.nl()
- ri.cw.p('err = mnl_socket_sendto(ys->sock, nlh, nlh->nlmsg_len);')
- ri.cw.p('if (err < 0)')
- ri.cw.p(f"return {ret_err};")
- ri.cw.nl()
- ri.cw.p('len = mnl_socket_recvfrom(ys->sock, ys->rx_buf, MNL_SOCKET_BUFFER_SIZE);')
- ri.cw.p('if (len < 0)')
- ri.cw.p(f"return {ret_err};")
- 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('yarg.data = rsp;')
+ ri.cw.p('yrs.yarg.data = rsp;')
+ ri.cw.p(f"yrs.cb = {op_prefix(ri, 'reply')}_parse;")
+ if ri.op.value is not None:
+ ri.cw.p(f'yrs.rsp_cmd = {ri.op.enum_name};')
+ else:
+ ri.cw.p(f'yrs.rsp_cmd = {ri.op.rsp_value};')
ri.cw.nl()
- ri.cw.p(f"err = {ri.nl.parse_cb_run(op_prefix(ri, 'reply') + '_parse', '&yarg', False)};")
- ri.cw.p('if (err < 0)')
+ parse_arg = '&yrs'
+ ri.cw.p(f"err = ynl_exec(ys, nlh, {parse_arg});")
+ ri.cw.p('if (err < 0)')
+ if 'reply' in ri.op[ri.op_mode]:
ri.cw.p('goto err_free;')
- ri.cw.nl()
-
- ri.cw.p('err = ynl_recv_ack(ys, err);')
- ri.cw.p('if (err)')
- ri.cw.p('goto err_free;')
+ else:
+ ri.cw.p('return -1;')
ri.cw.nl()
+
ri.cw.p(f"return {ret_ok};")
ri.cw.nl()
- ri.cw.p('err_free:')
if 'reply' in ri.op[ri.op_mode]:
+ ri.cw.p('err_free:')
ri.cw.p(f"{call_free(ri, rdir(direction), 'rsp')}")
- ri.cw.p(f"return {ret_err};")
+ ri.cw.p(f"return {ret_err};")
+
ri.cw.block_end()
@@ -1364,7 +1604,7 @@ def print_dump(ri):
ri.cw.block_start()
local_vars = ['struct ynl_dump_state yds = {};',
'struct nlmsghdr *nlh;',
- 'int len, err;']
+ 'int err;']
for var in local_vars:
ri.cw.p(f'{var}')
@@ -1373,6 +1613,10 @@ def print_dump(ri):
ri.cw.p('yds.ys = ys;')
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);")
@@ -1384,20 +1628,9 @@ def print_dump(ri):
attr.attr_put(ri, "req")
ri.cw.nl()
- ri.cw.p('err = mnl_socket_sendto(ys->sock, nlh, nlh->nlmsg_len);')
- ri.cw.p('if (err < 0)')
- ri.cw.p('return NULL;')
- ri.cw.nl()
-
- ri.cw.block_start(line='do')
- ri.cw.p('len = mnl_socket_recvfrom(ys->sock, ys->rx_buf, MNL_SOCKET_BUFFER_SIZE);')
- ri.cw.p('if (len < 0)')
- ri.cw.p('goto free_list;')
- ri.cw.nl()
- ri.cw.p(f"err = {ri.nl.parse_cb_run('ynl_dump_trampoline', '&yds', False, indent=2)};")
+ ri.cw.p('err = ynl_exec_dump(ys, nlh, &yds);')
ri.cw.p('if (err < 0)')
ri.cw.p('goto free_list;')
- ri.cw.block_end(line='while (err > 0);')
ri.cw.nl()
ri.cw.p('return yds.first;')
@@ -1418,14 +1651,27 @@ def free_arg_name(direction):
return 'obj'
+def print_alloc_wrapper(ri, direction):
+ name = op_prefix(ri, direction)
+ ri.cw.write_func_prot(f'static inline struct {name} *', f"{name}_alloc", [f"void"])
+ ri.cw.block_start()
+ ri.cw.p(f'return calloc(1, sizeof(struct {name}));')
+ ri.cw.block_end()
+
+
def print_free_prototype(ri, direction, suffix=';'):
name = op_prefix(ri, direction)
+ struct_name = name
+ if ri.type_name_conflict:
+ struct_name += '_'
arg = free_arg_name(direction)
- ri.cw.write_func_prot('void', f"{name}_free", [f"struct {name} *{arg}"], suffix=suffix)
+ ri.cw.write_func_prot('void', f"{name}_free", [f"struct {struct_name} *{arg}"], suffix=suffix)
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':
suffix += '_dump'
@@ -1465,6 +1711,7 @@ def print_type_full(ri, struct):
def print_type_helpers(ri, direction, deref=False):
print_free_prototype(ri, direction)
+ ri.cw.nl()
if ri.ku_space == 'user' and direction == 'request':
for _, attr in ri.struct[direction].member_list():
@@ -1473,6 +1720,7 @@ def print_type_helpers(ri, direction, deref=False):
def print_req_type_helpers(ri):
+ print_alloc_wrapper(ri, "request")
print_type_helpers(ri, "request")
@@ -1496,6 +1744,12 @@ def print_req_type(ri):
print_type(ri, "request")
+def print_req_free(ri):
+ if 'request' not in ri.op[ri.op_mode]:
+ return
+ _free_type(ri, 'request', ri.struct['request'])
+
+
def print_rsp_type(ri):
if (ri.op_mode == 'do' or ri.op_mode == 'dump') and 'reply' in ri.op[ri.op_mode]:
direction = 'reply'
@@ -1513,6 +1767,7 @@ def print_wrapped_type(ri):
elif ri.op_mode == 'notify' or ri.op_mode == 'event':
ri.cw.p('__u16 family;')
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.block_end(line=';')
@@ -1564,7 +1819,7 @@ def print_dump_type_free(ri):
ri.cw.block_start()
ri.cw.p(f"{sub_type} *next = rsp;")
ri.cw.nl()
- ri.cw.block_start(line='while (next)')
+ ri.cw.block_start(line='while ((void *)next != YNL_LIST_END)')
_free_type_members_iter(ri, ri.struct['reply'])
ri.cw.p('rsp = next;')
ri.cw.p('next = rsp->next;')
@@ -1587,70 +1842,6 @@ def print_ntf_type_free(ri):
ri.cw.nl()
-def print_ntf_parse_prototype(family, cw, suffix=';'):
- cw.write_func_prot('struct ynl_ntf_base_type *', f"{family['name']}_ntf_parse",
- ['struct ynl_sock *ys'], suffix=suffix)
-
-
-def print_ntf_type_parse(family, cw, ku_mode):
- print_ntf_parse_prototype(family, cw, suffix='')
- cw.block_start()
- cw.write_func_lvar(['struct genlmsghdr *genlh;',
- 'struct nlmsghdr *nlh;',
- 'struct ynl_parse_arg yarg = { .ys = ys, };',
- 'struct ynl_ntf_base_type *rsp;',
- 'int len, err;',
- 'mnl_cb_t parse;'])
- cw.p('len = mnl_socket_recvfrom(ys->sock, ys->rx_buf, MNL_SOCKET_BUFFER_SIZE);')
- cw.p('if (len < (ssize_t)(sizeof(*nlh) + sizeof(*genlh)))')
- cw.p('return NULL;')
- cw.nl()
- cw.p('nlh = (struct nlmsghdr *)ys->rx_buf;')
- cw.p('genlh = mnl_nlmsg_get_payload(nlh);')
- cw.nl()
- cw.block_start(line='switch (genlh->cmd)')
- for ntf_op in sorted(family.all_notify.keys()):
- op = family.ops[ntf_op]
- ri = RenderInfo(cw, family, ku_mode, op, ntf_op, "notify")
- for ntf in op['notify']['cmds']:
- cw.p(f"case {ntf.enum_name}:")
- cw.p(f"rsp = calloc(1, sizeof({type_name(ri, 'notify')}));")
- cw.p(f"parse = {op_prefix(ri, 'reply', deref=True)}_parse;")
- cw.p(f"yarg.rsp_policy = &{ri.struct['reply'].render_name}_nest;")
- cw.p(f"rsp->free = (void *){op_prefix(ri, 'notify')}_free;")
- cw.p('break;')
- for op_name, op in family.ops.items():
- if 'event' not in op:
- continue
- ri = RenderInfo(cw, family, ku_mode, op, op_name, "event")
- cw.p(f"case {op.enum_name}:")
- cw.p(f"rsp = calloc(1, sizeof({type_name(ri, 'event')}));")
- cw.p(f"parse = {op_prefix(ri, 'reply', deref=True)}_parse;")
- cw.p(f"yarg.rsp_policy = &{ri.struct['reply'].render_name}_nest;")
- cw.p(f"rsp->free = (void *){op_prefix(ri, 'notify')}_free;")
- cw.p('break;')
- cw.p('default:')
- cw.p('ynl_error_unknown_notification(ys, genlh->cmd);')
- cw.p('return NULL;')
- cw.block_end()
- cw.nl()
- cw.p('yarg.data = rsp->data;')
- cw.nl()
- cw.p(f"err = {cw.nlib.parse_cb_run('parse', '&yarg', True)};")
- cw.p('if (err < 0)')
- cw.p('goto err_free;')
- cw.nl()
- cw.p('rsp->family = nlh->nlmsg_type;')
- cw.p('rsp->cmd = genlh->cmd;')
- cw.p('return rsp;')
- cw.nl()
- cw.p('err_free:')
- cw.p('free(rsp);')
- cw.p('return NULL;')
- cw.block_end()
- cw.nl()
-
-
def print_req_policy_fwd(cw, struct, ri=None, terminate=True):
if terminate and ri and kernel_can_gen_family_struct(struct.family):
return
@@ -2035,6 +2226,48 @@ def render_uapi(family, cw):
cw.p(f'#endif /* {hdr_prot} */')
+def _render_user_ntf_entry(ri, op):
+ ri.cw.block_start(line=f"[{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,")
+ ri.cw.p(f".free\t\t= (void *){op_prefix(ri, 'notify')}_free,")
+ ri.cw.block_end(line=',')
+
+
+def render_user_family(family, cw, prototype):
+ symbol = f'const struct ynl_family ynl_{family.c_name}_family'
+ if prototype:
+ cw.p(f'extern {symbol};')
+ return
+
+ if family.ntfs:
+ cw.block_start(line=f"static const struct ynl_ntf_info {family['name']}_ntf_info[] = ")
+ for ntf_op_name, ntf_op in family.ntfs.items():
+ if 'notify' in ntf_op:
+ op = family.ops[ntf_op['notify']]
+ ri = RenderInfo(cw, family, "user", op, "notify")
+ elif 'event' in ntf_op:
+ ri = RenderInfo(cw, family, "user", ntf_op, "event")
+ else:
+ raise Exception('Invalid notification ' + ntf_op_name)
+ _render_user_ntf_entry(ri, ntf_op)
+ for op_name, op in family.ops.items():
+ if 'event' not in op:
+ continue
+ ri = RenderInfo(cw, family, "user", op, "event")
+ _render_user_ntf_entry(ri, op)
+ cw.block_end(line=";")
+ cw.nl()
+
+ cw.block_start(f'{symbol} = ')
+ cw.p(f'.name\t\t= "{family.name}",')
+ 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.block_end(line=';')
+
+
def find_kernel_root(full_path):
sub_path = ''
while True:
@@ -2052,6 +2285,7 @@ def main():
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('--exclude-op', action='append', default=[])
parser.add_argument('-o', dest='out_file', type=str)
args = parser.parse_args()
@@ -2060,8 +2294,10 @@ def main():
if args.header is None:
parser.error("--header or --source is required")
+ exclude_ops = [re.compile(expr) for expr in args.exclude_op]
+
try:
- parsed = Family(args.spec)
+ parsed = Family(args.spec, exclude_ops)
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)')
@@ -2071,6 +2307,13 @@ def main():
os.sys.exit(1)
return
+ supported_models = ['unified']
+ if args.mode == 'user':
+ 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(), out_file)
_, spec_kernel = find_kernel_root(args.spec)
@@ -2081,6 +2324,11 @@ 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:
+ line = ''
+ line += ' --user-header '.join([''] + args.user_header)
+ line += ' --exclude-op '.join([''] + args.exclude_op)
+ cw.p(f'/* YNL-ARG{line} */')
cw.nl()
if args.mode == 'uapi':
@@ -2103,6 +2351,13 @@ def main():
cw.nl()
headers = ['uapi/' + parsed.uapi_header]
else:
+ cw.p('#include <stdlib.h>')
+ cw.p('#include <string.h>')
+ if args.header:
+ cw.p('#include <linux/types.h>')
+ else:
+ cw.p(f'#include "{parsed.name}-user.h"')
+ cw.p('#include "ynl.h"')
headers = [parsed.uapi_header]
for definition in parsed['definitions']:
if 'header' in definition:
@@ -2113,9 +2368,6 @@ def main():
if args.mode == "user":
if not args.header:
- cw.p("#include <stdlib.h>")
- cw.p("#include <stdio.h>")
- cw.p("#include <string.h>")
cw.p("#include <libmnl/libmnl.h>")
cw.p("#include <linux/genetlink.h>")
cw.nl()
@@ -2123,6 +2375,8 @@ def main():
cw.p(f'#include "{one}"')
else:
cw.p('struct ynl_sock;')
+ cw.nl()
+ render_user_family(parsed, cw, True)
cw.nl()
if args.mode == "kernel":
@@ -2146,7 +2400,7 @@ def main():
if parsed.kernel_policy in {'per-op', 'split'}:
for op_name, op in parsed.ops.items():
if 'do' in op and 'event' not in op:
- ri = RenderInfo(cw, parsed, args.mode, op, op_name, "do")
+ ri = RenderInfo(cw, parsed, args.mode, op, "do")
print_req_policy_fwd(cw, ri.struct['request'], ri=ri)
cw.nl()
@@ -2175,7 +2429,7 @@ def main():
for op_mode in ['do', 'dump']:
if op_mode in op and 'request' in op[op_mode]:
cw.p(f"/* {op.enum_name} - {op_mode} */")
- ri = RenderInfo(cw, parsed, args.mode, op, op_name, op_mode)
+ ri = RenderInfo(cw, parsed, args.mode, op, op_mode)
print_req_policy(cw, ri.struct['request'], ri=ri)
cw.nl()
@@ -2184,11 +2438,18 @@ def main():
print_kernel_family_struct_src(parsed, cw)
if args.mode == "user":
- has_ntf = False
if args.header:
+ cw.p('/* Enums */')
+ put_op_name_fwd(parsed, cw)
+
+ for name, const in parsed.consts.items():
+ if isinstance(const, EnumSet):
+ put_enum_to_str_fwd(parsed, cw, const)
+ cw.nl()
+
cw.p('/* Common nested types */')
- for attr_set, struct in sorted(parsed.pure_nested_structs.items()):
- ri = RenderInfo(cw, parsed, args.mode, "", "", "", attr_set)
+ for attr_set, struct in parsed.pure_nested_structs.items():
+ ri = RenderInfo(cw, parsed, args.mode, "", "", attr_set)
print_type_full(ri, struct)
for op_name, op in parsed.ops.items():
@@ -2196,7 +2457,7 @@ def main():
if 'do' in op and 'event' not in op:
cw.p(f"/* {op.enum_name} - do */")
- ri = RenderInfo(cw, parsed, args.mode, op, op_name, "do")
+ ri = RenderInfo(cw, parsed, args.mode, op, "do")
print_req_type(ri)
print_req_type_helpers(ri)
cw.nl()
@@ -2208,7 +2469,7 @@ def main():
if 'dump' in op:
cw.p(f"/* {op.enum_name} - dump */")
- ri = RenderInfo(cw, parsed, args.mode, op, op_name, 'dump')
+ ri = RenderInfo(cw, parsed, args.mode, op, 'dump')
if 'request' in op['dump']:
print_req_type(ri)
print_req_type_helpers(ri)
@@ -2218,39 +2479,41 @@ def main():
print_dump_prototype(ri)
cw.nl()
- if 'notify' in op:
+ if op.has_ntf:
cw.p(f"/* {op.enum_name} - notify */")
- ri = RenderInfo(cw, parsed, args.mode, op, op_name, 'notify')
- has_ntf = True
+ ri = RenderInfo(cw, parsed, args.mode, op, 'notify')
if not ri.type_consistent:
- raise Exception('Only notifications with consistent types supported')
+ raise Exception(f'Only notifications with consistent types supported ({op.name})')
print_wrapped_type(ri)
+ for op_name, op in parsed.ntfs.items():
if 'event' in op:
- ri = RenderInfo(cw, parsed, args.mode, op, op_name, 'event')
+ ri = RenderInfo(cw, parsed, args.mode, op, 'event')
cw.p(f"/* {op.enum_name} - event */")
print_rsp_type(ri)
cw.nl()
print_wrapped_type(ri)
-
- if has_ntf:
- cw.p('/* --------------- Common notification parsing --------------- */')
- print_ntf_parse_prototype(parsed, cw)
cw.nl()
else:
- cw.p('/* Policies */')
- for name, _ in parsed.attr_sets.items():
- struct = Struct(parsed, name)
- put_typol_fwd(cw, struct)
+ cw.p('/* Enums */')
+ put_op_name(parsed, cw)
+
+ for name, const in parsed.consts.items():
+ if isinstance(const, EnumSet):
+ put_enum_to_str(parsed, cw, const)
cw.nl()
- for name, _ in parsed.attr_sets.items():
+ cw.p('/* Policies */')
+ for name in parsed.pure_nested_structs:
+ struct = Struct(parsed, name)
+ put_typol(cw, struct)
+ for name in parsed.root_sets:
struct = Struct(parsed, name)
put_typol(cw, struct)
cw.p('/* Common nested types */')
- for attr_set, struct in sorted(parsed.pure_nested_structs.items()):
- ri = RenderInfo(cw, parsed, args.mode, "", "", "", attr_set)
+ for attr_set, struct in parsed.pure_nested_structs.items():
+ ri = RenderInfo(cw, parsed, args.mode, "", "", attr_set)
free_rsp_nested(ri, struct)
if struct.request:
@@ -2262,7 +2525,8 @@ def main():
cw.p(f"/* ============== {op.enum_name} ============== */")
if 'do' in op and 'event' not in op:
cw.p(f"/* {op.enum_name} - do */")
- ri = RenderInfo(cw, parsed, args.mode, op, op_name, "do")
+ ri = RenderInfo(cw, parsed, args.mode, op, "do")
+ print_req_free(ri)
print_rsp_free(ri)
parse_rsp_msg(ri)
print_req(ri)
@@ -2270,34 +2534,31 @@ def main():
if 'dump' in op:
cw.p(f"/* {op.enum_name} - dump */")
- ri = RenderInfo(cw, parsed, args.mode, op, op_name, "dump")
+ ri = RenderInfo(cw, parsed, args.mode, op, "dump")
if not ri.type_consistent:
parse_rsp_msg(ri, deref=True)
print_dump_type_free(ri)
print_dump(ri)
cw.nl()
- if 'notify' in op:
+ if op.has_ntf:
cw.p(f"/* {op.enum_name} - notify */")
- ri = RenderInfo(cw, parsed, args.mode, op, op_name, 'notify')
- has_ntf = True
+ ri = RenderInfo(cw, parsed, args.mode, op, 'notify')
if not ri.type_consistent:
- raise Exception('Only notifications with consistent types supported')
+ raise Exception(f'Only notifications with consistent types supported ({op.name})')
print_ntf_type_free(ri)
+ for op_name, op in parsed.ntfs.items():
if 'event' in op:
cw.p(f"/* {op.enum_name} - event */")
- has_ntf = True
- ri = RenderInfo(cw, parsed, args.mode, op, op_name, "do")
+ ri = RenderInfo(cw, parsed, args.mode, op, "do")
parse_rsp_msg(ri)
- ri = RenderInfo(cw, parsed, args.mode, op, op_name, "event")
+ ri = RenderInfo(cw, parsed, args.mode, op, "event")
print_ntf_type_free(ri)
-
- if has_ntf:
- cw.p('/* --------------- Common notification parsing --------------- */')
- print_ntf_type_parse(parsed, cw, args.mode)
+ cw.nl()
+ render_user_family(parsed, cw, False)
if args.header:
cw.p(f'#endif /* {hdr_prot} */')
diff --git a/tools/net/ynl/ynl-regen.sh b/tools/net/ynl/ynl-regen.sh
index 74f5de1c2399..8d4ca6a50582 100755
--- a/tools/net/ynl/ynl-regen.sh
+++ b/tools/net/ynl/ynl-regen.sh
@@ -14,11 +14,12 @@ done
KDIR=$(dirname $(dirname $(dirname $(dirname $(realpath $0)))))
-files=$(git grep --files-with-matches '^/\* YNL-GEN \(kernel\|uapi\)')
+files=$(git grep --files-with-matches '^/\* YNL-GEN \(kernel\|uapi\|user\)')
for f in $files; do
# params: 0 1 2 3
# $YAML YNL-GEN kernel $mode
params=( $(git grep -B1 -h '/\* YNL-GEN' $f | sed 's@/\*\(.*\)\*/@\1@') )
+ args=$(sed -n 's@/\* YNL-ARG \(.*\) \*/@\1@p' $f)
if [ $f -nt ${params[0]} -a -z "$force" ]; then
echo -e "\tSKIP $f"
@@ -26,5 +27,6 @@ for f in $files; do
fi
echo -e "\tGEN ${params[2]}\t$f"
- $TOOL --mode ${params[2]} --${params[3]} --spec $KDIR/${params[0]} -o $f
+ $TOOL --mode ${params[2]} --${params[3]} --spec $KDIR/${params[0]} \
+ $args -o $f
done
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
index 70268442f7ee..a794d9eca93d 100644
--- a/tools/perf/Makefile.config
+++ b/tools/perf/Makefile.config
@@ -927,6 +927,7 @@ ifndef NO_DEMANGLE
EXTLIBS += -lstdc++
CFLAGS += -DHAVE_CXA_DEMANGLE_SUPPORT
CXXFLAGS += -DHAVE_CXA_DEMANGLE_SUPPORT
+ $(call detected,CONFIG_CXX_DEMANGLE)
endif
ifdef BUILD_NONDISTRO
ifeq ($(filter -liberty,$(EXTLIBS)),)
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 1593c5dcaa9e..f48794816d82 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -181,7 +181,6 @@ HOSTCC ?= gcc
HOSTLD ?= ld
HOSTAR ?= ar
CLANG ?= clang
-LLVM_STRIP ?= llvm-strip
PKG_CONFIG = $(CROSS_COMPILE)pkg-config
@@ -1083,7 +1082,7 @@ $(BPFTOOL): | $(SKEL_TMP_OUT)
$(SKEL_TMP_OUT)/%.bpf.o: util/bpf_skel/%.bpf.c $(LIBBPF) | $(SKEL_TMP_OUT)
$(QUIET_CLANG)$(CLANG) -g -O2 -target bpf -Wall -Werror $(BPF_INCLUDE) $(TOOLS_UAPI_INCLUDE) \
- -c $(filter util/bpf_skel/%.bpf.c,$^) -o $@ && $(LLVM_STRIP) -g $@
+ -c $(filter util/bpf_skel/%.bpf.c,$^) -o $@
$(SKEL_OUT)/%.skel.h: $(SKEL_TMP_OUT)/%.bpf.o | $(BPFTOOL)
$(QUIET_GENSKEL)$(BPFTOOL) gen skeleton $< > $@
diff --git a/tools/perf/arch/arm/util/pmu.c b/tools/perf/arch/arm/util/pmu.c
index 860a8b42b4b5..a9623b128ece 100644
--- a/tools/perf/arch/arm/util/pmu.c
+++ b/tools/perf/arch/arm/util/pmu.c
@@ -12,7 +12,7 @@
#include "arm-spe.h"
#include "hisi-ptt.h"
#include "../../../util/pmu.h"
-#include "../cs-etm.h"
+#include "../../../util/cs-etm.h"
struct perf_event_attr
*perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused)
diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c
index 810e3376c7d6..f9906f52e4fa 100644
--- a/tools/perf/builtin-ftrace.c
+++ b/tools/perf/builtin-ftrace.c
@@ -1175,7 +1175,7 @@ int cmd_ftrace(int argc, const char **argv)
OPT_BOOLEAN('b', "use-bpf", &ftrace.target.use_bpf,
"Use BPF to measure function latency"),
#endif
- OPT_BOOLEAN('n', "--use-nsec", &ftrace.use_nsec,
+ OPT_BOOLEAN('n', "use-nsec", &ftrace.use_nsec,
"Use nano-second histogram"),
OPT_PARENT(common_options),
};
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index bd18fe5f2719..f9df1df1eec0 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -214,7 +214,7 @@ perf-$(CONFIG_ZSTD) += zstd.o
perf-$(CONFIG_LIBCAP) += cap.o
-perf-y += demangle-cxx.o
+perf-$(CONFIG_CXX_DEMANGLE) += demangle-cxx.o
perf-y += demangle-ocaml.o
perf-y += demangle-java.o
perf-y += demangle-rust.o
diff --git a/tools/perf/util/bpf_skel/sample_filter.bpf.c b/tools/perf/util/bpf_skel/sample_filter.bpf.c
index cffe493af1ed..fb94f5280626 100644
--- a/tools/perf/util/bpf_skel/sample_filter.bpf.c
+++ b/tools/perf/util/bpf_skel/sample_filter.bpf.c
@@ -25,7 +25,7 @@ struct perf_sample_data___new {
} __attribute__((preserve_access_index));
/* new kernel perf_mem_data_src definition */
-union perf_mem_data_src__new {
+union perf_mem_data_src___new {
__u64 val;
struct {
__u64 mem_op:5, /* type of opcode */
@@ -108,7 +108,7 @@ static inline __u64 perf_get_sample(struct bpf_perf_event_data_kern *kctx,
if (entry->part == 7)
return kctx->data->data_src.mem_blk;
if (entry->part == 8) {
- union perf_mem_data_src__new *data = (void *)&kctx->data->data_src;
+ union perf_mem_data_src___new *data = (void *)&kctx->data->data_src;
if (bpf_core_field_exists(data->mem_hops))
return data->mem_hops;
diff --git a/tools/perf/util/cs-etm.h b/tools/perf/util/cs-etm.h
index 70cac0375b34..ecca40787ac9 100644
--- a/tools/perf/util/cs-etm.h
+++ b/tools/perf/util/cs-etm.h
@@ -227,6 +227,19 @@ struct cs_etm_packet_queue {
#define INFO_HEADER_SIZE (sizeof(((struct perf_record_auxtrace_info *)0)->type) + \
sizeof(((struct perf_record_auxtrace_info *)0)->reserved__))
+/* CoreSight trace ID is currently the bottom 7 bits of the value */
+#define CORESIGHT_TRACE_ID_VAL_MASK GENMASK(6, 0)
+
+/*
+ * perf record will set the legacy meta data values as unused initially.
+ * This allows perf report to manage the decoders created when dynamic
+ * allocation in operation.
+ */
+#define CORESIGHT_TRACE_ID_UNUSED_FLAG BIT(31)
+
+/* Value to set for unused trace ID values */
+#define CORESIGHT_TRACE_ID_UNUSED_VAL 0x7F
+
int cs_etm__process_auxtrace_info(union perf_event *event,
struct perf_session *session);
struct perf_event_attr *cs_etm_get_default_config(struct perf_pmu *pmu);
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 2f5910b31fa9..c2dbb5647e75 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -282,6 +282,7 @@ void evsel__init(struct evsel *evsel,
evsel->bpf_fd = -1;
INIT_LIST_HEAD(&evsel->config_terms);
INIT_LIST_HEAD(&evsel->bpf_counter_list);
+ INIT_LIST_HEAD(&evsel->bpf_filters);
perf_evsel__object.init(evsel);
evsel->sample_size = __evsel__sample_size(attr->sample_type);
evsel__calc_id_pos(evsel);
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index df8928745fc6..0f54f28a69c2 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -151,10 +151,8 @@ struct evsel {
*/
struct bpf_counter_ops *bpf_counter_ops;
- union {
- struct list_head bpf_counter_list; /* for perf-stat -b */
- struct list_head bpf_filters; /* for perf-record --filter */
- };
+ struct list_head bpf_counter_list; /* for perf-stat -b */
+ struct list_head bpf_filters; /* for perf-record --filter */
/* for perf-stat --use-bpf */
int bperf_leader_prog_fd;
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index b2ed9cc52265..63882a4db5c7 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -31,6 +31,13 @@
#include <bfd.h>
#endif
+#if defined(HAVE_LIBBFD_SUPPORT) || defined(HAVE_CPLUS_DEMANGLE_SUPPORT)
+#ifndef DMGL_PARAMS
+#define DMGL_PARAMS (1 << 0) /* Include function args */
+#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
+#endif
+#endif
+
#ifndef EM_AARCH64
#define EM_AARCH64 183 /* ARM 64 bit */
#endif
@@ -271,6 +278,26 @@ static bool want_demangle(bool is_kernel_sym)
return is_kernel_sym ? symbol_conf.demangle_kernel : symbol_conf.demangle;
}
+/*
+ * Demangle C++ function signature, typically replaced by demangle-cxx.cpp
+ * version.
+ */
+__weak char *cxx_demangle_sym(const char *str __maybe_unused, bool params __maybe_unused,
+ bool modifiers __maybe_unused)
+{
+#ifdef HAVE_LIBBFD_SUPPORT
+ int flags = (params ? DMGL_PARAMS : 0) | (modifiers ? DMGL_ANSI : 0);
+
+ return bfd_demangle(NULL, str, flags);
+#elif defined(HAVE_CPLUS_DEMANGLE_SUPPORT)
+ int flags = (params ? DMGL_PARAMS : 0) | (modifiers ? DMGL_ANSI : 0);
+
+ return cplus_demangle(str, flags);
+#else
+ return NULL;
+#endif
+}
+
static char *demangle_sym(struct dso *dso, int kmodule, const char *elf_name)
{
char *demangled = NULL;
diff --git a/tools/testing/cxl/Kbuild b/tools/testing/cxl/Kbuild
index fba7bec96acd..6f9347ade82c 100644
--- a/tools/testing/cxl/Kbuild
+++ b/tools/testing/cxl/Kbuild
@@ -6,6 +6,7 @@ ldflags-y += --wrap=acpi_pci_find_root
ldflags-y += --wrap=nvdimm_bus_register
ldflags-y += --wrap=devm_cxl_port_enumerate_dports
ldflags-y += --wrap=devm_cxl_setup_hdm
+ldflags-y += --wrap=devm_cxl_enable_hdm
ldflags-y += --wrap=devm_cxl_add_passthrough_decoder
ldflags-y += --wrap=devm_cxl_enumerate_decoders
ldflags-y += --wrap=cxl_await_media_ready
diff --git a/tools/testing/cxl/test/mem.c b/tools/testing/cxl/test/mem.c
index ba572d03c687..34b48027b3de 100644
--- a/tools/testing/cxl/test/mem.c
+++ b/tools/testing/cxl/test/mem.c
@@ -1256,6 +1256,7 @@ static int cxl_mock_mem_probe(struct platform_device *pdev)
if (rc)
return rc;
+ cxlds->media_ready = true;
rc = cxl_dev_state_identify(cxlds);
if (rc)
return rc;
diff --git a/tools/testing/cxl/test/mock.c b/tools/testing/cxl/test/mock.c
index de3933a776fd..284416527644 100644
--- a/tools/testing/cxl/test/mock.c
+++ b/tools/testing/cxl/test/mock.c
@@ -149,6 +149,21 @@ struct cxl_hdm *__wrap_devm_cxl_setup_hdm(struct cxl_port *port,
}
EXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_setup_hdm, CXL);
+int __wrap_devm_cxl_enable_hdm(struct cxl_port *port, struct cxl_hdm *cxlhdm)
+{
+ int index, rc;
+ struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
+
+ if (ops && ops->is_mock_port(port->uport))
+ rc = 0;
+ else
+ rc = devm_cxl_enable_hdm(port, cxlhdm);
+ put_cxl_mock_ops(index);
+
+ return rc;
+}
+EXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_enable_hdm, CXL);
+
int __wrap_devm_cxl_add_passthrough_decoder(struct cxl_port *port)
{
int rc, index;
diff --git a/tools/testing/radix-tree/Makefile b/tools/testing/radix-tree/Makefile
index caf32a9b9608..7527f738b4a1 100644
--- a/tools/testing/radix-tree/Makefile
+++ b/tools/testing/radix-tree/Makefile
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
-CFLAGS += -I. -I../../include -g -Og -Wall -D_LGPL_SOURCE -fsanitize=address \
- -fsanitize=undefined
+CFLAGS += -I. -I../../include -I../../../lib -g -Og -Wall \
+ -D_LGPL_SOURCE -fsanitize=address -fsanitize=undefined
LDFLAGS += -fsanitize=address -fsanitize=undefined
LDLIBS+= -lpthread -lurcu
TARGETS = main idr-test multiorder xarray maple
@@ -49,6 +49,7 @@ $(OFILES): Makefile *.h */*.h generated/map-shift.h generated/bit-length.h \
../../../include/linux/xarray.h \
../../../include/linux/maple_tree.h \
../../../include/linux/radix-tree.h \
+ ../../../lib/radix-tree.h \
../../../include/linux/idr.h
radix-tree.c: ../../../lib/radix-tree.c
diff --git a/tools/testing/selftests/alsa/pcm-test.c b/tools/testing/selftests/alsa/pcm-test.c
index 3e390fe67eb9..b7eef32addb4 100644
--- a/tools/testing/selftests/alsa/pcm-test.c
+++ b/tools/testing/selftests/alsa/pcm-test.c
@@ -381,7 +381,7 @@ __format:
goto __close;
}
if (rrate != rate) {
- snprintf(msg, sizeof(msg), "rate mismatch %ld != %ld", rate, rrate);
+ snprintf(msg, sizeof(msg), "rate mismatch %ld != %d", rate, rrate);
goto __close;
}
rperiod_size = period_size;
@@ -447,24 +447,24 @@ __format:
frames = snd_pcm_writei(handle, samples, rate);
if (frames < 0) {
snprintf(msg, sizeof(msg),
- "Write failed: expected %d, wrote %li", rate, frames);
+ "Write failed: expected %ld, wrote %li", rate, frames);
goto __close;
}
if (frames < rate) {
snprintf(msg, sizeof(msg),
- "expected %d, wrote %li", rate, frames);
+ "expected %ld, wrote %li", rate, frames);
goto __close;
}
} else {
frames = snd_pcm_readi(handle, samples, rate);
if (frames < 0) {
snprintf(msg, sizeof(msg),
- "expected %d, wrote %li", rate, frames);
+ "expected %ld, wrote %li", rate, frames);
goto __close;
}
if (frames < rate) {
snprintf(msg, sizeof(msg),
- "expected %d, wrote %li", rate, frames);
+ "expected %ld, wrote %li", rate, frames);
goto __close;
}
}
diff --git a/tools/testing/selftests/bpf/prog_tests/inner_array_lookup.c b/tools/testing/selftests/bpf/prog_tests/inner_array_lookup.c
new file mode 100644
index 000000000000..9ab4cd195108
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/inner_array_lookup.c
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <test_progs.h>
+
+#include "inner_array_lookup.skel.h"
+
+void test_inner_array_lookup(void)
+{
+ int map1_fd, err;
+ int key = 3;
+ int val = 1;
+ struct inner_array_lookup *skel;
+
+ skel = inner_array_lookup__open_and_load();
+ if (!ASSERT_OK_PTR(skel, "open_load_skeleton"))
+ return;
+
+ err = inner_array_lookup__attach(skel);
+ if (!ASSERT_OK(err, "skeleton_attach"))
+ goto cleanup;
+
+ map1_fd = bpf_map__fd(skel->maps.inner_map1);
+ bpf_map_update_elem(map1_fd, &key, &val, 0);
+
+ /* Probe should have set the element at index 3 to 2 */
+ bpf_map_lookup_elem(map1_fd, &key, &val);
+ ASSERT_EQ(val, 2, "value_is_2");
+
+cleanup:
+ inner_array_lookup__destroy(skel);
+}
diff --git a/tools/testing/selftests/bpf/prog_tests/sockopt_sk.c b/tools/testing/selftests/bpf/prog_tests/sockopt_sk.c
index 4512dd808c33..05d0e07da394 100644
--- a/tools/testing/selftests/bpf/prog_tests/sockopt_sk.c
+++ b/tools/testing/selftests/bpf/prog_tests/sockopt_sk.c
@@ -209,7 +209,7 @@ static int getsetsockopt(void)
err, errno);
goto err;
}
- ASSERT_EQ(optlen, 4, "Unexpected NETLINK_LIST_MEMBERSHIPS value");
+ ASSERT_EQ(optlen, 8, "Unexpected NETLINK_LIST_MEMBERSHIPS value");
free(big_buf);
close(fd);
diff --git a/tools/testing/selftests/bpf/prog_tests/subprogs_extable.c b/tools/testing/selftests/bpf/prog_tests/subprogs_extable.c
new file mode 100644
index 000000000000..3afd9f775f68
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/subprogs_extable.c
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <test_progs.h>
+#include "test_subprogs_extable.skel.h"
+
+void test_subprogs_extable(void)
+{
+ const int read_sz = 456;
+ struct test_subprogs_extable *skel;
+ int err;
+
+ skel = test_subprogs_extable__open_and_load();
+ if (!ASSERT_OK_PTR(skel, "skel_open_and_load"))
+ return;
+
+ err = test_subprogs_extable__attach(skel);
+ if (!ASSERT_OK(err, "skel_attach"))
+ goto cleanup;
+
+ /* trigger tracepoint */
+ ASSERT_OK(trigger_module_test_read(read_sz), "trigger_read");
+
+ ASSERT_NEQ(skel->bss->triggered, 0, "verify at least one program ran");
+
+ test_subprogs_extable__detach(skel);
+
+cleanup:
+ test_subprogs_extable__destroy(skel);
+}
diff --git a/tools/testing/selftests/bpf/progs/inner_array_lookup.c b/tools/testing/selftests/bpf/progs/inner_array_lookup.c
new file mode 100644
index 000000000000..c2c8f2fa451d
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/inner_array_lookup.c
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/bpf.h>
+#include <bpf/bpf_helpers.h>
+
+struct inner_map {
+ __uint(type, BPF_MAP_TYPE_ARRAY);
+ __uint(max_entries, 5);
+ __type(key, int);
+ __type(value, int);
+} inner_map1 SEC(".maps");
+
+struct outer_map {
+ __uint(type, BPF_MAP_TYPE_HASH_OF_MAPS);
+ __uint(max_entries, 3);
+ __type(key, int);
+ __array(values, struct inner_map);
+} outer_map1 SEC(".maps") = {
+ .values = {
+ [2] = &inner_map1,
+ },
+};
+
+SEC("raw_tp/sys_enter")
+int handle__sys_enter(void *ctx)
+{
+ int outer_key = 2, inner_key = 3;
+ int *val;
+ void *map;
+
+ map = bpf_map_lookup_elem(&outer_map1, &outer_key);
+ if (!map)
+ return 1;
+
+ val = bpf_map_lookup_elem(map, &inner_key);
+ if (!val)
+ return 1;
+
+ if (*val == 1)
+ *val = 2;
+
+ return 0;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/progs/test_subprogs_extable.c b/tools/testing/selftests/bpf/progs/test_subprogs_extable.c
new file mode 100644
index 000000000000..e2a21fbd4e44
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/test_subprogs_extable.c
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include "vmlinux.h"
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_tracing.h>
+
+struct {
+ __uint(type, BPF_MAP_TYPE_ARRAY);
+ __uint(max_entries, 8);
+ __type(key, __u32);
+ __type(value, __u64);
+} test_array SEC(".maps");
+
+unsigned int triggered;
+
+static __u64 test_cb(struct bpf_map *map, __u32 *key, __u64 *val, void *data)
+{
+ return 1;
+}
+
+SEC("fexit/bpf_testmod_return_ptr")
+int BPF_PROG(handle_fexit_ret_subprogs, int arg, struct file *ret)
+{
+ *(volatile long *)ret;
+ *(volatile int *)&ret->f_mode;
+ bpf_for_each_map_elem(&test_array, test_cb, NULL, 0);
+ triggered++;
+ return 0;
+}
+
+SEC("fexit/bpf_testmod_return_ptr")
+int BPF_PROG(handle_fexit_ret_subprogs2, int arg, struct file *ret)
+{
+ *(volatile long *)ret;
+ *(volatile int *)&ret->f_mode;
+ bpf_for_each_map_elem(&test_array, test_cb, NULL, 0);
+ triggered++;
+ return 0;
+}
+
+SEC("fexit/bpf_testmod_return_ptr")
+int BPF_PROG(handle_fexit_ret_subprogs3, int arg, struct file *ret)
+{
+ *(volatile long *)ret;
+ *(volatile int *)&ret->f_mode;
+ bpf_for_each_map_elem(&test_array, test_cb, NULL, 0);
+ triggered++;
+ return 0;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c
index 136e5530b72c..6115520154e3 100644
--- a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c
+++ b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c
@@ -371,4 +371,83 @@ __naked void and_then_at_fp_8(void)
" ::: __clobber_all);
}
+SEC("xdp")
+__description("32-bit spill of 64-bit reg should clear ID")
+__failure __msg("math between ctx pointer and 4294967295 is not allowed")
+__naked void spill_32bit_of_64bit_fail(void)
+{
+ asm volatile (" \
+ r6 = r1; \
+ /* Roll one bit to force the verifier to track both branches. */\
+ call %[bpf_get_prandom_u32]; \
+ r0 &= 0x8; \
+ /* Put a large number into r1. */ \
+ r1 = 0xffffffff; \
+ r1 <<= 32; \
+ r1 += r0; \
+ /* Assign an ID to r1. */ \
+ r2 = r1; \
+ /* 32-bit spill r1 to stack - should clear the ID! */\
+ *(u32*)(r10 - 8) = r1; \
+ /* 32-bit fill r2 from stack. */ \
+ r2 = *(u32*)(r10 - 8); \
+ /* Compare r2 with another register to trigger find_equal_scalars.\
+ * Having one random bit is important here, otherwise the verifier cuts\
+ * the corners. If the ID was mistakenly preserved on spill, this would\
+ * cause the verifier to think that r1 is also equal to zero in one of\
+ * the branches, and equal to eight on the other branch.\
+ */ \
+ r3 = 0; \
+ if r2 != r3 goto l0_%=; \
+l0_%=: r1 >>= 32; \
+ /* At this point, if the verifier thinks that r1 is 0, an out-of-bounds\
+ * read will happen, because it actually contains 0xffffffff.\
+ */ \
+ r6 += r1; \
+ r0 = *(u32*)(r6 + 0); \
+ exit; \
+" :
+ : __imm(bpf_get_prandom_u32)
+ : __clobber_all);
+}
+
+SEC("xdp")
+__description("16-bit spill of 32-bit reg should clear ID")
+__failure __msg("dereference of modified ctx ptr R6 off=65535 disallowed")
+__naked void spill_16bit_of_32bit_fail(void)
+{
+ asm volatile (" \
+ r6 = r1; \
+ /* Roll one bit to force the verifier to track both branches. */\
+ call %[bpf_get_prandom_u32]; \
+ r0 &= 0x8; \
+ /* Put a large number into r1. */ \
+ w1 = 0xffff0000; \
+ r1 += r0; \
+ /* Assign an ID to r1. */ \
+ r2 = r1; \
+ /* 16-bit spill r1 to stack - should clear the ID! */\
+ *(u16*)(r10 - 8) = r1; \
+ /* 16-bit fill r2 from stack. */ \
+ r2 = *(u16*)(r10 - 8); \
+ /* Compare r2 with another register to trigger find_equal_scalars.\
+ * Having one random bit is important here, otherwise the verifier cuts\
+ * the corners. If the ID was mistakenly preserved on spill, this would\
+ * cause the verifier to think that r1 is also equal to zero in one of\
+ * the branches, and equal to eight on the other branch.\
+ */ \
+ r3 = 0; \
+ if r2 != r3 goto l0_%=; \
+l0_%=: r1 >>= 16; \
+ /* At this point, if the verifier thinks that r1 is 0, an out-of-bounds\
+ * read will happen, because it actually contains 0xffff.\
+ */ \
+ r6 += r1; \
+ r0 = *(u32*)(r6 + 0); \
+ exit; \
+" :
+ : __imm(bpf_get_prandom_u32)
+ : __clobber_all);
+}
+
char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/drivers/net/mlxsw/egress_vid_classification.sh b/tools/testing/selftests/drivers/net/mlxsw/egress_vid_classification.sh
index 0cf9e47e3209..a5c2aec52898 100755
--- a/tools/testing/selftests/drivers/net/mlxsw/egress_vid_classification.sh
+++ b/tools/testing/selftests/drivers/net/mlxsw/egress_vid_classification.sh
@@ -16,10 +16,9 @@
# +----------------|--+ +--|-----------------+
# | |
# +----------------|-------------------------|-----------------+
-# | SW | | |
+# | SW $swp1 + + $swp2 |
+# | | | |
# | +--------------|-------------------------|---------------+ |
-# | | $swp1 + + $swp2 | |
-# | | | | | |
# | | $swp1.10 + + $swp2.10 | |
# | | | |
# | | br0 | |
diff --git a/tools/testing/selftests/drivers/net/mlxsw/extack.sh b/tools/testing/selftests/drivers/net/mlxsw/extack.sh
index 7a0a99c1d22f..6fd422d38fe8 100755
--- a/tools/testing/selftests/drivers/net/mlxsw/extack.sh
+++ b/tools/testing/selftests/drivers/net/mlxsw/extack.sh
@@ -35,7 +35,9 @@ netdev_pre_up_test()
{
RET=0
- ip link add name br1 up type bridge vlan_filtering 0 mcast_snooping 0
+ ip link add name br1 type bridge vlan_filtering 0 mcast_snooping 0
+ ip link set dev br1 addrgenmode none
+ ip link set dev br1 up
ip link add name vx1 up type vxlan id 1000 \
local 192.0.2.17 remote 192.0.2.18 \
dstport 4789 nolearning noudpcsum tos inherit ttl 100
@@ -46,7 +48,9 @@ netdev_pre_up_test()
ip link set dev $swp1 master br1
check_err $?
- ip link add name br2 up type bridge vlan_filtering 0 mcast_snooping 0
+ ip link add name br2 type bridge vlan_filtering 0 mcast_snooping 0
+ ip link set dev br2 addrgenmode none
+ ip link set dev br2 up
ip link add name vx2 up type vxlan id 2000 \
local 192.0.2.17 remote 192.0.2.18 \
dstport 4789 nolearning noudpcsum tos inherit ttl 100
@@ -81,7 +85,9 @@ vxlan_vlan_add_test()
{
RET=0
- ip link add name br1 up type bridge vlan_filtering 1 mcast_snooping 0
+ ip link add name br1 type bridge vlan_filtering 1 mcast_snooping 0
+ ip link set dev br1 addrgenmode none
+ ip link set dev br1 up
# Unsupported configuration: mlxsw demands VXLAN with "noudpcsum".
ip link add name vx1 up type vxlan id 1000 \
@@ -117,7 +123,9 @@ vxlan_bridge_create_test()
dstport 4789 tos inherit ttl 100
# Test with VLAN-aware bridge.
- ip link add name br1 up type bridge vlan_filtering 1 mcast_snooping 0
+ ip link add name br1 type bridge vlan_filtering 1 mcast_snooping 0
+ ip link set dev br1 addrgenmode none
+ ip link set dev br1 up
ip link set dev vx1 master br1
@@ -142,8 +150,12 @@ bridge_create_test()
{
RET=0
- ip link add name br1 up type bridge vlan_filtering 1
- ip link add name br2 up type bridge vlan_filtering 1
+ ip link add name br1 type bridge vlan_filtering 1
+ ip link set dev br1 addrgenmode none
+ ip link set dev br1 up
+ ip link add name br2 type bridge vlan_filtering 1
+ ip link set dev br2 addrgenmode none
+ ip link set dev br2 up
ip link set dev $swp1 master br1
check_err $?
diff --git a/tools/testing/selftests/drivers/net/mlxsw/ingress_rif_conf_1d.sh b/tools/testing/selftests/drivers/net/mlxsw/ingress_rif_conf_1d.sh
index df2b09966886..7d7f862c809c 100755
--- a/tools/testing/selftests/drivers/net/mlxsw/ingress_rif_conf_1d.sh
+++ b/tools/testing/selftests/drivers/net/mlxsw/ingress_rif_conf_1d.sh
@@ -15,10 +15,9 @@
# +----------------|--+ +--|-----------------+
# | |
# +----------------|-------------------------|-----------------+
-# | SW | | |
+# | SW $swp1 + + $swp2 |
+# | | | |
# | +--------------|-------------------------|---------------+ |
-# | | $swp1 + + $swp2 | |
-# | | | | | |
# | | $swp1.10 + + $swp2.10 | |
# | | | |
# | | br0 | |
diff --git a/tools/testing/selftests/drivers/net/mlxsw/mirror_gre_scale.sh b/tools/testing/selftests/drivers/net/mlxsw/mirror_gre_scale.sh
index e00435753008..e5589e2fca85 100644
--- a/tools/testing/selftests/drivers/net/mlxsw/mirror_gre_scale.sh
+++ b/tools/testing/selftests/drivers/net/mlxsw/mirror_gre_scale.sh
@@ -165,6 +165,7 @@ mirror_gre_setup_prepare()
simple_if_init $h3
ip link add name br1 type bridge vlan_filtering 1
+ ip link set dev br1 addrgenmode none
ip link set dev br1 up
ip link set dev $swp1 master br1
diff --git a/tools/testing/selftests/drivers/net/mlxsw/one_armed_router.sh b/tools/testing/selftests/drivers/net/mlxsw/one_armed_router.sh
index f02d83e94576..fca0e1e642c6 100755
--- a/tools/testing/selftests/drivers/net/mlxsw/one_armed_router.sh
+++ b/tools/testing/selftests/drivers/net/mlxsw/one_armed_router.sh
@@ -83,7 +83,8 @@ h2_destroy()
switch_create()
{
- ip link add name br0 type bridge mcast_snooping 0
+ ip link add name br0 address $(mac_get $swp1) \
+ type bridge mcast_snooping 0
ip link set dev br0 up
ip link set dev $swp1 master br0
diff --git a/tools/testing/selftests/drivers/net/mlxsw/q_in_q_veto.sh b/tools/testing/selftests/drivers/net/mlxsw/q_in_q_veto.sh
index 7edaed8eb86a..00d55b0e98c1 100755
--- a/tools/testing/selftests/drivers/net/mlxsw/q_in_q_veto.sh
+++ b/tools/testing/selftests/drivers/net/mlxsw/q_in_q_veto.sh
@@ -48,6 +48,7 @@ create_vlan_upper_on_top_of_bridge()
ip link add dev br0 type bridge vlan_filtering 1 \
vlan_protocol $bridge_proto vlan_default_pvid 0 mcast_snooping 0
+ ip link set dev br0 addrgenmode none
ip link set dev br0 up
ip link set dev $swp1 master br0
@@ -88,6 +89,7 @@ create_8021ad_vlan_upper_on_top_bridge_port()
ip link add dev br0 type bridge vlan_filtering 1 \
vlan_default_pvid 0 mcast_snooping 0
+ ip link set dev br0 addrgenmode none
ip link set dev $swp1 master br0
ip link set dev br0 up
@@ -155,6 +157,7 @@ create_vlan_upper_on_top_front_panel_enslaved_to_8021ad_bridge()
ip link add dev br0 type bridge vlan_filtering 1 \
vlan_protocol 802.1ad vlan_default_pvid 0 mcast_snooping 0
+ ip link set dev br0 addrgenmode none
ip link set dev br0 up
ip link set dev $swp1 master br0
@@ -177,6 +180,7 @@ create_vlan_upper_on_top_lag_enslaved_to_8021ad_bridge()
ip link add dev br0 type bridge vlan_filtering 1 \
vlan_protocol 802.1ad vlan_default_pvid 0 mcast_snooping 0
+ ip link set dev br0 addrgenmode none
ip link set dev br0 up
ip link add name bond1 type bond mode 802.3ad
@@ -203,6 +207,7 @@ enslave_front_panel_with_vlan_upper_to_8021ad_bridge()
ip link add dev br0 type bridge vlan_filtering 1 \
vlan_protocol 802.1ad vlan_default_pvid 0 mcast_snooping 0
+ ip link set dev br0 addrgenmode none
ip link set dev br0 up
ip link add name $swp1.100 link $swp1 type vlan id 100
@@ -225,6 +230,7 @@ enslave_lag_with_vlan_upper_to_8021ad_bridge()
ip link add dev br0 type bridge vlan_filtering 1 \
vlan_protocol 802.1ad vlan_default_pvid 0 mcast_snooping 0
+ ip link set dev br0 addrgenmode none
ip link set dev br0 up
ip link add name bond1 type bond mode 802.3ad
@@ -252,6 +258,7 @@ add_ip_address_to_8021ad_bridge()
ip link add dev br0 type bridge vlan_filtering 1 \
vlan_protocol 802.1ad vlan_default_pvid 0 mcast_snooping 0
+ ip link set dev br0 addrgenmode none
ip link set dev br0 up
ip link set dev $swp1 master br0
@@ -273,6 +280,7 @@ switch_bridge_protocol_from_8021q_to_8021ad()
ip link add dev br0 type bridge vlan_filtering 1 \
vlan_protocol 802.1ad vlan_default_pvid 0 mcast_snooping 0
+ ip link set dev br0 addrgenmode none
ip link set dev br0 up
ip link set dev $swp1 master br0
diff --git a/tools/testing/selftests/drivers/net/mlxsw/qos_dscp_bridge.sh b/tools/testing/selftests/drivers/net/mlxsw/qos_dscp_bridge.sh
index 87c41f5727c9..914c63d6318a 100755
--- a/tools/testing/selftests/drivers/net/mlxsw/qos_dscp_bridge.sh
+++ b/tools/testing/selftests/drivers/net/mlxsw/qos_dscp_bridge.sh
@@ -65,6 +65,7 @@ h2_destroy()
switch_create()
{
ip link add name br1 type bridge vlan_filtering 1
+ ip link set dev br1 addrgenmode none
ip link set dev br1 up
ip link set dev $swp1 master br1
ip link set dev $swp1 up
diff --git a/tools/testing/selftests/drivers/net/mlxsw/qos_ets_strict.sh b/tools/testing/selftests/drivers/net/mlxsw/qos_ets_strict.sh
index 690d8daa71b4..fee74f215cec 100755
--- a/tools/testing/selftests/drivers/net/mlxsw/qos_ets_strict.sh
+++ b/tools/testing/selftests/drivers/net/mlxsw/qos_ets_strict.sh
@@ -138,11 +138,15 @@ switch_create()
vlan_create $swp3 111
vlan_create $swp3 222
- ip link add name br111 up type bridge vlan_filtering 0
+ ip link add name br111 type bridge vlan_filtering 0
+ ip link set dev br111 addrgenmode none
+ ip link set dev br111 up
ip link set dev $swp1.111 master br111
ip link set dev $swp3.111 master br111
- ip link add name br222 up type bridge vlan_filtering 0
+ ip link add name br222 type bridge vlan_filtering 0
+ ip link set dev br222 addrgenmode none
+ ip link set dev br222 up
ip link set dev $swp2.222 master br222
ip link set dev $swp3.222 master br222
diff --git a/tools/testing/selftests/drivers/net/mlxsw/qos_mc_aware.sh b/tools/testing/selftests/drivers/net/mlxsw/qos_mc_aware.sh
index c8e55fa91660..6d892de43fa8 100755
--- a/tools/testing/selftests/drivers/net/mlxsw/qos_mc_aware.sh
+++ b/tools/testing/selftests/drivers/net/mlxsw/qos_mc_aware.sh
@@ -135,11 +135,13 @@ switch_create()
prio bands 8 priomap 7 7 7 7 7 7 7 7
ip link add name br1 type bridge vlan_filtering 0
+ ip link set dev br1 addrgenmode none
ip link set dev br1 up
ip link set dev $swp1 master br1
ip link set dev $swp3 master br1
ip link add name br111 type bridge vlan_filtering 0
+ ip link set dev br111 addrgenmode none
ip link set dev br111 up
ip link set dev $swp2.111 master br111
ip link set dev $swp3.111 master br111
diff --git a/tools/testing/selftests/drivers/net/mlxsw/spectrum/q_in_vni_veto.sh b/tools/testing/selftests/drivers/net/mlxsw/spectrum/q_in_vni_veto.sh
index f0443b1b05b9..60753d46a2d4 100755
--- a/tools/testing/selftests/drivers/net/mlxsw/spectrum/q_in_vni_veto.sh
+++ b/tools/testing/selftests/drivers/net/mlxsw/spectrum/q_in_vni_veto.sh
@@ -34,6 +34,7 @@ create_vxlan_on_top_of_8021ad_bridge()
ip link add dev br0 type bridge vlan_filtering 1 vlan_protocol 802.1ad \
vlan_default_pvid 0 mcast_snooping 0
+ ip link set dev br0 addrgenmode none
ip link set dev br0 up
ip link add name vx100 type vxlan id 1000 local 192.0.2.17 dstport \
diff --git a/tools/testing/selftests/drivers/net/mlxsw/vxlan.sh b/tools/testing/selftests/drivers/net/mlxsw/vxlan.sh
index 99a332b712f0..4687b0a7dffb 100755
--- a/tools/testing/selftests/drivers/net/mlxsw/vxlan.sh
+++ b/tools/testing/selftests/drivers/net/mlxsw/vxlan.sh
@@ -444,8 +444,12 @@ offload_indication_setup_create()
{
# Create a simple setup with two bridges, each with a VxLAN device
# and one local port
- ip link add name br0 up type bridge mcast_snooping 0
- ip link add name br1 up type bridge mcast_snooping 0
+ ip link add name br0 type bridge mcast_snooping 0
+ ip link set dev br0 addrgenmode none
+ ip link set dev br0 up
+ ip link add name br1 type bridge mcast_snooping 0
+ ip link set dev br1 addrgenmode none
+ ip link set dev br1 up
ip link set dev $swp1 master br0
ip link set dev $swp2 master br1
@@ -646,8 +650,12 @@ offload_indication_decap_route_test()
RET=0
- ip link add name br0 up type bridge mcast_snooping 0
- ip link add name br1 up type bridge mcast_snooping 0
+ ip link add name br0 type bridge mcast_snooping 0
+ ip link set dev br0 addrgenmode none
+ ip link set dev br0 up
+ ip link add name br1 type bridge mcast_snooping 0
+ ip link set dev br1 addrgenmode none
+ ip link set dev br1 up
ip link set dev $swp1 master br0
ip link set dev $swp2 master br1
ip link set dev vxlan0 master br0
@@ -780,7 +788,9 @@ __offload_indication_join_vxlan_first()
offload_indication_join_vxlan_first()
{
- ip link add dev br0 up type bridge mcast_snooping 0
+ ip link add dev br0 type bridge mcast_snooping 0
+ ip link set dev br0 addrgenmode none
+ ip link set dev br0 up
ip link add name vxlan0 up type vxlan id 10 nolearning $UDPCSUM_FLAFS \
ttl 20 tos inherit local $LOCAL_IP_1 dstport 4789
@@ -815,7 +825,9 @@ __offload_indication_join_vxlan_last()
offload_indication_join_vxlan_last()
{
- ip link add dev br0 up type bridge mcast_snooping 0
+ ip link add dev br0 type bridge mcast_snooping 0
+ ip link set dev br0 addrgenmode none
+ ip link set dev br0 up
ip link add name vxlan0 up type vxlan id 10 nolearning $UDPCSUM_FLAFS \
ttl 20 tos inherit local $LOCAL_IP_1 dstport 4789
@@ -842,6 +854,7 @@ sanitization_vlan_aware_test()
RET=0
ip link add dev br0 type bridge mcast_snooping 0 vlan_filtering 1
+ ip link set dev br0 addrgenmode none
ip link add name vxlan10 up master br0 type vxlan id 10 nolearning \
$UDPCSUM_FLAFS ttl 20 tos inherit local $LOCAL_IP_1 dstport 4789
@@ -915,8 +928,10 @@ offload_indication_vlan_aware_setup_create()
{
# Create a simple setup with two VxLAN devices and a single VLAN-aware
# bridge
- ip link add name br0 up type bridge mcast_snooping 0 vlan_filtering 1 \
+ ip link add name br0 type bridge mcast_snooping 0 vlan_filtering 1 \
vlan_default_pvid 0
+ ip link set dev br0 addrgenmode none
+ ip link set dev br0 up
ip link set dev $swp1 master br0
@@ -1060,8 +1075,10 @@ offload_indication_vlan_aware_decap_route_test()
offload_indication_vlan_aware_join_vxlan_first()
{
- ip link add dev br0 up type bridge mcast_snooping 0 \
+ ip link add dev br0 type bridge mcast_snooping 0 \
vlan_filtering 1 vlan_default_pvid 1
+ ip link set dev br0 addrgenmode none
+ ip link set dev br0 up
ip link add name vxlan0 up type vxlan id 10 nolearning $UDPCSUM_FLAFS \
ttl 20 tos inherit local $LOCAL_IP_1 dstport 4789
@@ -1073,8 +1090,10 @@ offload_indication_vlan_aware_join_vxlan_first()
offload_indication_vlan_aware_join_vxlan_last()
{
- ip link add dev br0 up type bridge mcast_snooping 0 \
+ ip link add dev br0 type bridge mcast_snooping 0 \
vlan_filtering 1 vlan_default_pvid 1
+ ip link set dev br0 addrgenmode none
+ ip link set dev br0 up
ip link add name vxlan0 up type vxlan id 10 nolearning $UDPCSUM_FLAFS \
ttl 20 tos inherit local $LOCAL_IP_1 dstport 4789
@@ -1091,8 +1110,10 @@ offload_indication_vlan_aware_l3vni_test()
RET=0
sysctl_set net.ipv6.conf.default.disable_ipv6 1
- ip link add dev br0 up type bridge mcast_snooping 0 \
+ ip link add dev br0 type bridge mcast_snooping 0 \
vlan_filtering 1 vlan_default_pvid 0
+ ip link set dev br0 addrgenmode none
+ ip link set dev br0 up
ip link add name vxlan0 up type vxlan id 10 nolearning $UDPCSUM_FLAFS \
ttl 20 tos inherit local $LOCAL_IP_1 dstport 4789
diff --git a/tools/testing/selftests/ftrace/test.d/filter/event-filter-function.tc b/tools/testing/selftests/ftrace/test.d/filter/event-filter-function.tc
index e2ff3bf4df80..2de7c61d1ae3 100644
--- a/tools/testing/selftests/ftrace/test.d/filter/event-filter-function.tc
+++ b/tools/testing/selftests/ftrace/test.d/filter/event-filter-function.tc
@@ -9,18 +9,33 @@ fail() { #msg
exit_fail
}
-echo "Test event filter function name"
+sample_events() {
+ echo > trace
+ echo 1 > events/kmem/kmem_cache_free/enable
+ echo 1 > tracing_on
+ ls > /dev/null
+ echo 0 > tracing_on
+ echo 0 > events/kmem/kmem_cache_free/enable
+}
+
echo 0 > tracing_on
echo 0 > events/enable
+
+echo "Get the most frequently calling function"
+sample_events
+
+target_func=`cut -d: -f3 trace | sed 's/call_site=\([^+]*\)+0x.*/\1/' | sort | uniq -c | sort | tail -n 1 | sed 's/^[ 0-9]*//'`
+if [ -z "$target_func" ]; then
+ exit_fail
+fi
echo > trace
-echo 'call_site.function == exit_mmap' > events/kmem/kmem_cache_free/filter
-echo 1 > events/kmem/kmem_cache_free/enable
-echo 1 > tracing_on
-ls > /dev/null
-echo 0 > events/kmem/kmem_cache_free/enable
-hitcnt=`grep kmem_cache_free trace| grep exit_mmap | wc -l`
-misscnt=`grep kmem_cache_free trace| grep -v exit_mmap | wc -l`
+echo "Test event filter function name"
+echo "call_site.function == $target_func" > events/kmem/kmem_cache_free/filter
+sample_events
+
+hitcnt=`grep kmem_cache_free trace| grep $target_func | wc -l`
+misscnt=`grep kmem_cache_free trace| grep -v $target_func | wc -l`
if [ $hitcnt -eq 0 ]; then
exit_fail
@@ -30,20 +45,14 @@ if [ $misscnt -gt 0 ]; then
exit_fail
fi
-address=`grep ' exit_mmap$' /proc/kallsyms | cut -d' ' -f1`
+address=`grep " ${target_func}\$" /proc/kallsyms | cut -d' ' -f1`
echo "Test event filter function address"
-echo 0 > tracing_on
-echo 0 > events/enable
-echo > trace
echo "call_site.function == 0x$address" > events/kmem/kmem_cache_free/filter
-echo 1 > events/kmem/kmem_cache_free/enable
-echo 1 > tracing_on
-sleep 1
-echo 0 > events/kmem/kmem_cache_free/enable
+sample_events
-hitcnt=`grep kmem_cache_free trace| grep exit_mmap | wc -l`
-misscnt=`grep kmem_cache_free trace| grep -v exit_mmap | wc -l`
+hitcnt=`grep kmem_cache_free trace| grep $target_func | wc -l`
+misscnt=`grep kmem_cache_free trace| grep -v $target_func | wc -l`
if [ $hitcnt -eq 0 ]; then
exit_fail
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-synthetic-event-stack-legacy.tc b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-synthetic-event-stack-legacy.tc
new file mode 100644
index 000000000000..d0cd91a93069
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-synthetic-event-stack-legacy.tc
@@ -0,0 +1,24 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: event trigger - test inter-event histogram trigger trace action with dynamic string param (legacy stack)
+# requires: set_event synthetic_events events/sched/sched_process_exec/hist "long[] stack' >> synthetic_events":README
+
+fail() { #msg
+ echo $1
+ exit_fail
+}
+
+echo "Test create synthetic event with stack"
+
+# Test the old stacktrace keyword (for backward compatibility)
+echo 's:wake_lat pid_t pid; u64 delta; unsigned long[] stack;' > dynamic_events
+echo 'hist:keys=next_pid:ts=common_timestamp.usecs,st=stacktrace if prev_state == 1||prev_state == 2' >> events/sched/sched_switch/trigger
+echo 'hist:keys=prev_pid:delta=common_timestamp.usecs-$ts,s=$st:onmax($delta).trace(wake_lat,prev_pid,$delta,$s)' >> events/sched/sched_switch/trigger
+echo 1 > events/synthetic/wake_lat/enable
+sleep 1
+
+if ! grep -q "=>.*sched" trace; then
+ fail "Failed to create synthetic event with stack"
+fi
+
+exit 0
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-synthetic-event-stack.tc b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-synthetic-event-stack.tc
index 755dbe94ccf4..8f1cc9a86a06 100644
--- a/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-synthetic-event-stack.tc
+++ b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-synthetic-event-stack.tc
@@ -1,7 +1,7 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: event trigger - test inter-event histogram trigger trace action with dynamic string param
-# requires: set_event synthetic_events events/sched/sched_process_exec/hist "long[]' >> synthetic_events":README
+# requires: set_event synthetic_events events/sched/sched_process_exec/hist "can be any field, or the special string 'common_stacktrace'":README
fail() { #msg
echo $1
@@ -10,9 +10,8 @@ fail() { #msg
echo "Test create synthetic event with stack"
-
echo 's:wake_lat pid_t pid; u64 delta; unsigned long[] stack;' > dynamic_events
-echo 'hist:keys=next_pid:ts=common_timestamp.usecs,st=stacktrace if prev_state == 1||prev_state == 2' >> events/sched/sched_switch/trigger
+echo 'hist:keys=next_pid:ts=common_timestamp.usecs,st=common_stacktrace if prev_state == 1||prev_state == 2' >> events/sched/sched_switch/trigger
echo 'hist:keys=prev_pid:delta=common_timestamp.usecs-$ts,s=$st:onmax($delta).trace(wake_lat,prev_pid,$delta,$s)' >> events/sched/sched_switch/trigger
echo 1 > events/synthetic/wake_lat/enable
sleep 1
diff --git a/tools/testing/selftests/gpio/gpio-sim.sh b/tools/testing/selftests/gpio/gpio-sim.sh
index 9f539d454ee4..fa2ce2b9dd5f 100755
--- a/tools/testing/selftests/gpio/gpio-sim.sh
+++ b/tools/testing/selftests/gpio/gpio-sim.sh
@@ -389,6 +389,9 @@ create_chip chip
create_bank chip bank
set_num_lines chip bank 8
enable_chip chip
+DEVNAME=`configfs_dev_name chip`
+CHIPNAME=`configfs_chip_name chip bank`
+SYSFS_PATH="/sys/devices/platform/$DEVNAME/$CHIPNAME/sim_gpio0/value"
$BASE_DIR/gpio-mockup-cdev -b pull-up /dev/`configfs_chip_name chip bank` 0
test `cat $SYSFS_PATH` = "1" || fail "bias setting does not work"
remove_chip chip
diff --git a/tools/testing/selftests/kselftest_harness.h b/tools/testing/selftests/kselftest_harness.h
index d8bff2005dfc..5fd49ad0c696 100644
--- a/tools/testing/selftests/kselftest_harness.h
+++ b/tools/testing/selftests/kselftest_harness.h
@@ -249,7 +249,7 @@
/**
* FIXTURE_SETUP() - Prepares the setup function for the fixture.
- * *_metadata* is included so that EXPECT_* and ASSERT_* work correctly.
+ * *_metadata* is included so that EXPECT_*, ASSERT_* etc. work correctly.
*
* @fixture_name: fixture name
*
@@ -275,7 +275,7 @@
/**
* FIXTURE_TEARDOWN()
- * *_metadata* is included so that EXPECT_* and ASSERT_* work correctly.
+ * *_metadata* is included so that EXPECT_*, ASSERT_* etc. work correctly.
*
* @fixture_name: fixture name
*
@@ -388,7 +388,7 @@
if (setjmp(_metadata->env) == 0) { \
fixture_name##_setup(_metadata, &self, variant->data); \
/* Let setup failure terminate early. */ \
- if (!_metadata->passed) \
+ if (!_metadata->passed || _metadata->skip) \
return; \
_metadata->setup_completed = true; \
fixture_name##_##test_name(_metadata, &self, variant->data); \
diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile
index 7a5ff646e7e7..4761b768b773 100644
--- a/tools/testing/selftests/kvm/Makefile
+++ b/tools/testing/selftests/kvm/Makefile
@@ -116,6 +116,7 @@ TEST_GEN_PROGS_x86_64 += x86_64/sev_migrate_tests
TEST_GEN_PROGS_x86_64 += x86_64/amx_test
TEST_GEN_PROGS_x86_64 += x86_64/max_vcpuid_cap_test
TEST_GEN_PROGS_x86_64 += x86_64/triple_fault_event_test
+TEST_GEN_PROGS_x86_64 += x86_64/recalc_apic_map_test
TEST_GEN_PROGS_x86_64 += access_tracking_perf_test
TEST_GEN_PROGS_x86_64 += demand_paging_test
TEST_GEN_PROGS_x86_64 += dirty_log_test
diff --git a/tools/testing/selftests/kvm/x86_64/recalc_apic_map_test.c b/tools/testing/selftests/kvm/x86_64/recalc_apic_map_test.c
new file mode 100644
index 000000000000..4c416ebe7d66
--- /dev/null
+++ b/tools/testing/selftests/kvm/x86_64/recalc_apic_map_test.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Test edge cases and race conditions in kvm_recalculate_apic_map().
+ */
+
+#include <sys/ioctl.h>
+#include <pthread.h>
+#include <time.h>
+
+#include "processor.h"
+#include "test_util.h"
+#include "kvm_util.h"
+#include "apic.h"
+
+#define TIMEOUT 5 /* seconds */
+
+#define LAPIC_DISABLED 0
+#define LAPIC_X2APIC (MSR_IA32_APICBASE_ENABLE | X2APIC_ENABLE)
+#define MAX_XAPIC_ID 0xff
+
+static void *race(void *arg)
+{
+ struct kvm_lapic_state lapic = {};
+ struct kvm_vcpu *vcpu = arg;
+
+ while (1) {
+ /* Trigger kvm_recalculate_apic_map(). */
+ vcpu_ioctl(vcpu, KVM_SET_LAPIC, &lapic);
+ pthread_testcancel();
+ }
+
+ return NULL;
+}
+
+int main(void)
+{
+ struct kvm_vcpu *vcpus[KVM_MAX_VCPUS];
+ struct kvm_vcpu *vcpuN;
+ struct kvm_vm *vm;
+ pthread_t thread;
+ time_t t;
+ int i;
+
+ kvm_static_assert(KVM_MAX_VCPUS > MAX_XAPIC_ID);
+
+ /*
+ * Create the max number of vCPUs supported by selftests so that KVM
+ * has decent amount of work to do when recalculating the map, i.e. to
+ * make the problematic window large enough to hit.
+ */
+ vm = vm_create_with_vcpus(KVM_MAX_VCPUS, NULL, vcpus);
+
+ /*
+ * Enable x2APIC on all vCPUs so that KVM doesn't bail from the recalc
+ * due to vCPUs having aliased xAPIC IDs (truncated to 8 bits).
+ */
+ for (i = 0; i < KVM_MAX_VCPUS; i++)
+ vcpu_set_msr(vcpus[i], MSR_IA32_APICBASE, LAPIC_X2APIC);
+
+ ASSERT_EQ(pthread_create(&thread, NULL, race, vcpus[0]), 0);
+
+ vcpuN = vcpus[KVM_MAX_VCPUS - 1];
+ for (t = time(NULL) + TIMEOUT; time(NULL) < t;) {
+ vcpu_set_msr(vcpuN, MSR_IA32_APICBASE, LAPIC_X2APIC);
+ vcpu_set_msr(vcpuN, MSR_IA32_APICBASE, LAPIC_DISABLED);
+ }
+
+ ASSERT_EQ(pthread_cancel(thread), 0);
+ ASSERT_EQ(pthread_join(thread, NULL), 0);
+
+ kvm_vm_free(vm);
+
+ return 0;
+}
diff --git a/tools/testing/selftests/mm/Makefile b/tools/testing/selftests/mm/Makefile
index 23af4633f0f4..4f0c50c33ba7 100644
--- a/tools/testing/selftests/mm/Makefile
+++ b/tools/testing/selftests/mm/Makefile
@@ -5,12 +5,15 @@ LOCAL_HDRS += $(selfdir)/mm/local_config.h $(top_srcdir)/mm/gup_test.h
include local_config.mk
+ifeq ($(ARCH),)
+
ifeq ($(CROSS_COMPILE),)
uname_M := $(shell uname -m 2>/dev/null || echo not)
else
uname_M := $(shell echo $(CROSS_COMPILE) | grep -o '^[a-z0-9]\+')
endif
-MACHINE ?= $(shell echo $(uname_M) | sed -e 's/aarch64.*/arm64/' -e 's/ppc64.*/ppc64/')
+ARCH ?= $(shell echo $(uname_M) | sed -e 's/aarch64.*/arm64/' -e 's/ppc64.*/ppc64/')
+endif
# Without this, failed build products remain, with up-to-date timestamps,
# thus tricking Make (and you!) into believing that All Is Well, in subsequent
@@ -65,7 +68,7 @@ TEST_GEN_PROGS += ksm_tests
TEST_GEN_PROGS += ksm_functional_tests
TEST_GEN_PROGS += mdwe_test
-ifeq ($(MACHINE),x86_64)
+ifeq ($(ARCH),x86_64)
CAN_BUILD_I386 := $(shell ./../x86/check_cc.sh "$(CC)" ../x86/trivial_32bit_program.c -m32)
CAN_BUILD_X86_64 := $(shell ./../x86/check_cc.sh "$(CC)" ../x86/trivial_64bit_program.c)
CAN_BUILD_WITH_NOPIE := $(shell ./../x86/check_cc.sh "$(CC)" ../x86/trivial_program.c -no-pie)
@@ -87,13 +90,13 @@ TEST_GEN_PROGS += $(BINARIES_64)
endif
else
-ifneq (,$(findstring $(MACHINE),ppc64))
+ifneq (,$(findstring $(ARCH),ppc64))
TEST_GEN_PROGS += protection_keys
endif
endif
-ifneq (,$(filter $(MACHINE),arm64 ia64 mips64 parisc64 ppc64 riscv64 s390x sparc64 x86_64))
+ifneq (,$(filter $(ARCH),arm64 ia64 mips64 parisc64 ppc64 riscv64 s390x sparc64 x86_64))
TEST_GEN_PROGS += va_high_addr_switch
TEST_GEN_PROGS += virtual_address_range
TEST_GEN_PROGS += write_to_hugetlbfs
@@ -112,7 +115,7 @@ $(TEST_GEN_PROGS): vm_util.c
$(OUTPUT)/uffd-stress: uffd-common.c
$(OUTPUT)/uffd-unit-tests: uffd-common.c
-ifeq ($(MACHINE),x86_64)
+ifeq ($(ARCH),x86_64)
BINARIES_32 := $(patsubst %,$(OUTPUT)/%,$(BINARIES_32))
BINARIES_64 := $(patsubst %,$(OUTPUT)/%,$(BINARIES_64))
diff --git a/tools/testing/selftests/net/.gitignore b/tools/testing/selftests/net/.gitignore
index 80f06aa62034..501854a89cc0 100644
--- a/tools/testing/selftests/net/.gitignore
+++ b/tools/testing/selftests/net/.gitignore
@@ -8,8 +8,10 @@ diag_uid
fin_ack_lat
gro
hwtstamp_config
+io_uring_zerocopy_tx
ioam6_parser
ip_defrag
+ip_local_port_range
ipsec
ipv6_flowlabel
ipv6_flowlabel_mgr
@@ -26,6 +28,8 @@ reuseport_bpf_cpu
reuseport_bpf_numa
reuseport_dualstack
rxtimestamp
+sctp_hello
+scm_pidfd
sk_bind_sendto_listen
sk_connect_zero_addr
socket
diff --git a/tools/testing/selftests/net/af_unix/Makefile b/tools/testing/selftests/net/af_unix/Makefile
index 1e4b397cece6..221c387a7d7f 100644
--- a/tools/testing/selftests/net/af_unix/Makefile
+++ b/tools/testing/selftests/net/af_unix/Makefile
@@ -1,3 +1,4 @@
-TEST_GEN_PROGS := diag_uid test_unix_oob unix_connect
+CFLAGS += $(KHDR_INCLUDES)
+TEST_GEN_PROGS := diag_uid test_unix_oob unix_connect scm_pidfd
include ../../lib.mk
diff --git a/tools/testing/selftests/net/af_unix/scm_pidfd.c b/tools/testing/selftests/net/af_unix/scm_pidfd.c
new file mode 100644
index 000000000000..a86222143d79
--- /dev/null
+++ b/tools/testing/selftests/net/af_unix/scm_pidfd.c
@@ -0,0 +1,430 @@
+// SPDX-License-Identifier: GPL-2.0 OR MIT
+#define _GNU_SOURCE
+#include <error.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <linux/socket.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/un.h>
+#include <sys/signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "../../kselftest_harness.h"
+
+#define clean_errno() (errno == 0 ? "None" : strerror(errno))
+#define log_err(MSG, ...) \
+ fprintf(stderr, "(%s:%d: errno: %s) " MSG "\n", __FILE__, __LINE__, \
+ clean_errno(), ##__VA_ARGS__)
+
+#ifndef SCM_PIDFD
+#define SCM_PIDFD 0x04
+#endif
+
+static void child_die()
+{
+ exit(1);
+}
+
+static int safe_int(const char *numstr, int *converted)
+{
+ char *err = NULL;
+ long sli;
+
+ errno = 0;
+ sli = strtol(numstr, &err, 0);
+ if (errno == ERANGE && (sli == LONG_MAX || sli == LONG_MIN))
+ return -ERANGE;
+
+ if (errno != 0 && sli == 0)
+ return -EINVAL;
+
+ if (err == numstr || *err != '\0')
+ return -EINVAL;
+
+ if (sli > INT_MAX || sli < INT_MIN)
+ return -ERANGE;
+
+ *converted = (int)sli;
+ return 0;
+}
+
+static int char_left_gc(const char *buffer, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ if (buffer[i] == ' ' || buffer[i] == '\t')
+ continue;
+
+ return i;
+ }
+
+ return 0;
+}
+
+static int char_right_gc(const char *buffer, size_t len)
+{
+ int i;
+
+ for (i = len - 1; i >= 0; i--) {
+ if (buffer[i] == ' ' || buffer[i] == '\t' ||
+ buffer[i] == '\n' || buffer[i] == '\0')
+ continue;
+
+ return i + 1;
+ }
+
+ return 0;
+}
+
+static char *trim_whitespace_in_place(char *buffer)
+{
+ buffer += char_left_gc(buffer, strlen(buffer));
+ buffer[char_right_gc(buffer, strlen(buffer))] = '\0';
+ return buffer;
+}
+
+/* borrowed (with all helpers) from pidfd/pidfd_open_test.c */
+static pid_t get_pid_from_fdinfo_file(int pidfd, const char *key, size_t keylen)
+{
+ int ret;
+ char path[512];
+ FILE *f;
+ size_t n = 0;
+ pid_t result = -1;
+ char *line = NULL;
+
+ snprintf(path, sizeof(path), "/proc/self/fdinfo/%d", pidfd);
+
+ f = fopen(path, "re");
+ if (!f)
+ return -1;
+
+ while (getline(&line, &n, f) != -1) {
+ char *numstr;
+
+ if (strncmp(line, key, keylen))
+ continue;
+
+ numstr = trim_whitespace_in_place(line + 4);
+ ret = safe_int(numstr, &result);
+ if (ret < 0)
+ goto out;
+
+ break;
+ }
+
+out:
+ free(line);
+ fclose(f);
+ return result;
+}
+
+static int cmsg_check(int fd)
+{
+ struct msghdr msg = { 0 };
+ struct cmsghdr *cmsg;
+ struct iovec iov;
+ struct ucred *ucred = NULL;
+ int data = 0;
+ char control[CMSG_SPACE(sizeof(struct ucred)) +
+ CMSG_SPACE(sizeof(int))] = { 0 };
+ int *pidfd = NULL;
+ pid_t parent_pid;
+ int err;
+
+ iov.iov_base = &data;
+ iov.iov_len = sizeof(data);
+
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = control;
+ msg.msg_controllen = sizeof(control);
+
+ err = recvmsg(fd, &msg, 0);
+ if (err < 0) {
+ log_err("recvmsg");
+ return 1;
+ }
+
+ if (msg.msg_flags & (MSG_TRUNC | MSG_CTRUNC)) {
+ log_err("recvmsg: truncated");
+ return 1;
+ }
+
+ for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
+ cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+ if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_PIDFD) {
+ if (cmsg->cmsg_len < sizeof(*pidfd)) {
+ log_err("CMSG parse: SCM_PIDFD wrong len");
+ return 1;
+ }
+
+ pidfd = (void *)CMSG_DATA(cmsg);
+ }
+
+ if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_CREDENTIALS) {
+ if (cmsg->cmsg_len < sizeof(*ucred)) {
+ log_err("CMSG parse: SCM_CREDENTIALS wrong len");
+ return 1;
+ }
+
+ ucred = (void *)CMSG_DATA(cmsg);
+ }
+ }
+
+ /* send(pfd, "x", sizeof(char), 0) */
+ if (data != 'x') {
+ log_err("recvmsg: data corruption");
+ return 1;
+ }
+
+ if (!pidfd) {
+ log_err("CMSG parse: SCM_PIDFD not found");
+ return 1;
+ }
+
+ if (!ucred) {
+ log_err("CMSG parse: SCM_CREDENTIALS not found");
+ return 1;
+ }
+
+ /* pidfd from SCM_PIDFD should point to the parent process PID */
+ parent_pid =
+ get_pid_from_fdinfo_file(*pidfd, "Pid:", sizeof("Pid:") - 1);
+ if (parent_pid != getppid()) {
+ log_err("wrong SCM_PIDFD %d != %d", parent_pid, getppid());
+ return 1;
+ }
+
+ return 0;
+}
+
+struct sock_addr {
+ char sock_name[32];
+ struct sockaddr_un listen_addr;
+ socklen_t addrlen;
+};
+
+FIXTURE(scm_pidfd)
+{
+ int server;
+ pid_t client_pid;
+ int startup_pipe[2];
+ struct sock_addr server_addr;
+ struct sock_addr *client_addr;
+};
+
+FIXTURE_VARIANT(scm_pidfd)
+{
+ int type;
+ bool abstract;
+};
+
+FIXTURE_VARIANT_ADD(scm_pidfd, stream_pathname)
+{
+ .type = SOCK_STREAM,
+ .abstract = 0,
+};
+
+FIXTURE_VARIANT_ADD(scm_pidfd, stream_abstract)
+{
+ .type = SOCK_STREAM,
+ .abstract = 1,
+};
+
+FIXTURE_VARIANT_ADD(scm_pidfd, dgram_pathname)
+{
+ .type = SOCK_DGRAM,
+ .abstract = 0,
+};
+
+FIXTURE_VARIANT_ADD(scm_pidfd, dgram_abstract)
+{
+ .type = SOCK_DGRAM,
+ .abstract = 1,
+};
+
+FIXTURE_SETUP(scm_pidfd)
+{
+ self->client_addr = mmap(NULL, sizeof(*self->client_addr), PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+ ASSERT_NE(MAP_FAILED, self->client_addr);
+}
+
+FIXTURE_TEARDOWN(scm_pidfd)
+{
+ close(self->server);
+
+ kill(self->client_pid, SIGKILL);
+ waitpid(self->client_pid, NULL, 0);
+
+ if (!variant->abstract) {
+ unlink(self->server_addr.sock_name);
+ unlink(self->client_addr->sock_name);
+ }
+}
+
+static void fill_sockaddr(struct sock_addr *addr, bool abstract)
+{
+ char *sun_path_buf = (char *)&addr->listen_addr.sun_path;
+
+ addr->listen_addr.sun_family = AF_UNIX;
+ addr->addrlen = offsetof(struct sockaddr_un, sun_path);
+ snprintf(addr->sock_name, sizeof(addr->sock_name), "scm_pidfd_%d", getpid());
+ addr->addrlen += strlen(addr->sock_name);
+ if (abstract) {
+ *sun_path_buf = '\0';
+ addr->addrlen++;
+ sun_path_buf++;
+ } else {
+ unlink(addr->sock_name);
+ }
+ memcpy(sun_path_buf, addr->sock_name, strlen(addr->sock_name));
+}
+
+static void client(FIXTURE_DATA(scm_pidfd) *self,
+ const FIXTURE_VARIANT(scm_pidfd) *variant)
+{
+ int err;
+ int cfd;
+ socklen_t len;
+ struct ucred peer_cred;
+ int peer_pidfd;
+ pid_t peer_pid;
+ int on = 0;
+
+ cfd = socket(AF_UNIX, variant->type, 0);
+ if (cfd < 0) {
+ log_err("socket");
+ child_die();
+ }
+
+ if (variant->type == SOCK_DGRAM) {
+ fill_sockaddr(self->client_addr, variant->abstract);
+
+ if (bind(cfd, (struct sockaddr *)&self->client_addr->listen_addr, self->client_addr->addrlen)) {
+ log_err("bind");
+ child_die();
+ }
+ }
+
+ if (connect(cfd, (struct sockaddr *)&self->server_addr.listen_addr,
+ self->server_addr.addrlen) != 0) {
+ log_err("connect");
+ child_die();
+ }
+
+ on = 1;
+ if (setsockopt(cfd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on))) {
+ log_err("Failed to set SO_PASSCRED");
+ child_die();
+ }
+
+ if (setsockopt(cfd, SOL_SOCKET, SO_PASSPIDFD, &on, sizeof(on))) {
+ log_err("Failed to set SO_PASSPIDFD");
+ child_die();
+ }
+
+ close(self->startup_pipe[1]);
+
+ if (cmsg_check(cfd)) {
+ log_err("cmsg_check failed");
+ child_die();
+ }
+
+ /* skip further for SOCK_DGRAM as it's not applicable */
+ if (variant->type == SOCK_DGRAM)
+ return;
+
+ len = sizeof(peer_cred);
+ if (getsockopt(cfd, SOL_SOCKET, SO_PEERCRED, &peer_cred, &len)) {
+ log_err("Failed to get SO_PEERCRED");
+ child_die();
+ }
+
+ len = sizeof(peer_pidfd);
+ if (getsockopt(cfd, SOL_SOCKET, SO_PEERPIDFD, &peer_pidfd, &len)) {
+ log_err("Failed to get SO_PEERPIDFD");
+ child_die();
+ }
+
+ /* pid from SO_PEERCRED should point to the parent process PID */
+ if (peer_cred.pid != getppid()) {
+ log_err("peer_cred.pid != getppid(): %d != %d", peer_cred.pid, getppid());
+ child_die();
+ }
+
+ peer_pid = get_pid_from_fdinfo_file(peer_pidfd,
+ "Pid:", sizeof("Pid:") - 1);
+ if (peer_pid != peer_cred.pid) {
+ log_err("peer_pid != peer_cred.pid: %d != %d", peer_pid, peer_cred.pid);
+ child_die();
+ }
+}
+
+TEST_F(scm_pidfd, test)
+{
+ int err;
+ int pfd;
+ int child_status = 0;
+
+ self->server = socket(AF_UNIX, variant->type, 0);
+ ASSERT_NE(-1, self->server);
+
+ fill_sockaddr(&self->server_addr, variant->abstract);
+
+ err = bind(self->server, (struct sockaddr *)&self->server_addr.listen_addr, self->server_addr.addrlen);
+ ASSERT_EQ(0, err);
+
+ if (variant->type == SOCK_STREAM) {
+ err = listen(self->server, 1);
+ ASSERT_EQ(0, err);
+ }
+
+ err = pipe(self->startup_pipe);
+ ASSERT_NE(-1, err);
+
+ self->client_pid = fork();
+ ASSERT_NE(-1, self->client_pid);
+ if (self->client_pid == 0) {
+ close(self->server);
+ close(self->startup_pipe[0]);
+ client(self, variant);
+ exit(0);
+ }
+ close(self->startup_pipe[1]);
+
+ if (variant->type == SOCK_STREAM) {
+ pfd = accept(self->server, NULL, NULL);
+ ASSERT_NE(-1, pfd);
+ } else {
+ pfd = self->server;
+ }
+
+ /* wait until the child arrives at checkpoint */
+ read(self->startup_pipe[0], &err, sizeof(int));
+ close(self->startup_pipe[0]);
+
+ if (variant->type == SOCK_DGRAM) {
+ err = sendto(pfd, "x", sizeof(char), 0, (struct sockaddr *)&self->client_addr->listen_addr, self->client_addr->addrlen);
+ ASSERT_NE(-1, err);
+ } else {
+ err = send(pfd, "x", sizeof(char), 0);
+ ASSERT_NE(-1, err);
+ }
+
+ close(pfd);
+ waitpid(self->client_pid, &child_status, 0);
+ ASSERT_EQ(0, WIFEXITED(child_status) ? WEXITSTATUS(child_status) : 1);
+}
+
+TEST_HARNESS_MAIN
diff --git a/tools/testing/selftests/net/fcnal-test.sh b/tools/testing/selftests/net/fcnal-test.sh
index 05b5c4af7a08..d32a14ba069a 100755
--- a/tools/testing/selftests/net/fcnal-test.sh
+++ b/tools/testing/selftests/net/fcnal-test.sh
@@ -92,6 +92,13 @@ NSC_CMD="ip netns exec ${NSC}"
which ping6 > /dev/null 2>&1 && ping6=$(which ping6) || ping6=$(which ping)
+# Check if FIPS mode is enabled
+if [ -f /proc/sys/crypto/fips_enabled ]; then
+ fips_enabled=`cat /proc/sys/crypto/fips_enabled`
+else
+ fips_enabled=0
+fi
+
################################################################################
# utilities
@@ -1283,7 +1290,7 @@ ipv4_tcp_novrf()
run_cmd nettest -d ${NSA_DEV} -r ${a}
log_test_addr ${a} $? 1 "No server, device client, local conn"
- ipv4_tcp_md5_novrf
+ [ "$fips_enabled" = "1" ] || ipv4_tcp_md5_novrf
ipv4_tcp_dontroute 0
ipv4_tcp_dontroute 2
@@ -1340,9 +1347,11 @@ ipv4_tcp_vrf()
log_test_addr ${a} $? 1 "Global server, local connection"
# run MD5 tests
- setup_vrf_dup
- ipv4_tcp_md5
- cleanup_vrf_dup
+ if [ "$fips_enabled" = "0" ]; then
+ setup_vrf_dup
+ ipv4_tcp_md5
+ cleanup_vrf_dup
+ fi
#
# enable VRF global server
@@ -2859,7 +2868,7 @@ ipv6_tcp_novrf()
log_test_addr ${a} $? 1 "No server, device client, local conn"
done
- ipv6_tcp_md5_novrf
+ [ "$fips_enabled" = "1" ] || ipv6_tcp_md5_novrf
}
ipv6_tcp_vrf()
@@ -2929,9 +2938,11 @@ ipv6_tcp_vrf()
log_test_addr ${a} $? 1 "Global server, local connection"
# run MD5 tests
- setup_vrf_dup
- ipv6_tcp_md5
- cleanup_vrf_dup
+ if [ "$fips_enabled" = "0" ]; then
+ setup_vrf_dup
+ ipv6_tcp_md5
+ cleanup_vrf_dup
+ fi
#
# enable VRF global server
diff --git a/tools/testing/selftests/net/forwarding/Makefile b/tools/testing/selftests/net/forwarding/Makefile
index a474c60fe348..770efbe24f0d 100644
--- a/tools/testing/selftests/net/forwarding/Makefile
+++ b/tools/testing/selftests/net/forwarding/Makefile
@@ -83,6 +83,8 @@ TEST_PROGS = bridge_igmp.sh \
tc_chains.sh \
tc_flower_router.sh \
tc_flower.sh \
+ tc_flower_l2_miss.sh \
+ tc_flower_cfm.sh \
tc_mpls_l2vpn.sh \
tc_police.sh \
tc_shblocks.sh \
diff --git a/tools/testing/selftests/net/forwarding/dual_vxlan_bridge.sh b/tools/testing/selftests/net/forwarding/dual_vxlan_bridge.sh
index 5148d97a5df8..68ee92df3e07 100755
--- a/tools/testing/selftests/net/forwarding/dual_vxlan_bridge.sh
+++ b/tools/testing/selftests/net/forwarding/dual_vxlan_bridge.sh
@@ -132,6 +132,7 @@ switch_create()
#### BR1 ####
ip link add name br1 type bridge vlan_filtering 1 \
vlan_protocol 802.1ad vlan_default_pvid 0 mcast_snooping 0
+ ip link set dev br1 addrgenmode none
# Make sure the bridge uses the MAC address of the local port and not
# that of the VxLAN's device.
ip link set dev br1 address $(mac_get $swp1)
diff --git a/tools/testing/selftests/net/forwarding/hw_stats_l3.sh b/tools/testing/selftests/net/forwarding/hw_stats_l3.sh
index 432fe8469851..48584a51388f 100755
--- a/tools/testing/selftests/net/forwarding/hw_stats_l3.sh
+++ b/tools/testing/selftests/net/forwarding/hw_stats_l3.sh
@@ -84,8 +84,9 @@ h2_destroy()
router_rp1_200_create()
{
- ip link add name $rp1.200 up \
- link $rp1 addrgenmode eui64 type vlan id 200
+ ip link add name $rp1.200 link $rp1 type vlan id 200
+ ip link set dev $rp1.200 addrgenmode eui64
+ ip link set dev $rp1.200 up
ip address add dev $rp1.200 192.0.2.2/28
ip address add dev $rp1.200 2001:db8:1::2/64
ip stats set dev $rp1.200 l3_stats on
@@ -256,9 +257,11 @@ reapply_config()
router_rp1_200_destroy
- ip link add name $rp1.200 link $rp1 addrgenmode none type vlan id 200
+ ip link add name $rp1.200 link $rp1 type vlan id 200
+ ip link set dev $rp1.200 addrgenmode none
ip stats set dev $rp1.200 l3_stats on
- ip link set dev $rp1.200 up addrgenmode eui64
+ ip link set dev $rp1.200 addrgenmode eui64
+ ip link set dev $rp1.200 up
ip address add dev $rp1.200 192.0.2.2/28
ip address add dev $rp1.200 2001:db8:1::2/64
}
diff --git a/tools/testing/selftests/net/forwarding/mirror_gre_bound.sh b/tools/testing/selftests/net/forwarding/mirror_gre_bound.sh
index 360ca133bead..6c257ec03756 100755
--- a/tools/testing/selftests/net/forwarding/mirror_gre_bound.sh
+++ b/tools/testing/selftests/net/forwarding/mirror_gre_bound.sh
@@ -98,6 +98,7 @@ switch_create()
# Bridge between H1 and H2.
ip link add name br1 type bridge vlan_filtering 1
+ ip link set dev br1 addrgenmode none
ip link set dev br1 up
ip link set dev $swp1 master br1
diff --git a/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d.sh b/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d.sh
index c5095da7f6bf..04fd14b0a9b7 100755
--- a/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d.sh
+++ b/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d.sh
@@ -65,7 +65,8 @@ setup_prepare()
vrf_prepare
mirror_gre_topo_create
- ip link add name br2 type bridge vlan_filtering 0
+ ip link add name br2 address $(mac_get $swp3) \
+ type bridge vlan_filtering 0
ip link set dev br2 up
ip link set dev $swp3 master br2
@@ -93,12 +94,16 @@ cleanup()
test_gretap()
{
+ ip neigh replace 192.0.2.130 lladdr $(mac_get $h3) \
+ nud permanent dev br2
full_test_span_gre_dir gt4 ingress 8 0 "mirror to gretap"
full_test_span_gre_dir gt4 egress 0 8 "mirror to gretap"
}
test_ip6gretap()
{
+ ip neigh replace 2001:db8:2::2 lladdr $(mac_get $h3) \
+ nud permanent dev br2
full_test_span_gre_dir gt6 ingress 8 0 "mirror to ip6gretap"
full_test_span_gre_dir gt6 egress 0 8 "mirror to ip6gretap"
}
diff --git a/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d_vlan.sh b/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d_vlan.sh
index 1b27f2b0f196..f35313c76fac 100755
--- a/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d_vlan.sh
+++ b/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d_vlan.sh
@@ -35,7 +35,8 @@ setup_prepare()
vrf_prepare
mirror_gre_topo_create
- ip link add name br2 type bridge vlan_filtering 0
+ ip link add name br2 address $(mac_get $swp3) \
+ type bridge vlan_filtering 0
ip link set dev br2 up
vlan_create $swp3 555
diff --git a/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1q.sh b/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1q.sh
index 9ff22f28032d..0cf4c47a46f9 100755
--- a/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1q.sh
+++ b/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1q.sh
@@ -90,12 +90,16 @@ cleanup()
test_gretap()
{
+ ip neigh replace 192.0.2.130 lladdr $(mac_get $h3) \
+ nud permanent dev br1
full_test_span_gre_dir gt4 ingress 8 0 "mirror to gretap"
full_test_span_gre_dir gt4 egress 0 8 "mirror to gretap"
}
test_ip6gretap()
{
+ ip neigh replace 2001:db8:2::2 lladdr $(mac_get $h3) \
+ nud permanent dev br1
full_test_span_gre_dir gt6 ingress 8 0 "mirror to ip6gretap"
full_test_span_gre_dir gt6 egress 0 8 "mirror to ip6gretap"
}
diff --git a/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1q_lag.sh b/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1q_lag.sh
index 91e431cd919e..c53148b1dc63 100755
--- a/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1q_lag.sh
+++ b/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1q_lag.sh
@@ -140,7 +140,8 @@ switch_create()
ip link set dev $swp3 up
ip link set dev $swp4 up
- ip link add name br1 type bridge vlan_filtering 1
+ ip link add name br1 address $(mac_get $swp3) \
+ type bridge vlan_filtering 1
team_create lag loadbalance $swp3 $swp4
ip link set dev lag master br1
diff --git a/tools/testing/selftests/net/forwarding/mirror_topo_lib.sh b/tools/testing/selftests/net/forwarding/mirror_topo_lib.sh
index 04979e5962e7..bb1adbb7b98a 100644
--- a/tools/testing/selftests/net/forwarding/mirror_topo_lib.sh
+++ b/tools/testing/selftests/net/forwarding/mirror_topo_lib.sh
@@ -60,6 +60,7 @@ mirror_topo_switch_create()
ip link set dev $swp3 up
ip link add name br1 type bridge vlan_filtering 1
+ ip link set dev br1 addrgenmode none
ip link set dev br1 up
ip link set dev $swp1 master br1
diff --git a/tools/testing/selftests/net/forwarding/pedit_dsfield.sh b/tools/testing/selftests/net/forwarding/pedit_dsfield.sh
index 64fbd211d907..af008fbf2725 100755
--- a/tools/testing/selftests/net/forwarding/pedit_dsfield.sh
+++ b/tools/testing/selftests/net/forwarding/pedit_dsfield.sh
@@ -60,7 +60,9 @@ h2_destroy()
switch_create()
{
- ip link add name br1 up type bridge vlan_filtering 1
+ ip link add name br1 type bridge vlan_filtering 1
+ ip link set dev br1 addrgenmode none
+ ip link set dev br1 up
ip link set dev $swp1 master br1
ip link set dev $swp1 up
ip link set dev $swp2 master br1
diff --git a/tools/testing/selftests/net/forwarding/q_in_vni.sh b/tools/testing/selftests/net/forwarding/q_in_vni.sh
index 4c50c0234bce..798b13525c02 100755
--- a/tools/testing/selftests/net/forwarding/q_in_vni.sh
+++ b/tools/testing/selftests/net/forwarding/q_in_vni.sh
@@ -137,6 +137,7 @@ switch_create()
{
ip link add name br1 type bridge vlan_filtering 1 vlan_protocol 802.1ad \
vlan_default_pvid 0 mcast_snooping 0
+ ip link set dev br1 addrgenmode none
# Make sure the bridge uses the MAC address of the local port and not
# that of the VxLAN's device.
ip link set dev br1 address $(mac_get $swp1)
diff --git a/tools/testing/selftests/net/forwarding/router_bridge.sh b/tools/testing/selftests/net/forwarding/router_bridge.sh
index ebc596a272f7..8ce0aed54ece 100755
--- a/tools/testing/selftests/net/forwarding/router_bridge.sh
+++ b/tools/testing/selftests/net/forwarding/router_bridge.sh
@@ -38,7 +38,8 @@ h2_destroy()
router_create()
{
- ip link add name br1 type bridge vlan_filtering 1
+ ip link add name br1 address $(mac_get $swp1) \
+ type bridge vlan_filtering 1
ip link set dev br1 up
ip link set dev $swp1 master br1
diff --git a/tools/testing/selftests/net/forwarding/router_bridge_vlan.sh b/tools/testing/selftests/net/forwarding/router_bridge_vlan.sh
index fa6a88c50750..de2b2d5480dd 100755
--- a/tools/testing/selftests/net/forwarding/router_bridge_vlan.sh
+++ b/tools/testing/selftests/net/forwarding/router_bridge_vlan.sh
@@ -1,6 +1,28 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
+# +------------------------+ +----------------------+
+# | H1 (vrf) | | H2 (vrf) |
+# | + $h1.555 | | + $h2 |
+# | | 192.0.2.1/28 | | | 192.0.2.130/28 |
+# | | 2001:db8:1::1/64 | | | 2001:db8:2::2/64 |
+# | | | | | |
+# | + $h1 | | | |
+# +----|-------------------+ +--|-------------------+
+# | |
+# +----|--------------------------------------------------|-------------------+
+# | SW | | |
+# | +--|-------------------------------+ + $swp2 |
+# | | + $swp1 | 192.0.2.129/28 |
+# | | vid 555 | 2001:db8:2::1/64 |
+# | | | |
+# | | + BR1 (802.1q) | |
+# | | vid 555 pvid untagged | |
+# | | 192.0.2.2/28 | |
+# | | 2001:db8:1::2/64 | |
+# | +----------------------------------+ |
+# +---------------------------------------------------------------------------+
+
ALL_TESTS="
ping_ipv4
ping_ipv6
@@ -41,7 +63,7 @@ h2_destroy()
router_create()
{
- ip link add name br1 type bridge vlan_filtering 1
+ ip link add name br1 type bridge vlan_filtering 1 vlan_default_pvid 0
ip link set dev br1 up
ip link set dev $swp1 master br1
diff --git a/tools/testing/selftests/net/forwarding/skbedit_priority.sh b/tools/testing/selftests/net/forwarding/skbedit_priority.sh
index bde11dc27873..3dd5fcbd3eaa 100755
--- a/tools/testing/selftests/net/forwarding/skbedit_priority.sh
+++ b/tools/testing/selftests/net/forwarding/skbedit_priority.sh
@@ -54,7 +54,9 @@ h2_destroy()
switch_create()
{
- ip link add name br1 up type bridge vlan_filtering 1
+ ip link add name br1 type bridge vlan_filtering 1
+ ip link set dev br1 addrgenmode none
+ ip link set dev br1 up
ip link set dev $swp1 master br1
ip link set dev $swp1 up
ip link set dev $swp2 master br1
diff --git a/tools/testing/selftests/net/forwarding/tc_flower_cfm.sh b/tools/testing/selftests/net/forwarding/tc_flower_cfm.sh
new file mode 100755
index 000000000000..3ca20df952eb
--- /dev/null
+++ b/tools/testing/selftests/net/forwarding/tc_flower_cfm.sh
@@ -0,0 +1,206 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+ALL_TESTS="match_cfm_opcode match_cfm_level match_cfm_level_and_opcode"
+NUM_NETIFS=2
+source tc_common.sh
+source lib.sh
+
+h1_create()
+{
+ simple_if_init $h1
+}
+
+h1_destroy()
+{
+ simple_if_fini $h1
+}
+
+h2_create()
+{
+ simple_if_init $h2
+ tc qdisc add dev $h2 clsact
+}
+
+h2_destroy()
+{
+ tc qdisc del dev $h2 clsact
+ simple_if_fini $h2
+}
+
+u8_to_hex()
+{
+ local u8=$1; shift
+
+ printf "%02x" $u8
+}
+
+generate_cfm_hdr()
+{
+ local mdl=$1; shift
+ local op=$1; shift
+ local flags=$1; shift
+ local tlv_offset=$1; shift
+
+ local cfm_hdr=$(:
+ )"$(u8_to_hex $((mdl << 5))):"$( : MD level and Version
+ )"$(u8_to_hex $op):"$( : OpCode
+ )"$(u8_to_hex $flags):"$( : Flags
+ )"$(u8_to_hex $tlv_offset)"$( : TLV offset
+ )
+
+ echo $cfm_hdr
+}
+
+match_cfm_opcode()
+{
+ local ethtype="89 02"; readonly ethtype
+ RET=0
+
+ tc filter add dev $h2 ingress protocol cfm pref 1 handle 101 \
+ flower cfm op 47 action drop
+ tc filter add dev $h2 ingress protocol cfm pref 1 handle 102 \
+ flower cfm op 43 action drop
+
+ pkt="$ethtype $(generate_cfm_hdr 7 47 0 32)"
+ $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac "$pkt" -q
+ pkt="$ethtype $(generate_cfm_hdr 6 5 0 4)"
+ $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac "$pkt" -q
+
+ tc_check_packets "dev $h2 ingress" 101 1
+ check_err $? "Did not match on correct opcode"
+
+ tc_check_packets "dev $h2 ingress" 102 0
+ check_err $? "Matched on the wrong opcode"
+
+ pkt="$ethtype $(generate_cfm_hdr 0 43 0 12)"
+ $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac "$pkt" -q
+
+ tc_check_packets "dev $h2 ingress" 101 1
+ check_err $? "Matched on the wrong opcode"
+
+ tc_check_packets "dev $h2 ingress" 102 1
+ check_err $? "Did not match on correct opcode"
+
+ tc filter del dev $h2 ingress protocol cfm pref 1 handle 101 flower
+ tc filter del dev $h2 ingress protocol cfm pref 1 handle 102 flower
+
+ log_test "CFM opcode match test"
+}
+
+match_cfm_level()
+{
+ local ethtype="89 02"; readonly ethtype
+ RET=0
+
+ tc filter add dev $h2 ingress protocol cfm pref 1 handle 101 \
+ flower cfm mdl 5 action drop
+ tc filter add dev $h2 ingress protocol cfm pref 1 handle 102 \
+ flower cfm mdl 3 action drop
+ tc filter add dev $h2 ingress protocol cfm pref 1 handle 103 \
+ flower cfm mdl 0 action drop
+
+ pkt="$ethtype $(generate_cfm_hdr 5 42 0 12)"
+ $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac "$pkt" -q
+ pkt="$ethtype $(generate_cfm_hdr 6 1 0 70)"
+ $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac "$pkt" -q
+ pkt="$ethtype $(generate_cfm_hdr 0 1 0 70)"
+ $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac "$pkt" -q
+
+ tc_check_packets "dev $h2 ingress" 101 1
+ check_err $? "Did not match on correct level"
+
+ tc_check_packets "dev $h2 ingress" 102 0
+ check_err $? "Matched on the wrong level"
+
+ tc_check_packets "dev $h2 ingress" 103 1
+ check_err $? "Did not match on correct level"
+
+ pkt="$ethtype $(generate_cfm_hdr 3 0 0 4)"
+ $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac "$pkt" -q
+
+ tc_check_packets "dev $h2 ingress" 101 1
+ check_err $? "Matched on the wrong level"
+
+ tc_check_packets "dev $h2 ingress" 102 1
+ check_err $? "Did not match on correct level"
+
+ tc_check_packets "dev $h2 ingress" 103 1
+ check_err $? "Matched on the wrong level"
+
+ tc filter del dev $h2 ingress protocol cfm pref 1 handle 101 flower
+ tc filter del dev $h2 ingress protocol cfm pref 1 handle 102 flower
+ tc filter del dev $h2 ingress protocol cfm pref 1 handle 103 flower
+
+ log_test "CFM level match test"
+}
+
+match_cfm_level_and_opcode()
+{
+ local ethtype="89 02"; readonly ethtype
+ RET=0
+
+ tc filter add dev $h2 ingress protocol cfm pref 1 handle 101 \
+ flower cfm mdl 5 op 41 action drop
+ tc filter add dev $h2 ingress protocol cfm pref 1 handle 102 \
+ flower cfm mdl 7 op 42 action drop
+
+ pkt="$ethtype $(generate_cfm_hdr 5 41 0 4)"
+ $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac "$pkt" -q
+ pkt="$ethtype $(generate_cfm_hdr 7 3 0 4)"
+ $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac "$pkt" -q
+ pkt="$ethtype $(generate_cfm_hdr 3 42 0 12)"
+ $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac "$pkt" -q
+
+ tc_check_packets "dev $h2 ingress" 101 1
+ check_err $? "Did not match on correct level and opcode"
+
+ tc_check_packets "dev $h2 ingress" 102 0
+ check_err $? "Matched on the wrong level and opcode"
+
+ pkt="$ethtype $(generate_cfm_hdr 7 42 0 12)"
+ $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac "$pkt" -q
+
+ tc_check_packets "dev $h2 ingress" 101 1
+ check_err $? "Matched on the wrong level and opcode"
+
+ tc_check_packets "dev $h2 ingress" 102 1
+ check_err $? "Did not match on correct level and opcode"
+
+ tc filter del dev $h2 ingress protocol cfm pref 1 handle 101 flower
+ tc filter del dev $h2 ingress protocol cfm pref 1 handle 102 flower
+
+ log_test "CFM opcode and level match test"
+}
+
+setup_prepare()
+{
+ h1=${NETIFS[p1]}
+ h2=${NETIFS[p2]}
+ h1mac=$(mac_get $h1)
+ h2mac=$(mac_get $h2)
+
+ vrf_prepare
+
+ h1_create
+ h2_create
+}
+
+cleanup()
+{
+ pre_cleanup
+
+ h2_destroy
+ h1_destroy
+
+ vrf_cleanup
+}
+
+trap cleanup EXIT
+
+setup_prepare
+setup_wait
+
+tests_run
+
+exit $EXIT_STATUS
diff --git a/tools/testing/selftests/net/forwarding/tc_flower_l2_miss.sh b/tools/testing/selftests/net/forwarding/tc_flower_l2_miss.sh
new file mode 100755
index 000000000000..e22c2d28b6eb
--- /dev/null
+++ b/tools/testing/selftests/net/forwarding/tc_flower_l2_miss.sh
@@ -0,0 +1,350 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+# +-----------------------+ +----------------------+
+# | H1 (vrf) | | H2 (vrf) |
+# | + $h1 | | $h2 + |
+# | | 192.0.2.1/28 | | 192.0.2.2/28 | |
+# | | 2001:db8:1::1/64 | | 2001:db8:1::2/64 | |
+# +----|------------------+ +------------------|---+
+# | |
+# +----|-------------------------------------------------------------------|---+
+# | SW | | |
+# | +-|-------------------------------------------------------------------|-+ |
+# | | + $swp1 BR $swp2 + | |
+# | +-----------------------------------------------------------------------+ |
+# +----------------------------------------------------------------------------+
+
+ALL_TESTS="
+ test_l2_miss_unicast
+ test_l2_miss_multicast
+ test_l2_miss_ll_multicast
+ test_l2_miss_broadcast
+"
+
+NUM_NETIFS=4
+source lib.sh
+source tc_common.sh
+
+h1_create()
+{
+ simple_if_init $h1 192.0.2.1/28 2001:db8:1::1/64
+}
+
+h1_destroy()
+{
+ simple_if_fini $h1 192.0.2.1/28 2001:db8:1::1/64
+}
+
+h2_create()
+{
+ simple_if_init $h2 192.0.2.2/28 2001:db8:1::2/64
+}
+
+h2_destroy()
+{
+ simple_if_fini $h2 192.0.2.2/28 2001:db8:1::2/64
+}
+
+switch_create()
+{
+ ip link add name br1 up type bridge
+ ip link set dev $swp1 master br1
+ ip link set dev $swp1 up
+ ip link set dev $swp2 master br1
+ ip link set dev $swp2 up
+
+ tc qdisc add dev $swp2 clsact
+}
+
+switch_destroy()
+{
+ tc qdisc del dev $swp2 clsact
+
+ ip link set dev $swp2 down
+ ip link set dev $swp2 nomaster
+ ip link set dev $swp1 down
+ ip link set dev $swp1 nomaster
+ ip link del dev br1
+}
+
+test_l2_miss_unicast()
+{
+ local dmac=00:01:02:03:04:05
+ local dip=192.0.2.2
+ local sip=192.0.2.1
+
+ RET=0
+
+ # Unknown unicast.
+ tc filter add dev $swp2 egress protocol ipv4 handle 101 pref 1 \
+ flower indev $swp1 l2_miss 1 dst_mac $dmac src_ip $sip \
+ dst_ip $dip action pass
+ # Known unicast.
+ tc filter add dev $swp2 egress protocol ipv4 handle 102 pref 1 \
+ flower indev $swp1 l2_miss 0 dst_mac $dmac src_ip $sip \
+ dst_ip $dip action pass
+
+ # Before adding FDB entry.
+ $MZ $h1 -a own -b $dmac -t ip -A $sip -B $dip -c 1 -p 100 -q
+
+ tc_check_packets "dev $swp2 egress" 101 1
+ check_err $? "Unknown unicast filter was not hit before adding FDB entry"
+
+ tc_check_packets "dev $swp2 egress" 102 0
+ check_err $? "Known unicast filter was hit before adding FDB entry"
+
+ # Adding FDB entry.
+ bridge fdb replace $dmac dev $swp2 master static
+
+ $MZ $h1 -a own -b $dmac -t ip -A $sip -B $dip -c 1 -p 100 -q
+
+ tc_check_packets "dev $swp2 egress" 101 1
+ check_err $? "Unknown unicast filter was hit after adding FDB entry"
+
+ tc_check_packets "dev $swp2 egress" 102 1
+ check_err $? "Known unicast filter was not hit after adding FDB entry"
+
+ # Deleting FDB entry.
+ bridge fdb del $dmac dev $swp2 master static
+
+ $MZ $h1 -a own -b $dmac -t ip -A $sip -B $dip -c 1 -p 100 -q
+
+ tc_check_packets "dev $swp2 egress" 101 2
+ check_err $? "Unknown unicast filter was not hit after deleting FDB entry"
+
+ tc_check_packets "dev $swp2 egress" 102 1
+ check_err $? "Known unicast filter was hit after deleting FDB entry"
+
+ tc filter del dev $swp2 egress protocol ipv4 pref 1 handle 102 flower
+ tc filter del dev $swp2 egress protocol ipv4 pref 1 handle 101 flower
+
+ log_test "L2 miss - Unicast"
+}
+
+test_l2_miss_multicast_common()
+{
+ local proto=$1; shift
+ local sip=$1; shift
+ local dip=$1; shift
+ local mode=$1; shift
+ local name=$1; shift
+
+ RET=0
+
+ # Unregistered multicast.
+ tc filter add dev $swp2 egress protocol $proto handle 101 pref 1 \
+ flower indev $swp1 l2_miss 1 src_ip $sip dst_ip $dip \
+ action pass
+ # Registered multicast.
+ tc filter add dev $swp2 egress protocol $proto handle 102 pref 1 \
+ flower indev $swp1 l2_miss 0 src_ip $sip dst_ip $dip \
+ action pass
+
+ # Before adding MDB entry.
+ $MZ $mode $h1 -t ip -A $sip -B $dip -c 1 -p 100 -q
+
+ tc_check_packets "dev $swp2 egress" 101 1
+ check_err $? "Unregistered multicast filter was not hit before adding MDB entry"
+
+ tc_check_packets "dev $swp2 egress" 102 0
+ check_err $? "Registered multicast filter was hit before adding MDB entry"
+
+ # Adding MDB entry.
+ bridge mdb replace dev br1 port $swp2 grp $dip permanent
+
+ $MZ $mode $h1 -t ip -A $sip -B $dip -c 1 -p 100 -q
+
+ tc_check_packets "dev $swp2 egress" 101 1
+ check_err $? "Unregistered multicast filter was hit after adding MDB entry"
+
+ tc_check_packets "dev $swp2 egress" 102 1
+ check_err $? "Registered multicast filter was not hit after adding MDB entry"
+
+ # Deleting MDB entry.
+ bridge mdb del dev br1 port $swp2 grp $dip
+
+ $MZ $mode $h1 -t ip -A $sip -B $dip -c 1 -p 100 -q
+
+ tc_check_packets "dev $swp2 egress" 101 2
+ check_err $? "Unregistered multicast filter was not hit after deleting MDB entry"
+
+ tc_check_packets "dev $swp2 egress" 102 1
+ check_err $? "Registered multicast filter was hit after deleting MDB entry"
+
+ tc filter del dev $swp2 egress protocol $proto pref 1 handle 102 flower
+ tc filter del dev $swp2 egress protocol $proto pref 1 handle 101 flower
+
+ log_test "L2 miss - Multicast ($name)"
+}
+
+test_l2_miss_multicast_ipv4()
+{
+ local proto="ipv4"
+ local sip=192.0.2.1
+ local dip=239.1.1.1
+ local mode="-4"
+ local name="IPv4"
+
+ test_l2_miss_multicast_common $proto $sip $dip $mode $name
+}
+
+test_l2_miss_multicast_ipv6()
+{
+ local proto="ipv6"
+ local sip=2001:db8:1::1
+ local dip=ff0e::1
+ local mode="-6"
+ local name="IPv6"
+
+ test_l2_miss_multicast_common $proto $sip $dip $mode $name
+}
+
+test_l2_miss_multicast()
+{
+ # Configure $swp2 as a multicast router port so that it will forward
+ # both registered and unregistered multicast traffic.
+ bridge link set dev $swp2 mcast_router 2
+
+ # Forwarding according to MDB entries only takes place when the bridge
+ # detects that there is a valid querier in the network. Set the bridge
+ # as the querier and assign it a valid IPv6 link-local address to be
+ # used as the source address for MLD queries.
+ ip link set dev br1 type bridge mcast_querier 1
+ ip -6 address add fe80::1/64 nodad dev br1
+ # Wait the default Query Response Interval (10 seconds) for the bridge
+ # to determine that there are no other queriers in the network.
+ sleep 10
+
+ test_l2_miss_multicast_ipv4
+ test_l2_miss_multicast_ipv6
+
+ ip -6 address del fe80::1/64 dev br1
+ ip link set dev br1 type bridge mcast_querier 0
+ bridge link set dev $swp2 mcast_router 1
+}
+
+test_l2_miss_multicast_common2()
+{
+ local name=$1; shift
+ local dmac=$1; shift
+ local dip=224.0.0.1
+ local sip=192.0.2.1
+
+}
+
+test_l2_miss_ll_multicast_common()
+{
+ local proto=$1; shift
+ local dmac=$1; shift
+ local sip=$1; shift
+ local dip=$1; shift
+ local mode=$1; shift
+ local name=$1; shift
+
+ RET=0
+
+ tc filter add dev $swp2 egress protocol $proto handle 101 pref 1 \
+ flower indev $swp1 l2_miss 1 dst_mac $dmac src_ip $sip \
+ dst_ip $dip action pass
+
+ $MZ $mode $h1 -a own -b $dmac -t ip -A $sip -B $dip -c 1 -p 100 -q
+
+ tc_check_packets "dev $swp2 egress" 101 1
+ check_err $? "Filter was not hit"
+
+ tc filter del dev $swp2 egress protocol $proto pref 1 handle 101 flower
+
+ log_test "L2 miss - Link-local multicast ($name)"
+}
+
+test_l2_miss_ll_multicast_ipv4()
+{
+ local proto=ipv4
+ local dmac=01:00:5e:00:00:01
+ local sip=192.0.2.1
+ local dip=224.0.0.1
+ local mode="-4"
+ local name="IPv4"
+
+ test_l2_miss_ll_multicast_common $proto $dmac $sip $dip $mode $name
+}
+
+test_l2_miss_ll_multicast_ipv6()
+{
+ local proto=ipv6
+ local dmac=33:33:00:00:00:01
+ local sip=2001:db8:1::1
+ local dip=ff02::1
+ local mode="-6"
+ local name="IPv6"
+
+ test_l2_miss_ll_multicast_common $proto $dmac $sip $dip $mode $name
+}
+
+test_l2_miss_ll_multicast()
+{
+ test_l2_miss_ll_multicast_ipv4
+ test_l2_miss_ll_multicast_ipv6
+}
+
+test_l2_miss_broadcast()
+{
+ local dmac=ff:ff:ff:ff:ff:ff
+ local smac=00:01:02:03:04:05
+
+ RET=0
+
+ tc filter add dev $swp2 egress protocol all handle 101 pref 1 \
+ flower l2_miss 1 dst_mac $dmac src_mac $smac \
+ action pass
+ tc filter add dev $swp2 egress protocol all handle 102 pref 1 \
+ flower l2_miss 0 dst_mac $dmac src_mac $smac \
+ action pass
+
+ $MZ $h1 -a $smac -b $dmac -c 1 -p 100 -q
+
+ tc_check_packets "dev $swp2 egress" 101 0
+ check_err $? "L2 miss filter was hit when should not"
+
+ tc_check_packets "dev $swp2 egress" 102 1
+ check_err $? "L2 no miss filter was not hit when should"
+
+ tc filter del dev $swp2 egress protocol all pref 1 handle 102 flower
+ tc filter del dev $swp2 egress protocol all pref 1 handle 101 flower
+
+ log_test "L2 miss - Broadcast"
+}
+
+setup_prepare()
+{
+ h1=${NETIFS[p1]}
+ swp1=${NETIFS[p2]}
+
+ swp2=${NETIFS[p3]}
+ h2=${NETIFS[p4]}
+
+ vrf_prepare
+ h1_create
+ h2_create
+ switch_create
+}
+
+cleanup()
+{
+ pre_cleanup
+
+ switch_destroy
+ h2_destroy
+ h1_destroy
+ vrf_cleanup
+}
+
+trap cleanup EXIT
+
+setup_prepare
+setup_wait
+
+tests_run
+
+exit $EXIT_STATUS
diff --git a/tools/testing/selftests/net/mptcp/Makefile b/tools/testing/selftests/net/mptcp/Makefile
index 43a723626126..7b936a926859 100644
--- a/tools/testing/selftests/net/mptcp/Makefile
+++ b/tools/testing/selftests/net/mptcp/Makefile
@@ -9,7 +9,7 @@ TEST_PROGS := mptcp_connect.sh pm_netlink.sh mptcp_join.sh diag.sh \
TEST_GEN_FILES = mptcp_connect pm_nl_ctl mptcp_sockopt mptcp_inq
-TEST_FILES := settings
+TEST_FILES := mptcp_lib.sh settings
EXTRA_CLEAN := *.pcap
diff --git a/tools/testing/selftests/net/mptcp/config b/tools/testing/selftests/net/mptcp/config
index 38021a0dd527..6032f9b23c4c 100644
--- a/tools/testing/selftests/net/mptcp/config
+++ b/tools/testing/selftests/net/mptcp/config
@@ -1,3 +1,4 @@
+CONFIG_KALLSYMS=y
CONFIG_MPTCP=y
CONFIG_IPV6=y
CONFIG_MPTCP_IPV6=y
diff --git a/tools/testing/selftests/net/mptcp/diag.sh b/tools/testing/selftests/net/mptcp/diag.sh
index ef628b16fe9b..fa9e09ad97d9 100755
--- a/tools/testing/selftests/net/mptcp/diag.sh
+++ b/tools/testing/selftests/net/mptcp/diag.sh
@@ -1,6 +1,8 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
+. "$(dirname "${0}")/mptcp_lib.sh"
+
sec=$(date +%s)
rndh=$(printf %x $sec)-$(mktemp -u XXXXXX)
ns="ns1-$rndh"
@@ -31,6 +33,8 @@ cleanup()
ip netns del $ns
}
+mptcp_lib_check_mptcp
+
ip -Version > /dev/null 2>&1
if [ $? -ne 0 ];then
echo "SKIP: Could not run test without ip tool"
@@ -51,16 +55,20 @@ __chk_nr()
{
local command="$1"
local expected=$2
- local msg nr
+ local msg="$3"
+ local skip="${4:-SKIP}"
+ local nr
- shift 2
- msg=$*
nr=$(eval $command)
printf "%-50s" "$msg"
if [ $nr != $expected ]; then
- echo "[ fail ] expected $expected found $nr"
- ret=$test_cnt
+ if [ $nr = "$skip" ] && ! mptcp_lib_expect_all_features; then
+ echo "[ skip ] Feature probably not supported"
+ else
+ echo "[ fail ] expected $expected found $nr"
+ ret=$test_cnt
+ fi
else
echo "[ ok ]"
fi
@@ -72,12 +80,12 @@ __chk_msk_nr()
local condition=$1
shift 1
- __chk_nr "ss -inmHMN $ns | $condition" $*
+ __chk_nr "ss -inmHMN $ns | $condition" "$@"
}
chk_msk_nr()
{
- __chk_msk_nr "grep -c token:" $*
+ __chk_msk_nr "grep -c token:" "$@"
}
wait_msk_nr()
@@ -115,37 +123,26 @@ wait_msk_nr()
chk_msk_fallback_nr()
{
- __chk_msk_nr "grep -c fallback" $*
+ __chk_msk_nr "grep -c fallback" "$@"
}
chk_msk_remote_key_nr()
{
- __chk_msk_nr "grep -c remote_key" $*
+ __chk_msk_nr "grep -c remote_key" "$@"
}
__chk_listen()
{
local filter="$1"
local expected=$2
+ local msg="$3"
- shift 2
- msg=$*
-
- nr=$(ss -N $ns -Ml "$filter" | grep -c LISTEN)
- printf "%-50s" "$msg"
-
- if [ $nr != $expected ]; then
- echo "[ fail ] expected $expected found $nr"
- ret=$test_cnt
- else
- echo "[ ok ]"
- fi
+ __chk_nr "ss -N $ns -Ml '$filter' | grep -c LISTEN" "$expected" "$msg" 0
}
chk_msk_listen()
{
lport=$1
- local msg="check for listen socket"
# destination port search should always return empty list
__chk_listen "dport $lport" 0 "listen match for dport $lport"
@@ -163,10 +160,9 @@ chk_msk_listen()
chk_msk_inuse()
{
local expected=$1
+ local msg="$2"
local listen_nr
- shift 1
-
listen_nr=$(ss -N "${ns}" -Ml | grep -c LISTEN)
expected=$((expected + listen_nr))
@@ -177,7 +173,7 @@ chk_msk_inuse()
sleep 0.1
done
- __chk_nr get_msk_inuse $expected $*
+ __chk_nr get_msk_inuse $expected "$msg" 0
}
# $1: ns, $2: port
diff --git a/tools/testing/selftests/net/mptcp/mptcp_connect.sh b/tools/testing/selftests/net/mptcp/mptcp_connect.sh
index a43d3e2f59bb..773dd770a567 100755
--- a/tools/testing/selftests/net/mptcp/mptcp_connect.sh
+++ b/tools/testing/selftests/net/mptcp/mptcp_connect.sh
@@ -1,6 +1,8 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
+. "$(dirname "${0}")/mptcp_lib.sh"
+
time_start=$(date +%s)
optstring="S:R:d:e:l:r:h4cm:f:tC"
@@ -141,6 +143,9 @@ cleanup()
done
}
+mptcp_lib_check_mptcp
+mptcp_lib_check_kallsyms
+
ip -Version > /dev/null 2>&1
if [ $? -ne 0 ];then
echo "SKIP: Could not run test without ip tool"
@@ -691,6 +696,15 @@ run_test_transparent()
return 0
fi
+ # IP(V6)_TRANSPARENT has been added after TOS support which came with
+ # the required infrastructure in MPTCP sockopt code. To support TOS, the
+ # following function has been exported (T). Not great but better than
+ # checking for a specific kernel version.
+ if ! mptcp_lib_kallsyms_has "T __ip_sock_set_tos$"; then
+ echo "INFO: ${msg} not supported by the kernel: SKIP"
+ return
+ fi
+
ip netns exec "$listener_ns" nft -f /dev/stdin <<"EOF"
flush ruleset
table inet mangle {
@@ -763,6 +777,11 @@ run_tests_peekmode()
run_tests_mptfo()
{
+ if ! mptcp_lib_kallsyms_has "mptcp_fastopen_"; then
+ echo "INFO: TFO not supported by the kernel: SKIP"
+ return
+ fi
+
echo "INFO: with MPTFO start"
ip netns exec "$ns1" sysctl -q net.ipv4.tcp_fastopen=2
ip netns exec "$ns2" sysctl -q net.ipv4.tcp_fastopen=1
@@ -783,6 +802,11 @@ run_tests_disconnect()
local old_cin=$cin
local old_sin=$sin
+ if ! mptcp_lib_kallsyms_has "mptcp_pm_data_reset$"; then
+ echo "INFO: Full disconnect not supported: SKIP"
+ return
+ fi
+
cat $cin $cin $cin > "$cin".disconnect
# force do_transfer to cope with the multiple tranmissions
diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh
index e74d3074ef90..a7973d6a40a0 100755
--- a/tools/testing/selftests/net/mptcp/mptcp_join.sh
+++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh
@@ -10,6 +10,8 @@
# because it's invoked by variable name, see how the "tests" array is used
#shellcheck disable=SC2317
+. "$(dirname "${0}")/mptcp_lib.sh"
+
ret=0
sin=""
sinfail=""
@@ -17,11 +19,14 @@ sout=""
cin=""
cinfail=""
cinsent=""
+tmpfile=""
cout=""
capout=""
ns1=""
ns2=""
ksft_skip=4
+iptables="iptables"
+ip6tables="ip6tables"
timeout_poll=30
timeout_test=$((timeout_poll * 2 + 1))
capture=0
@@ -80,7 +85,7 @@ init_partial()
ip netns add $netns || exit $ksft_skip
ip -net $netns link set lo up
ip netns exec $netns sysctl -q net.mptcp.enabled=1
- ip netns exec $netns sysctl -q net.mptcp.pm_type=0
+ ip netns exec $netns sysctl -q net.mptcp.pm_type=0 2>/dev/null || true
ip netns exec $netns sysctl -q net.ipv4.conf.all.rp_filter=0
ip netns exec $netns sysctl -q net.ipv4.conf.default.rp_filter=0
if [ $checksum -eq 1 ]; then
@@ -138,12 +143,19 @@ cleanup_partial()
check_tools()
{
+ mptcp_lib_check_mptcp
+ mptcp_lib_check_kallsyms
+
if ! ip -Version &> /dev/null; then
echo "SKIP: Could not run test without ip tool"
exit $ksft_skip
fi
- if ! iptables -V &> /dev/null; then
+ # Use the legacy version if available to support old kernel versions
+ if iptables-legacy -V &> /dev/null; then
+ iptables="iptables-legacy"
+ ip6tables="ip6tables-legacy"
+ elif ! iptables -V &> /dev/null; then
echo "SKIP: Could not run all tests without iptables tool"
exit $ksft_skip
fi
@@ -177,10 +189,37 @@ cleanup()
{
rm -f "$cin" "$cout" "$sinfail"
rm -f "$sin" "$sout" "$cinsent" "$cinfail"
+ rm -f "$tmpfile"
rm -rf $evts_ns1 $evts_ns2
cleanup_partial
}
+# $1: msg
+print_title()
+{
+ printf "%03u %-36s %s" "${TEST_COUNT}" "${TEST_NAME}" "${1}"
+}
+
+# [ $1: fail msg ]
+mark_as_skipped()
+{
+ local msg="${1:-"Feature not supported"}"
+
+ mptcp_lib_fail_if_expected_feature "${msg}"
+
+ print_title "[ skip ] ${msg}"
+ printf "\n"
+}
+
+# $@: condition
+continue_if()
+{
+ if ! "${@}"; then
+ mark_as_skipped
+ return 1
+ fi
+}
+
skip_test()
{
if [ "${#only_tests_ids[@]}" -eq 0 ] && [ "${#only_tests_names[@]}" -eq 0 ]; then
@@ -224,6 +263,19 @@ reset()
return 0
}
+# $1: test name ; $2: counter to check
+reset_check_counter()
+{
+ reset "${1}" || return 1
+
+ local counter="${2}"
+
+ if ! nstat -asz "${counter}" | grep -wq "${counter}"; then
+ mark_as_skipped "counter '${counter}' is not available"
+ return 1
+ fi
+}
+
# $1: test name
reset_with_cookies()
{
@@ -243,17 +295,21 @@ reset_with_add_addr_timeout()
reset "${1}" || return 1
- tables="iptables"
+ tables="${iptables}"
if [ $ip -eq 6 ]; then
- tables="ip6tables"
+ tables="${ip6tables}"
fi
ip netns exec $ns1 sysctl -q net.mptcp.add_addr_timeout=1
- ip netns exec $ns2 $tables -A OUTPUT -p tcp \
- -m tcp --tcp-option 30 \
- -m bpf --bytecode \
- "$CBPF_MPTCP_SUBOPTION_ADD_ADDR" \
- -j DROP
+
+ if ! ip netns exec $ns2 $tables -A OUTPUT -p tcp \
+ -m tcp --tcp-option 30 \
+ -m bpf --bytecode \
+ "$CBPF_MPTCP_SUBOPTION_ADD_ADDR" \
+ -j DROP; then
+ mark_as_skipped "unable to set the 'add addr' rule"
+ return 1
+ fi
}
# $1: test name
@@ -297,22 +353,17 @@ reset_with_allow_join_id0()
# tc action pedit offset 162 out of bounds
#
# Netfilter is used to mark packets with enough data.
-reset_with_fail()
+setup_fail_rules()
{
- reset "${1}" || return 1
-
- ip netns exec $ns1 sysctl -q net.mptcp.checksum_enabled=1
- ip netns exec $ns2 sysctl -q net.mptcp.checksum_enabled=1
-
check_invert=1
validate_checksum=1
- local i="$2"
- local ip="${3:-4}"
+ local i="$1"
+ local ip="${2:-4}"
local tables
- tables="iptables"
+ tables="${iptables}"
if [ $ip -eq 6 ]; then
- tables="ip6tables"
+ tables="${ip6tables}"
fi
ip netns exec $ns2 $tables \
@@ -322,15 +373,32 @@ reset_with_fail()
-p tcp \
-m length --length 150:9999 \
-m statistic --mode nth --packet 1 --every 99999 \
- -j MARK --set-mark 42 || exit 1
+ -j MARK --set-mark 42 || return ${ksft_skip}
- tc -n $ns2 qdisc add dev ns2eth$i clsact || exit 1
+ tc -n $ns2 qdisc add dev ns2eth$i clsact || return ${ksft_skip}
tc -n $ns2 filter add dev ns2eth$i egress \
protocol ip prio 1000 \
handle 42 fw \
action pedit munge offset 148 u8 invert \
pipe csum tcp \
- index 100 || exit 1
+ index 100 || return ${ksft_skip}
+}
+
+reset_with_fail()
+{
+ reset_check_counter "${1}" "MPTcpExtInfiniteMapTx" || return 1
+ shift
+
+ ip netns exec $ns1 sysctl -q net.mptcp.checksum_enabled=1
+ ip netns exec $ns2 sysctl -q net.mptcp.checksum_enabled=1
+
+ local rc=0
+ setup_fail_rules "${@}" || rc=$?
+
+ if [ ${rc} -eq ${ksft_skip} ]; then
+ mark_as_skipped "unable to set the 'fail' rules"
+ return 1
+ fi
}
reset_with_events()
@@ -345,6 +413,25 @@ reset_with_events()
evts_ns2_pid=$!
}
+reset_with_tcp_filter()
+{
+ reset "${1}" || return 1
+ shift
+
+ local ns="${!1}"
+ local src="${2}"
+ local target="${3}"
+
+ if ! ip netns exec "${ns}" ${iptables} \
+ -A INPUT \
+ -s "${src}" \
+ -p tcp \
+ -j "${target}"; then
+ mark_as_skipped "unable to set the filter rules"
+ return 1
+ fi
+}
+
fail_test()
{
ret=1
@@ -388,9 +475,16 @@ check_transfer()
fail_test
return 1
fi
- bytes="--bytes=${bytes}"
+
+ # note: BusyBox's "cmp" command doesn't support --bytes
+ tmpfile=$(mktemp)
+ head --bytes="$bytes" "$in" > "$tmpfile"
+ mv "$tmpfile" "$in"
+ head --bytes="$bytes" "$out" > "$tmpfile"
+ mv "$tmpfile" "$out"
+ tmpfile=""
fi
- cmp -l "$in" "$out" ${bytes} | while read -r i a b; do
+ cmp -l "$in" "$out" | while read -r i a b; do
local sum=$((0${a} + 0${b}))
if [ $check_invert -eq 0 ] || [ $sum -ne $((0xff)) ]; then
echo "[ FAIL ] $what does not match (in, out):"
@@ -459,11 +553,25 @@ wait_local_port_listen()
done
}
-rm_addr_count()
+# $1: ns ; $2: counter
+get_counter()
{
- local ns=${1}
+ local ns="${1}"
+ local counter="${2}"
+ local count
+
+ count=$(ip netns exec ${ns} nstat -asz "${counter}" | awk 'NR==1 {next} {print $2}')
+ if [ -z "${count}" ]; then
+ mptcp_lib_fail_if_expected_feature "${counter} counter"
+ return 1
+ fi
- ip netns exec ${ns} nstat -as | grep MPTcpExtRmAddr | awk '{print $2}'
+ echo "${count}"
+}
+
+rm_addr_count()
+{
+ get_counter "${1}" "MPTcpExtRmAddr"
}
# $1: ns, $2: old rm_addr counter in $ns
@@ -486,11 +594,11 @@ wait_mpj()
local ns="${1}"
local cnt old_cnt
- old_cnt=$(ip netns exec ${ns} nstat -as | grep MPJoinAckRx | awk '{print $2}')
+ old_cnt=$(get_counter ${ns} "MPTcpExtMPJoinAckRx")
local i
for i in $(seq 10); do
- cnt=$(ip netns exec ${ns} nstat -as | grep MPJoinAckRx | awk '{print $2}')
+ cnt=$(get_counter ${ns} "MPTcpExtMPJoinAckRx")
[ "$cnt" = "${old_cnt}" ] || break
sleep 0.1
done
@@ -690,15 +798,6 @@ pm_nl_check_endpoint()
fi
}
-filter_tcp_from()
-{
- local ns="${1}"
- local src="${2}"
- local target="${3}"
-
- ip netns exec "${ns}" iptables -A INPUT -s "${src}" -p tcp -j "${target}"
-}
-
do_transfer()
{
local listener_ns="$1"
@@ -854,7 +953,15 @@ do_transfer()
sed -n 's/.*\(token:\)\([[:digit:]]*\).*$/\2/p;q')
ip netns exec ${listener_ns} ./pm_nl_ctl ann $addr token $tk id $id
sleep 1
+ sp=$(grep "type:10" "$evts_ns1" |
+ sed -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q')
+ da=$(grep "type:10" "$evts_ns1" |
+ sed -n 's/.*\(daddr6:\)\([0-9a-f:.]*\).*$/\2/p;q')
+ dp=$(grep "type:10" "$evts_ns1" |
+ sed -n 's/.*\(dport:\)\([[:digit:]]*\).*$/\2/p;q')
ip netns exec ${listener_ns} ./pm_nl_ctl rem token $tk id $id
+ ip netns exec ${listener_ns} ./pm_nl_ctl dsf lip "::ffff:$addr" \
+ lport $sp rip $da rport $dp token $tk
fi
counter=$((counter + 1))
@@ -920,6 +1027,7 @@ do_transfer()
sleep 1
sp=$(grep "type:10" "$evts_ns2" |
sed -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q')
+ ip netns exec ${connector_ns} ./pm_nl_ctl rem token $tk id $id
ip netns exec ${connector_ns} ./pm_nl_ctl dsf lip $addr lport $sp \
rip $da rport $dp token $tk
fi
@@ -1139,12 +1247,13 @@ chk_csum_nr()
fi
printf "%-${nr_blank}s %s" " " "sum"
- count=$(ip netns exec $ns1 nstat -as | grep MPTcpExtDataCsumErr | awk '{print $2}')
- [ -z "$count" ] && count=0
+ count=$(get_counter ${ns1} "MPTcpExtDataCsumErr")
if [ "$count" != "$csum_ns1" ]; then
extra_msg="$extra_msg ns1=$count"
fi
- if { [ "$count" != $csum_ns1 ] && [ $allow_multi_errors_ns1 -eq 0 ]; } ||
+ if [ -z "$count" ]; then
+ echo -n "[skip]"
+ elif { [ "$count" != $csum_ns1 ] && [ $allow_multi_errors_ns1 -eq 0 ]; } ||
{ [ "$count" -lt $csum_ns1 ] && [ $allow_multi_errors_ns1 -eq 1 ]; }; then
echo "[fail] got $count data checksum error[s] expected $csum_ns1"
fail_test
@@ -1152,12 +1261,13 @@ chk_csum_nr()
echo -n "[ ok ]"
fi
echo -n " - csum "
- count=$(ip netns exec $ns2 nstat -as | grep MPTcpExtDataCsumErr | awk '{print $2}')
- [ -z "$count" ] && count=0
+ count=$(get_counter ${ns2} "MPTcpExtDataCsumErr")
if [ "$count" != "$csum_ns2" ]; then
extra_msg="$extra_msg ns2=$count"
fi
- if { [ "$count" != $csum_ns2 ] && [ $allow_multi_errors_ns2 -eq 0 ]; } ||
+ if [ -z "$count" ]; then
+ echo -n "[skip]"
+ elif { [ "$count" != $csum_ns2 ] && [ $allow_multi_errors_ns2 -eq 0 ]; } ||
{ [ "$count" -lt $csum_ns2 ] && [ $allow_multi_errors_ns2 -eq 1 ]; }; then
echo "[fail] got $count data checksum error[s] expected $csum_ns2"
fail_test
@@ -1196,12 +1306,13 @@ chk_fail_nr()
fi
printf "%-${nr_blank}s %s" " " "ftx"
- count=$(ip netns exec $ns_tx nstat -as | grep MPTcpExtMPFailTx | awk '{print $2}')
- [ -z "$count" ] && count=0
+ count=$(get_counter ${ns_tx} "MPTcpExtMPFailTx")
if [ "$count" != "$fail_tx" ]; then
extra_msg="$extra_msg,tx=$count"
fi
- if { [ "$count" != "$fail_tx" ] && [ $allow_tx_lost -eq 0 ]; } ||
+ if [ -z "$count" ]; then
+ echo -n "[skip]"
+ elif { [ "$count" != "$fail_tx" ] && [ $allow_tx_lost -eq 0 ]; } ||
{ [ "$count" -gt "$fail_tx" ] && [ $allow_tx_lost -eq 1 ]; }; then
echo "[fail] got $count MP_FAIL[s] TX expected $fail_tx"
fail_test
@@ -1210,12 +1321,13 @@ chk_fail_nr()
fi
echo -n " - failrx"
- count=$(ip netns exec $ns_rx nstat -as | grep MPTcpExtMPFailRx | awk '{print $2}')
- [ -z "$count" ] && count=0
+ count=$(get_counter ${ns_rx} "MPTcpExtMPFailRx")
if [ "$count" != "$fail_rx" ]; then
extra_msg="$extra_msg,rx=$count"
fi
- if { [ "$count" != "$fail_rx" ] && [ $allow_rx_lost -eq 0 ]; } ||
+ if [ -z "$count" ]; then
+ echo -n "[skip]"
+ elif { [ "$count" != "$fail_rx" ] && [ $allow_rx_lost -eq 0 ]; } ||
{ [ "$count" -gt "$fail_rx" ] && [ $allow_rx_lost -eq 1 ]; }; then
echo "[fail] got $count MP_FAIL[s] RX expected $fail_rx"
fail_test
@@ -1243,10 +1355,11 @@ chk_fclose_nr()
fi
printf "%-${nr_blank}s %s" " " "ctx"
- count=$(ip netns exec $ns_tx nstat -as | grep MPTcpExtMPFastcloseTx | awk '{print $2}')
- [ -z "$count" ] && count=0
- [ "$count" != "$fclose_tx" ] && extra_msg="$extra_msg,tx=$count"
- if [ "$count" != "$fclose_tx" ]; then
+ count=$(get_counter ${ns_tx} "MPTcpExtMPFastcloseTx")
+ if [ -z "$count" ]; then
+ echo -n "[skip]"
+ elif [ "$count" != "$fclose_tx" ]; then
+ extra_msg="$extra_msg,tx=$count"
echo "[fail] got $count MP_FASTCLOSE[s] TX expected $fclose_tx"
fail_test
else
@@ -1254,10 +1367,11 @@ chk_fclose_nr()
fi
echo -n " - fclzrx"
- count=$(ip netns exec $ns_rx nstat -as | grep MPTcpExtMPFastcloseRx | awk '{print $2}')
- [ -z "$count" ] && count=0
- [ "$count" != "$fclose_rx" ] && extra_msg="$extra_msg,rx=$count"
- if [ "$count" != "$fclose_rx" ]; then
+ count=$(get_counter ${ns_rx} "MPTcpExtMPFastcloseRx")
+ if [ -z "$count" ]; then
+ echo -n "[skip]"
+ elif [ "$count" != "$fclose_rx" ]; then
+ extra_msg="$extra_msg,rx=$count"
echo "[fail] got $count MP_FASTCLOSE[s] RX expected $fclose_rx"
fail_test
else
@@ -1284,9 +1398,10 @@ chk_rst_nr()
fi
printf "%-${nr_blank}s %s" " " "rtx"
- count=$(ip netns exec $ns_tx nstat -as | grep MPTcpExtMPRstTx | awk '{print $2}')
- [ -z "$count" ] && count=0
- if [ $count -lt $rst_tx ]; then
+ count=$(get_counter ${ns_tx} "MPTcpExtMPRstTx")
+ if [ -z "$count" ]; then
+ echo -n "[skip]"
+ elif [ $count -lt $rst_tx ]; then
echo "[fail] got $count MP_RST[s] TX expected $rst_tx"
fail_test
else
@@ -1294,9 +1409,10 @@ chk_rst_nr()
fi
echo -n " - rstrx "
- count=$(ip netns exec $ns_rx nstat -as | grep MPTcpExtMPRstRx | awk '{print $2}')
- [ -z "$count" ] && count=0
- if [ "$count" -lt "$rst_rx" ]; then
+ count=$(get_counter ${ns_rx} "MPTcpExtMPRstRx")
+ if [ -z "$count" ]; then
+ echo -n "[skip]"
+ elif [ "$count" -lt "$rst_rx" ]; then
echo "[fail] got $count MP_RST[s] RX expected $rst_rx"
fail_test
else
@@ -1313,9 +1429,10 @@ chk_infi_nr()
local count
printf "%-${nr_blank}s %s" " " "itx"
- count=$(ip netns exec $ns2 nstat -as | grep InfiniteMapTx | awk '{print $2}')
- [ -z "$count" ] && count=0
- if [ "$count" != "$infi_tx" ]; then
+ count=$(get_counter ${ns2} "MPTcpExtInfiniteMapTx")
+ if [ -z "$count" ]; then
+ echo -n "[skip]"
+ elif [ "$count" != "$infi_tx" ]; then
echo "[fail] got $count infinite map[s] TX expected $infi_tx"
fail_test
else
@@ -1323,9 +1440,10 @@ chk_infi_nr()
fi
echo -n " - infirx"
- count=$(ip netns exec $ns1 nstat -as | grep InfiniteMapRx | awk '{print $2}')
- [ -z "$count" ] && count=0
- if [ "$count" != "$infi_rx" ]; then
+ count=$(get_counter ${ns1} "MPTcpExtInfiniteMapRx")
+ if [ -z "$count" ]; then
+ echo "[skip]"
+ elif [ "$count" != "$infi_rx" ]; then
echo "[fail] got $count infinite map[s] RX expected $infi_rx"
fail_test
else
@@ -1353,9 +1471,10 @@ chk_join_nr()
fi
printf "%03u %-36s %s" "${TEST_COUNT}" "${title}" "syn"
- count=$(ip netns exec $ns1 nstat -as | grep MPTcpExtMPJoinSynRx | awk '{print $2}')
- [ -z "$count" ] && count=0
- if [ "$count" != "$syn_nr" ]; then
+ count=$(get_counter ${ns1} "MPTcpExtMPJoinSynRx")
+ if [ -z "$count" ]; then
+ echo -n "[skip]"
+ elif [ "$count" != "$syn_nr" ]; then
echo "[fail] got $count JOIN[s] syn expected $syn_nr"
fail_test
else
@@ -1364,9 +1483,10 @@ chk_join_nr()
echo -n " - synack"
with_cookie=$(ip netns exec $ns2 sysctl -n net.ipv4.tcp_syncookies)
- count=$(ip netns exec $ns2 nstat -as | grep MPTcpExtMPJoinSynAckRx | awk '{print $2}')
- [ -z "$count" ] && count=0
- if [ "$count" != "$syn_ack_nr" ]; then
+ count=$(get_counter ${ns2} "MPTcpExtMPJoinSynAckRx")
+ if [ -z "$count" ]; then
+ echo -n "[skip]"
+ elif [ "$count" != "$syn_ack_nr" ]; then
# simult connections exceeding the limit with cookie enabled could go up to
# synack validation as the conn limit can be enforced reliably only after
# the subflow creation
@@ -1381,9 +1501,10 @@ chk_join_nr()
fi
echo -n " - ack"
- count=$(ip netns exec $ns1 nstat -as | grep MPTcpExtMPJoinAckRx | awk '{print $2}')
- [ -z "$count" ] && count=0
- if [ "$count" != "$ack_nr" ]; then
+ count=$(get_counter ${ns1} "MPTcpExtMPJoinAckRx")
+ if [ -z "$count" ]; then
+ echo "[skip]"
+ elif [ "$count" != "$ack_nr" ]; then
echo "[fail] got $count JOIN[s] ack expected $ack_nr"
fail_test
else
@@ -1413,12 +1534,12 @@ chk_stale_nr()
local recover_nr
printf "%-${nr_blank}s %-18s" " " "stale"
- stale_nr=$(ip netns exec $ns nstat -as | grep MPTcpExtSubflowStale | awk '{print $2}')
- [ -z "$stale_nr" ] && stale_nr=0
- recover_nr=$(ip netns exec $ns nstat -as | grep MPTcpExtSubflowRecover | awk '{print $2}')
- [ -z "$recover_nr" ] && recover_nr=0
- if [ $stale_nr -lt $stale_min ] ||
+ stale_nr=$(get_counter ${ns} "MPTcpExtSubflowStale")
+ recover_nr=$(get_counter ${ns} "MPTcpExtSubflowRecover")
+ if [ -z "$stale_nr" ] || [ -z "$recover_nr" ]; then
+ echo "[skip]"
+ elif [ $stale_nr -lt $stale_min ] ||
{ [ $stale_max -gt 0 ] && [ $stale_nr -gt $stale_max ]; } ||
[ $((stale_nr - recover_nr)) -ne $stale_delta ]; then
echo "[fail] got $stale_nr stale[s] $recover_nr recover[s], " \
@@ -1453,12 +1574,12 @@ chk_add_nr()
timeout=$(ip netns exec $ns1 sysctl -n net.mptcp.add_addr_timeout)
printf "%-${nr_blank}s %s" " " "add"
- count=$(ip netns exec $ns2 nstat -as MPTcpExtAddAddr | grep MPTcpExtAddAddr | awk '{print $2}')
- [ -z "$count" ] && count=0
-
+ count=$(get_counter ${ns2} "MPTcpExtAddAddr")
+ if [ -z "$count" ]; then
+ echo -n "[skip]"
# if the test configured a short timeout tolerate greater then expected
# add addrs options, due to retransmissions
- if [ "$count" != "$add_nr" ] && { [ "$timeout" -gt 1 ] || [ "$count" -lt "$add_nr" ]; }; then
+ elif [ "$count" != "$add_nr" ] && { [ "$timeout" -gt 1 ] || [ "$count" -lt "$add_nr" ]; }; then
echo "[fail] got $count ADD_ADDR[s] expected $add_nr"
fail_test
else
@@ -1466,9 +1587,10 @@ chk_add_nr()
fi
echo -n " - echo "
- count=$(ip netns exec $ns1 nstat -as MPTcpExtEchoAdd | grep MPTcpExtEchoAdd | awk '{print $2}')
- [ -z "$count" ] && count=0
- if [ "$count" != "$echo_nr" ]; then
+ count=$(get_counter ${ns1} "MPTcpExtEchoAdd")
+ if [ -z "$count" ]; then
+ echo -n "[skip]"
+ elif [ "$count" != "$echo_nr" ]; then
echo "[fail] got $count ADD_ADDR echo[s] expected $echo_nr"
fail_test
else
@@ -1477,9 +1599,10 @@ chk_add_nr()
if [ $port_nr -gt 0 ]; then
echo -n " - pt "
- count=$(ip netns exec $ns2 nstat -as | grep MPTcpExtPortAdd | awk '{print $2}')
- [ -z "$count" ] && count=0
- if [ "$count" != "$port_nr" ]; then
+ count=$(get_counter ${ns2} "MPTcpExtPortAdd")
+ if [ -z "$count" ]; then
+ echo "[skip]"
+ elif [ "$count" != "$port_nr" ]; then
echo "[fail] got $count ADD_ADDR[s] with a port-number expected $port_nr"
fail_test
else
@@ -1487,10 +1610,10 @@ chk_add_nr()
fi
printf "%-${nr_blank}s %s" " " "syn"
- count=$(ip netns exec $ns1 nstat -as | grep MPTcpExtMPJoinPortSynRx |
- awk '{print $2}')
- [ -z "$count" ] && count=0
- if [ "$count" != "$syn_nr" ]; then
+ count=$(get_counter ${ns1} "MPTcpExtMPJoinPortSynRx")
+ if [ -z "$count" ]; then
+ echo -n "[skip]"
+ elif [ "$count" != "$syn_nr" ]; then
echo "[fail] got $count JOIN[s] syn with a different \
port-number expected $syn_nr"
fail_test
@@ -1499,10 +1622,10 @@ chk_add_nr()
fi
echo -n " - synack"
- count=$(ip netns exec $ns2 nstat -as | grep MPTcpExtMPJoinPortSynAckRx |
- awk '{print $2}')
- [ -z "$count" ] && count=0
- if [ "$count" != "$syn_ack_nr" ]; then
+ count=$(get_counter ${ns2} "MPTcpExtMPJoinPortSynAckRx")
+ if [ -z "$count" ]; then
+ echo -n "[skip]"
+ elif [ "$count" != "$syn_ack_nr" ]; then
echo "[fail] got $count JOIN[s] synack with a different \
port-number expected $syn_ack_nr"
fail_test
@@ -1511,10 +1634,10 @@ chk_add_nr()
fi
echo -n " - ack"
- count=$(ip netns exec $ns1 nstat -as | grep MPTcpExtMPJoinPortAckRx |
- awk '{print $2}')
- [ -z "$count" ] && count=0
- if [ "$count" != "$ack_nr" ]; then
+ count=$(get_counter ${ns1} "MPTcpExtMPJoinPortAckRx")
+ if [ -z "$count" ]; then
+ echo "[skip]"
+ elif [ "$count" != "$ack_nr" ]; then
echo "[fail] got $count JOIN[s] ack with a different \
port-number expected $ack_nr"
fail_test
@@ -1523,10 +1646,10 @@ chk_add_nr()
fi
printf "%-${nr_blank}s %s" " " "syn"
- count=$(ip netns exec $ns1 nstat -as | grep MPTcpExtMismatchPortSynRx |
- awk '{print $2}')
- [ -z "$count" ] && count=0
- if [ "$count" != "$mis_syn_nr" ]; then
+ count=$(get_counter ${ns1} "MPTcpExtMismatchPortSynRx")
+ if [ -z "$count" ]; then
+ echo -n "[skip]"
+ elif [ "$count" != "$mis_syn_nr" ]; then
echo "[fail] got $count JOIN[s] syn with a mismatched \
port-number expected $mis_syn_nr"
fail_test
@@ -1535,10 +1658,10 @@ chk_add_nr()
fi
echo -n " - ack "
- count=$(ip netns exec $ns1 nstat -as | grep MPTcpExtMismatchPortAckRx |
- awk '{print $2}')
- [ -z "$count" ] && count=0
- if [ "$count" != "$mis_ack_nr" ]; then
+ count=$(get_counter ${ns1} "MPTcpExtMismatchPortAckRx")
+ if [ -z "$count" ]; then
+ echo "[skip]"
+ elif [ "$count" != "$mis_ack_nr" ]; then
echo "[fail] got $count JOIN[s] ack with a mismatched \
port-number expected $mis_ack_nr"
fail_test
@@ -1560,12 +1683,12 @@ chk_add_tx_nr()
timeout=$(ip netns exec $ns1 sysctl -n net.mptcp.add_addr_timeout)
printf "%-${nr_blank}s %s" " " "add TX"
- count=$(ip netns exec $ns1 nstat -as MPTcpExtAddAddrTx | grep MPTcpExtAddAddrTx | awk '{print $2}')
- [ -z "$count" ] && count=0
-
+ count=$(get_counter ${ns1} "MPTcpExtAddAddrTx")
+ if [ -z "$count" ]; then
+ echo -n "[skip]"
# if the test configured a short timeout tolerate greater then expected
# add addrs options, due to retransmissions
- if [ "$count" != "$add_tx_nr" ] && { [ "$timeout" -gt 1 ] || [ "$count" -lt "$add_tx_nr" ]; }; then
+ elif [ "$count" != "$add_tx_nr" ] && { [ "$timeout" -gt 1 ] || [ "$count" -lt "$add_tx_nr" ]; }; then
echo "[fail] got $count ADD_ADDR[s] TX, expected $add_tx_nr"
fail_test
else
@@ -1573,9 +1696,10 @@ chk_add_tx_nr()
fi
echo -n " - echo TX "
- count=$(ip netns exec $ns2 nstat -as MPTcpExtEchoAddTx | grep MPTcpExtEchoAddTx | awk '{print $2}')
- [ -z "$count" ] && count=0
- if [ "$count" != "$echo_tx_nr" ]; then
+ count=$(get_counter ${ns2} "MPTcpExtEchoAddTx")
+ if [ -z "$count" ]; then
+ echo "[skip]"
+ elif [ "$count" != "$echo_tx_nr" ]; then
echo "[fail] got $count ADD_ADDR echo[s] TX, expected $echo_tx_nr"
fail_test
else
@@ -1611,9 +1735,10 @@ chk_rm_nr()
fi
printf "%-${nr_blank}s %s" " " "rm "
- count=$(ip netns exec $addr_ns nstat -as MPTcpExtRmAddr | grep MPTcpExtRmAddr | awk '{print $2}')
- [ -z "$count" ] && count=0
- if [ "$count" != "$rm_addr_nr" ]; then
+ count=$(get_counter ${addr_ns} "MPTcpExtRmAddr")
+ if [ -z "$count" ]; then
+ echo -n "[skip]"
+ elif [ "$count" != "$rm_addr_nr" ]; then
echo "[fail] got $count RM_ADDR[s] expected $rm_addr_nr"
fail_test
else
@@ -1621,28 +1746,26 @@ chk_rm_nr()
fi
echo -n " - rmsf "
- count=$(ip netns exec $subflow_ns nstat -as | grep MPTcpExtRmSubflow | awk '{print $2}')
- [ -z "$count" ] && count=0
- if [ -n "$simult" ]; then
+ count=$(get_counter ${subflow_ns} "MPTcpExtRmSubflow")
+ if [ -z "$count" ]; then
+ echo -n "[skip]"
+ elif [ -n "$simult" ]; then
local cnt suffix
- cnt=$(ip netns exec $addr_ns nstat -as | grep MPTcpExtRmSubflow | awk '{print $2}')
+ cnt=$(get_counter ${addr_ns} "MPTcpExtRmSubflow")
# in case of simult flush, the subflow removal count on each side is
# unreliable
- [ -z "$cnt" ] && cnt=0
count=$((count + cnt))
[ "$count" != "$rm_subflow_nr" ] && suffix="$count in [$rm_subflow_nr:$((rm_subflow_nr*2))]"
if [ $count -ge "$rm_subflow_nr" ] && \
[ "$count" -le "$((rm_subflow_nr *2 ))" ]; then
- echo "[ ok ] $suffix"
+ echo -n "[ ok ] $suffix"
else
echo "[fail] got $count RM_SUBFLOW[s] expected in range [$rm_subflow_nr:$((rm_subflow_nr*2))]"
fail_test
fi
- return
- fi
- if [ "$count" != "$rm_subflow_nr" ]; then
+ elif [ "$count" != "$rm_subflow_nr" ]; then
echo "[fail] got $count RM_SUBFLOW[s] expected $rm_subflow_nr"
fail_test
else
@@ -1657,16 +1780,15 @@ chk_rm_tx_nr()
local rm_addr_tx_nr=$1
printf "%-${nr_blank}s %s" " " "rm TX "
- count=$(ip netns exec $ns2 nstat -as MPTcpExtRmAddrTx | grep MPTcpExtRmAddrTx | awk '{print $2}')
- [ -z "$count" ] && count=0
- if [ "$count" != "$rm_addr_tx_nr" ]; then
+ count=$(get_counter ${ns2} "MPTcpExtRmAddrTx")
+ if [ -z "$count" ]; then
+ echo "[skip]"
+ elif [ "$count" != "$rm_addr_tx_nr" ]; then
echo "[fail] got $count RM_ADDR[s] expected $rm_addr_tx_nr"
fail_test
else
- echo -n "[ ok ]"
+ echo "[ ok ]"
fi
-
- echo "$extra_msg"
}
chk_prio_nr()
@@ -1676,9 +1798,10 @@ chk_prio_nr()
local count
printf "%-${nr_blank}s %s" " " "ptx"
- count=$(ip netns exec $ns1 nstat -as | grep MPTcpExtMPPrioTx | awk '{print $2}')
- [ -z "$count" ] && count=0
- if [ "$count" != "$mp_prio_nr_tx" ]; then
+ count=$(get_counter ${ns1} "MPTcpExtMPPrioTx")
+ if [ -z "$count" ]; then
+ echo -n "[skip]"
+ elif [ "$count" != "$mp_prio_nr_tx" ]; then
echo "[fail] got $count MP_PRIO[s] TX expected $mp_prio_nr_tx"
fail_test
else
@@ -1686,9 +1809,10 @@ chk_prio_nr()
fi
echo -n " - prx "
- count=$(ip netns exec $ns1 nstat -as | grep MPTcpExtMPPrioRx | awk '{print $2}')
- [ -z "$count" ] && count=0
- if [ "$count" != "$mp_prio_nr_rx" ]; then
+ count=$(get_counter ${ns1} "MPTcpExtMPPrioRx")
+ if [ -z "$count" ]; then
+ echo "[skip]"
+ elif [ "$count" != "$mp_prio_nr_rx" ]; then
echo "[fail] got $count MP_PRIO[s] RX expected $mp_prio_nr_rx"
fail_test
else
@@ -1799,7 +1923,7 @@ wait_attempt_fail()
while [ $time -lt $timeout_ms ]; do
local cnt
- cnt=$(ip netns exec $ns nstat -as TcpAttemptFails | grep TcpAttemptFails | awk '{print $2}')
+ cnt=$(get_counter ${ns} "TcpAttemptFails")
[ "$cnt" = 1 ] && return 1
time=$((time + 100))
@@ -1892,23 +2016,23 @@ subflows_error_tests()
fi
# multiple subflows, with subflow creation error
- if reset "multi subflows, with failing subflow"; then
+ if reset_with_tcp_filter "multi subflows, with failing subflow" ns1 10.0.3.2 REJECT &&
+ continue_if mptcp_lib_kallsyms_has "mptcp_pm_subflow_check_next$"; then
pm_nl_set_limits $ns1 0 2
pm_nl_set_limits $ns2 0 2
pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow
pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow
- filter_tcp_from $ns1 10.0.3.2 REJECT
run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow
chk_join_nr 1 1 1
fi
# multiple subflows, with subflow timeout on MPJ
- if reset "multi subflows, with subflow timeout"; then
+ if reset_with_tcp_filter "multi subflows, with subflow timeout" ns1 10.0.3.2 DROP &&
+ continue_if mptcp_lib_kallsyms_has "mptcp_pm_subflow_check_next$"; then
pm_nl_set_limits $ns1 0 2
pm_nl_set_limits $ns2 0 2
pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow
pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow
- filter_tcp_from $ns1 10.0.3.2 DROP
run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow
chk_join_nr 1 1 1
fi
@@ -1916,11 +2040,11 @@ subflows_error_tests()
# multiple subflows, check that the endpoint corresponding to
# closed subflow (due to reset) is not reused if additional
# subflows are added later
- if reset "multi subflows, fair usage on close"; then
+ if reset_with_tcp_filter "multi subflows, fair usage on close" ns1 10.0.3.2 REJECT &&
+ continue_if mptcp_lib_kallsyms_has "mptcp_pm_subflow_check_next$"; then
pm_nl_set_limits $ns1 0 1
pm_nl_set_limits $ns2 0 1
pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow
- filter_tcp_from $ns1 10.0.3.2 REJECT
run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow &
# mpj subflow will be in TW after the reset
@@ -2021,11 +2145,18 @@ signal_address_tests()
# the peer could possibly miss some addr notification, allow retransmission
ip netns exec $ns1 sysctl -q net.mptcp.add_addr_timeout=1
run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow
- chk_join_nr 3 3 3
- # the server will not signal the address terminating
- # the MPC subflow
- chk_add_nr 3 3
+ # It is not directly linked to the commit introducing this
+ # symbol but for the parent one which is linked anyway.
+ if ! mptcp_lib_kallsyms_has "mptcp_pm_subflow_check_next$"; then
+ chk_join_nr 3 3 2
+ chk_add_nr 4 4
+ else
+ chk_join_nr 3 3 3
+ # the server will not signal the address terminating
+ # the MPC subflow
+ chk_add_nr 3 3
+ fi
fi
}
@@ -2268,8 +2399,13 @@ remove_tests()
pm_nl_add_endpoint $ns2 10.0.4.2 flags subflow
run_tests $ns1 $ns2 10.0.1.1 0 -8 -8 slow
chk_join_nr 3 3 3
- chk_rm_tx_nr 0
- chk_rm_nr 0 3 simult
+
+ if mptcp_lib_kversion_ge 5.18; then
+ chk_rm_tx_nr 0
+ chk_rm_nr 0 3 simult
+ else
+ chk_rm_nr 3 3
+ fi
fi
# addresses flush
@@ -2507,7 +2643,8 @@ v4mapped_tests()
mixed_tests()
{
- if reset "IPv4 sockets do not use IPv6 addresses"; then
+ if reset "IPv4 sockets do not use IPv6 addresses" &&
+ continue_if mptcp_lib_kversion_ge 6.3; then
pm_nl_set_limits $ns1 0 1
pm_nl_set_limits $ns2 1 1
pm_nl_add_endpoint $ns1 dead:beef:2::1 flags signal
@@ -2516,7 +2653,8 @@ mixed_tests()
fi
# Need an IPv6 mptcp socket to allow subflows of both families
- if reset "simult IPv4 and IPv6 subflows"; then
+ if reset "simult IPv4 and IPv6 subflows" &&
+ continue_if mptcp_lib_kversion_ge 6.3; then
pm_nl_set_limits $ns1 0 1
pm_nl_set_limits $ns2 1 1
pm_nl_add_endpoint $ns1 10.0.1.1 flags signal
@@ -2525,7 +2663,8 @@ mixed_tests()
fi
# cross families subflows will not be created even in fullmesh mode
- if reset "simult IPv4 and IPv6 subflows, fullmesh 1x1"; then
+ if reset "simult IPv4 and IPv6 subflows, fullmesh 1x1" &&
+ continue_if mptcp_lib_kversion_ge 6.3; then
pm_nl_set_limits $ns1 0 4
pm_nl_set_limits $ns2 1 4
pm_nl_add_endpoint $ns2 dead:beef:2::2 flags subflow,fullmesh
@@ -2536,7 +2675,8 @@ mixed_tests()
# fullmesh still tries to create all the possibly subflows with
# matching family
- if reset "simult IPv4 and IPv6 subflows, fullmesh 2x2"; then
+ if reset "simult IPv4 and IPv6 subflows, fullmesh 2x2" &&
+ continue_if mptcp_lib_kversion_ge 6.3; then
pm_nl_set_limits $ns1 0 4
pm_nl_set_limits $ns2 2 4
pm_nl_add_endpoint $ns1 10.0.2.1 flags signal
@@ -2549,7 +2689,8 @@ mixed_tests()
backup_tests()
{
# single subflow, backup
- if reset "single subflow, backup"; then
+ if reset "single subflow, backup" &&
+ continue_if mptcp_lib_kallsyms_has "subflow_rebuild_header$"; then
pm_nl_set_limits $ns1 0 1
pm_nl_set_limits $ns2 0 1
pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow,backup
@@ -2559,7 +2700,8 @@ backup_tests()
fi
# single address, backup
- if reset "single address, backup"; then
+ if reset "single address, backup" &&
+ continue_if mptcp_lib_kallsyms_has "subflow_rebuild_header$"; then
pm_nl_set_limits $ns1 0 1
pm_nl_add_endpoint $ns1 10.0.2.1 flags signal
pm_nl_set_limits $ns2 1 1
@@ -2570,7 +2712,8 @@ backup_tests()
fi
# single address with port, backup
- if reset "single address with port, backup"; then
+ if reset "single address with port, backup" &&
+ continue_if mptcp_lib_kallsyms_has "subflow_rebuild_header$"; then
pm_nl_set_limits $ns1 0 1
pm_nl_add_endpoint $ns1 10.0.2.1 flags signal port 10100
pm_nl_set_limits $ns2 1 1
@@ -2580,14 +2723,16 @@ backup_tests()
chk_prio_nr 1 1
fi
- if reset "mpc backup"; then
+ if reset "mpc backup" &&
+ continue_if mptcp_lib_kallsyms_doesnt_have "mptcp_subflow_send_ack$"; then
pm_nl_add_endpoint $ns2 10.0.1.2 flags subflow,backup
run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow
chk_join_nr 0 0 0
chk_prio_nr 0 1
fi
- if reset "mpc backup both sides"; then
+ if reset "mpc backup both sides" &&
+ continue_if mptcp_lib_kallsyms_doesnt_have "mptcp_subflow_send_ack$"; then
pm_nl_add_endpoint $ns1 10.0.1.1 flags subflow,backup
pm_nl_add_endpoint $ns2 10.0.1.2 flags subflow,backup
run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow
@@ -2595,14 +2740,16 @@ backup_tests()
chk_prio_nr 1 1
fi
- if reset "mpc switch to backup"; then
+ if reset "mpc switch to backup" &&
+ continue_if mptcp_lib_kallsyms_doesnt_have "mptcp_subflow_send_ack$"; then
pm_nl_add_endpoint $ns2 10.0.1.2 flags subflow
run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow backup
chk_join_nr 0 0 0
chk_prio_nr 0 1
fi
- if reset "mpc switch to backup both sides"; then
+ if reset "mpc switch to backup both sides" &&
+ continue_if mptcp_lib_kallsyms_doesnt_have "mptcp_subflow_send_ack$"; then
pm_nl_add_endpoint $ns1 10.0.1.1 flags subflow
pm_nl_add_endpoint $ns2 10.0.1.2 flags subflow
run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow backup
@@ -2628,38 +2775,41 @@ verify_listener_events()
local family
local saddr
local sport
+ local name
if [ $e_type = $LISTENER_CREATED ]; then
- stdbuf -o0 -e0 printf "\t\t\t\t\t CREATE_LISTENER %s:%s"\
- $e_saddr $e_sport
+ name="LISTENER_CREATED"
elif [ $e_type = $LISTENER_CLOSED ]; then
- stdbuf -o0 -e0 printf "\t\t\t\t\t CLOSE_LISTENER %s:%s "\
- $e_saddr $e_sport
+ name="LISTENER_CLOSED"
+ else
+ name="$e_type"
+ fi
+
+ printf "%-${nr_blank}s %s %s:%s " " " "$name" "$e_saddr" "$e_sport"
+
+ if ! mptcp_lib_kallsyms_has "mptcp_event_pm_listener$"; then
+ printf "[skip]: event not supported\n"
+ return
fi
- type=$(grep "type:$e_type," $evt |
- sed --unbuffered -n 's/.*\(type:\)\([[:digit:]]*\).*$/\2/p;q')
- family=$(grep "type:$e_type," $evt |
- sed --unbuffered -n 's/.*\(family:\)\([[:digit:]]*\).*$/\2/p;q')
- sport=$(grep "type:$e_type," $evt |
- sed --unbuffered -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q')
+ type=$(grep "type:$e_type," $evt | sed -n 's/.*\(type:\)\([[:digit:]]*\).*$/\2/p;q')
+ family=$(grep "type:$e_type," $evt | sed -n 's/.*\(family:\)\([[:digit:]]*\).*$/\2/p;q')
+ sport=$(grep "type:$e_type," $evt | sed -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q')
if [ $family ] && [ $family = $AF_INET6 ]; then
- saddr=$(grep "type:$e_type," $evt |
- sed --unbuffered -n 's/.*\(saddr6:\)\([0-9a-f:.]*\).*$/\2/p;q')
+ saddr=$(grep "type:$e_type," $evt | sed -n 's/.*\(saddr6:\)\([0-9a-f:.]*\).*$/\2/p;q')
else
- saddr=$(grep "type:$e_type," $evt |
- sed --unbuffered -n 's/.*\(saddr4:\)\([0-9.]*\).*$/\2/p;q')
+ saddr=$(grep "type:$e_type," $evt | sed -n 's/.*\(saddr4:\)\([0-9.]*\).*$/\2/p;q')
fi
if [ $type ] && [ $type = $e_type ] &&
[ $family ] && [ $family = $e_family ] &&
[ $saddr ] && [ $saddr = $e_saddr ] &&
[ $sport ] && [ $sport = $e_sport ]; then
- stdbuf -o0 -e0 printf "[ ok ]\n"
+ echo "[ ok ]"
return 0
fi
fail_test
- stdbuf -o0 -e0 printf "[fail]\n"
+ echo "[fail]"
}
add_addr_ports_tests()
@@ -2965,7 +3115,8 @@ fullmesh_tests()
fi
# set fullmesh flag
- if reset "set fullmesh flag test"; then
+ if reset "set fullmesh flag test" &&
+ continue_if mptcp_lib_kversion_ge 5.18; then
pm_nl_set_limits $ns1 4 4
pm_nl_add_endpoint $ns1 10.0.2.1 flags subflow
pm_nl_set_limits $ns2 4 4
@@ -2975,7 +3126,8 @@ fullmesh_tests()
fi
# set nofullmesh flag
- if reset "set nofullmesh flag test"; then
+ if reset "set nofullmesh flag test" &&
+ continue_if mptcp_lib_kversion_ge 5.18; then
pm_nl_set_limits $ns1 4 4
pm_nl_add_endpoint $ns1 10.0.2.1 flags subflow,fullmesh
pm_nl_set_limits $ns2 4 4
@@ -2985,7 +3137,8 @@ fullmesh_tests()
fi
# set backup,fullmesh flags
- if reset "set backup,fullmesh flags test"; then
+ if reset "set backup,fullmesh flags test" &&
+ continue_if mptcp_lib_kversion_ge 5.18; then
pm_nl_set_limits $ns1 4 4
pm_nl_add_endpoint $ns1 10.0.2.1 flags subflow
pm_nl_set_limits $ns2 4 4
@@ -2996,7 +3149,8 @@ fullmesh_tests()
fi
# set nobackup,nofullmesh flags
- if reset "set nobackup,nofullmesh flags test"; then
+ if reset "set nobackup,nofullmesh flags test" &&
+ continue_if mptcp_lib_kversion_ge 5.18; then
pm_nl_set_limits $ns1 4 4
pm_nl_set_limits $ns2 4 4
pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow,backup,fullmesh
@@ -3009,14 +3163,14 @@ fullmesh_tests()
fastclose_tests()
{
- if reset "fastclose test"; then
+ if reset_check_counter "fastclose test" "MPTcpExtMPFastcloseTx"; then
run_tests $ns1 $ns2 10.0.1.1 1024 0 fastclose_client
chk_join_nr 0 0 0
chk_fclose_nr 1 1
chk_rst_nr 1 1 invert
fi
- if reset "fastclose server test"; then
+ if reset_check_counter "fastclose server test" "MPTcpExtMPFastcloseRx"; then
run_tests $ns1 $ns2 10.0.1.1 1024 0 fastclose_server
chk_join_nr 0 0 0
chk_fclose_nr 1 1 invert
@@ -3054,7 +3208,8 @@ fail_tests()
userspace_tests()
{
# userspace pm type prevents add_addr
- if reset "userspace pm type prevents add_addr"; then
+ if reset "userspace pm type prevents add_addr" &&
+ continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then
set_userspace_pm $ns1
pm_nl_set_limits $ns1 0 2
pm_nl_set_limits $ns2 0 2
@@ -3065,7 +3220,8 @@ userspace_tests()
fi
# userspace pm type does not echo add_addr without daemon
- if reset "userspace pm no echo w/o daemon"; then
+ if reset "userspace pm no echo w/o daemon" &&
+ continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then
set_userspace_pm $ns2
pm_nl_set_limits $ns1 0 2
pm_nl_set_limits $ns2 0 2
@@ -3076,7 +3232,8 @@ userspace_tests()
fi
# userspace pm type rejects join
- if reset "userspace pm type rejects join"; then
+ if reset "userspace pm type rejects join" &&
+ continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then
set_userspace_pm $ns1
pm_nl_set_limits $ns1 1 1
pm_nl_set_limits $ns2 1 1
@@ -3086,7 +3243,8 @@ userspace_tests()
fi
# userspace pm type does not send join
- if reset "userspace pm type does not send join"; then
+ if reset "userspace pm type does not send join" &&
+ continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then
set_userspace_pm $ns2
pm_nl_set_limits $ns1 1 1
pm_nl_set_limits $ns2 1 1
@@ -3096,7 +3254,8 @@ userspace_tests()
fi
# userspace pm type prevents mp_prio
- if reset "userspace pm type prevents mp_prio"; then
+ if reset "userspace pm type prevents mp_prio" &&
+ continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then
set_userspace_pm $ns1
pm_nl_set_limits $ns1 1 1
pm_nl_set_limits $ns2 1 1
@@ -3107,7 +3266,8 @@ userspace_tests()
fi
# userspace pm type prevents rm_addr
- if reset "userspace pm type prevents rm_addr"; then
+ if reset "userspace pm type prevents rm_addr" &&
+ continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then
set_userspace_pm $ns1
set_userspace_pm $ns2
pm_nl_set_limits $ns1 0 1
@@ -3119,7 +3279,8 @@ userspace_tests()
fi
# userspace pm add & remove address
- if reset_with_events "userspace pm add & remove address"; then
+ if reset_with_events "userspace pm add & remove address" &&
+ continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then
set_userspace_pm $ns1
pm_nl_set_limits $ns2 1 1
run_tests $ns1 $ns2 10.0.1.1 0 userspace_1 0 slow
@@ -3130,20 +3291,23 @@ userspace_tests()
fi
# userspace pm create destroy subflow
- if reset_with_events "userspace pm create destroy subflow"; then
+ if reset_with_events "userspace pm create destroy subflow" &&
+ continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then
set_userspace_pm $ns2
pm_nl_set_limits $ns1 0 1
run_tests $ns1 $ns2 10.0.1.1 0 0 userspace_1 slow
chk_join_nr 1 1 1
- chk_rm_nr 0 1
+ chk_rm_nr 1 1
kill_events_pids
fi
}
endpoint_tests()
{
+ # subflow_rebuild_header is needed to support the implicit flag
# userspace pm type prevents add_addr
- if reset "implicit EP"; then
+ if reset "implicit EP" &&
+ mptcp_lib_kallsyms_has "subflow_rebuild_header$"; then
pm_nl_set_limits $ns1 2 2
pm_nl_set_limits $ns2 2 2
pm_nl_add_endpoint $ns1 10.0.2.1 flags signal
@@ -3163,7 +3327,8 @@ endpoint_tests()
kill_tests_wait
fi
- if reset "delete and re-add"; then
+ if reset "delete and re-add" &&
+ mptcp_lib_kallsyms_has "subflow_rebuild_header$"; then
pm_nl_set_limits $ns1 1 1
pm_nl_set_limits $ns2 1 1
pm_nl_add_endpoint $ns2 10.0.2.2 id 2 dev ns2eth2 flags subflow
diff --git a/tools/testing/selftests/net/mptcp/mptcp_lib.sh b/tools/testing/selftests/net/mptcp/mptcp_lib.sh
new file mode 100644
index 000000000000..f32045b23b89
--- /dev/null
+++ b/tools/testing/selftests/net/mptcp/mptcp_lib.sh
@@ -0,0 +1,104 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+readonly KSFT_FAIL=1
+readonly KSFT_SKIP=4
+
+# SELFTESTS_MPTCP_LIB_EXPECT_ALL_FEATURES env var can be set when validating all
+# features using the last version of the kernel and the selftests to make sure
+# a test is not being skipped by mistake.
+mptcp_lib_expect_all_features() {
+ [ "${SELFTESTS_MPTCP_LIB_EXPECT_ALL_FEATURES:-}" = "1" ]
+}
+
+# $1: msg
+mptcp_lib_fail_if_expected_feature() {
+ if mptcp_lib_expect_all_features; then
+ echo "ERROR: missing feature: ${*}"
+ exit ${KSFT_FAIL}
+ fi
+
+ return 1
+}
+
+# $1: file
+mptcp_lib_has_file() {
+ local f="${1}"
+
+ if [ -f "${f}" ]; then
+ return 0
+ fi
+
+ mptcp_lib_fail_if_expected_feature "${f} file not found"
+}
+
+mptcp_lib_check_mptcp() {
+ if ! mptcp_lib_has_file "/proc/sys/net/mptcp/enabled"; then
+ echo "SKIP: MPTCP support is not available"
+ exit ${KSFT_SKIP}
+ fi
+}
+
+mptcp_lib_check_kallsyms() {
+ if ! mptcp_lib_has_file "/proc/kallsyms"; then
+ echo "SKIP: CONFIG_KALLSYMS is missing"
+ exit ${KSFT_SKIP}
+ fi
+}
+
+# Internal: use mptcp_lib_kallsyms_has() instead
+__mptcp_lib_kallsyms_has() {
+ local sym="${1}"
+
+ mptcp_lib_check_kallsyms
+
+ grep -q " ${sym}" /proc/kallsyms
+}
+
+# $1: part of a symbol to look at, add '$' at the end for full name
+mptcp_lib_kallsyms_has() {
+ local sym="${1}"
+
+ if __mptcp_lib_kallsyms_has "${sym}"; then
+ return 0
+ fi
+
+ mptcp_lib_fail_if_expected_feature "${sym} symbol not found"
+}
+
+# $1: part of a symbol to look at, add '$' at the end for full name
+mptcp_lib_kallsyms_doesnt_have() {
+ local sym="${1}"
+
+ if ! __mptcp_lib_kallsyms_has "${sym}"; then
+ return 0
+ fi
+
+ mptcp_lib_fail_if_expected_feature "${sym} symbol has been found"
+}
+
+# !!!AVOID USING THIS!!!
+# Features might not land in the expected version and features can be backported
+#
+# $1: kernel version, e.g. 6.3
+mptcp_lib_kversion_ge() {
+ local exp_maj="${1%.*}"
+ local exp_min="${1#*.}"
+ local v maj min
+
+ # If the kernel has backported features, set this env var to 1:
+ if [ "${SELFTESTS_MPTCP_LIB_NO_KVERSION_CHECK:-}" = "1" ]; then
+ return 0
+ fi
+
+ v=$(uname -r | cut -d'.' -f1,2)
+ maj=${v%.*}
+ min=${v#*.}
+
+ if [ "${maj}" -gt "${exp_maj}" ] ||
+ { [ "${maj}" -eq "${exp_maj}" ] && [ "${min}" -ge "${exp_min}" ]; }; then
+ return 0
+ fi
+
+ mptcp_lib_fail_if_expected_feature "kernel version ${1} lower than ${v}"
+}
diff --git a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
index ae61f39556ca..926b0be87c99 100644
--- a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
+++ b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
@@ -51,6 +51,11 @@ struct mptcp_info {
__u8 mptcpi_local_addr_used;
__u8 mptcpi_local_addr_max;
__u8 mptcpi_csum_enabled;
+ __u32 mptcpi_retransmits;
+ __u64 mptcpi_bytes_retrans;
+ __u64 mptcpi_bytes_sent;
+ __u64 mptcpi_bytes_received;
+ __u64 mptcpi_bytes_acked;
};
struct mptcp_subflow_data {
@@ -81,12 +86,47 @@ struct mptcp_subflow_addrs {
#define MPTCP_SUBFLOW_ADDRS 3
#endif
+#ifndef MPTCP_FULL_INFO
+struct mptcp_subflow_info {
+ __u32 id;
+ struct mptcp_subflow_addrs addrs;
+};
+
+struct mptcp_full_info {
+ __u32 size_tcpinfo_kernel; /* must be 0, set by kernel */
+ __u32 size_tcpinfo_user;
+ __u32 size_sfinfo_kernel; /* must be 0, set by kernel */
+ __u32 size_sfinfo_user;
+ __u32 num_subflows; /* must be 0, set by kernel (real subflow count) */
+ __u32 size_arrays_user; /* max subflows that userspace is interested in;
+ * the buffers at subflow_info/tcp_info
+ * are respectively at least:
+ * size_arrays * size_sfinfo_user
+ * size_arrays * size_tcpinfo_user
+ * bytes wide
+ */
+ __aligned_u64 subflow_info;
+ __aligned_u64 tcp_info;
+ struct mptcp_info mptcp_info;
+};
+
+#define MPTCP_FULL_INFO 4
+#endif
+
struct so_state {
struct mptcp_info mi;
+ struct mptcp_info last_sample;
+ struct tcp_info tcp_info;
+ struct mptcp_subflow_addrs addrs;
uint64_t mptcpi_rcv_delta;
uint64_t tcpi_rcv_delta;
+ bool pkt_stats_avail;
};
+#ifndef MIN
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
static void die_perror(const char *msg)
{
perror(msg);
@@ -318,8 +358,9 @@ static void do_getsockopt_mptcp_info(struct so_state *s, int fd, size_t w)
if (ret < 0)
die_perror("getsockopt MPTCP_INFO");
- assert(olen == sizeof(i));
+ s->pkt_stats_avail = olen >= sizeof(i);
+ s->last_sample = i;
if (s->mi.mptcpi_write_seq == 0)
s->mi = i;
@@ -349,13 +390,16 @@ static void do_getsockopt_tcp_info(struct so_state *s, int fd, size_t r, size_t
xerror("getsockopt MPTCP_TCPINFO (tries %d, %m)");
assert(olen <= sizeof(ti));
- assert(ti.d.size_user == ti.d.size_kernel);
- assert(ti.d.size_user == sizeof(struct tcp_info));
+ assert(ti.d.size_kernel > 0);
+ assert(ti.d.size_user ==
+ MIN(ti.d.size_kernel, sizeof(struct tcp_info)));
assert(ti.d.num_subflows == 1);
assert(olen > (socklen_t)sizeof(struct mptcp_subflow_data));
olen -= sizeof(struct mptcp_subflow_data);
- assert(olen == sizeof(struct tcp_info));
+ assert(olen == ti.d.size_user);
+
+ s->tcp_info = ti.ti[0];
if (ti.ti[0].tcpi_bytes_sent == w &&
ti.ti[0].tcpi_bytes_received == r)
@@ -378,7 +422,7 @@ done:
do_getsockopt_bogus_sf_data(fd, MPTCP_TCPINFO);
}
-static void do_getsockopt_subflow_addrs(int fd)
+static void do_getsockopt_subflow_addrs(struct so_state *s, int fd)
{
struct sockaddr_storage remote, local;
socklen_t olen, rlen, llen;
@@ -401,13 +445,14 @@ static void do_getsockopt_subflow_addrs(int fd)
die_perror("getsockopt MPTCP_SUBFLOW_ADDRS");
assert(olen <= sizeof(addrs));
- assert(addrs.d.size_user == addrs.d.size_kernel);
- assert(addrs.d.size_user == sizeof(struct mptcp_subflow_addrs));
+ assert(addrs.d.size_kernel > 0);
+ assert(addrs.d.size_user ==
+ MIN(addrs.d.size_kernel, sizeof(struct mptcp_subflow_addrs)));
assert(addrs.d.num_subflows == 1);
assert(olen > (socklen_t)sizeof(struct mptcp_subflow_data));
olen -= sizeof(struct mptcp_subflow_data);
- assert(olen == sizeof(struct mptcp_subflow_addrs));
+ assert(olen == addrs.d.size_user);
llen = sizeof(local);
ret = getsockname(fd, (struct sockaddr *)&local, &llen);
@@ -425,6 +470,7 @@ static void do_getsockopt_subflow_addrs(int fd)
assert(memcmp(&local, &addrs.addr[0].ss_local, sizeof(local)) == 0);
assert(memcmp(&remote, &addrs.addr[0].ss_remote, sizeof(remote)) == 0);
+ s->addrs = addrs.addr[0];
memset(&addrs, 0, sizeof(addrs));
@@ -445,13 +491,70 @@ static void do_getsockopt_subflow_addrs(int fd)
do_getsockopt_bogus_sf_data(fd, MPTCP_SUBFLOW_ADDRS);
}
+static void do_getsockopt_mptcp_full_info(struct so_state *s, int fd)
+{
+ size_t data_size = sizeof(struct mptcp_full_info);
+ struct mptcp_subflow_info sfinfo[2];
+ struct tcp_info tcp_info[2];
+ struct mptcp_full_info mfi;
+ socklen_t olen;
+ int ret;
+
+ memset(&mfi, 0, data_size);
+ memset(tcp_info, 0, sizeof(tcp_info));
+ memset(sfinfo, 0, sizeof(sfinfo));
+
+ mfi.size_tcpinfo_user = sizeof(struct tcp_info);
+ mfi.size_sfinfo_user = sizeof(struct mptcp_subflow_info);
+ mfi.size_arrays_user = 2;
+ mfi.subflow_info = (unsigned long)&sfinfo[0];
+ mfi.tcp_info = (unsigned long)&tcp_info[0];
+ olen = data_size;
+
+ ret = getsockopt(fd, SOL_MPTCP, MPTCP_FULL_INFO, &mfi, &olen);
+ if (ret < 0) {
+ if (errno == EOPNOTSUPP) {
+ perror("MPTCP_FULL_INFO test skipped");
+ return;
+ }
+ xerror("getsockopt MPTCP_FULL_INFO");
+ }
+
+ assert(olen <= data_size);
+ assert(mfi.size_tcpinfo_kernel > 0);
+ assert(mfi.size_tcpinfo_user ==
+ MIN(mfi.size_tcpinfo_kernel, sizeof(struct tcp_info)));
+ assert(mfi.size_sfinfo_kernel > 0);
+ assert(mfi.size_sfinfo_user ==
+ MIN(mfi.size_sfinfo_kernel, sizeof(struct mptcp_subflow_info)));
+ assert(mfi.num_subflows == 1);
+
+ /* Tolerate future extension to mptcp_info struct and running newer
+ * test on top of older kernel.
+ * Anyway any kernel supporting MPTCP_FULL_INFO must at least include
+ * the following in mptcp_info.
+ */
+ assert(olen > (socklen_t)__builtin_offsetof(struct mptcp_full_info, tcp_info));
+ assert(mfi.mptcp_info.mptcpi_subflows == 0);
+ assert(mfi.mptcp_info.mptcpi_bytes_sent == s->last_sample.mptcpi_bytes_sent);
+ assert(mfi.mptcp_info.mptcpi_bytes_received == s->last_sample.mptcpi_bytes_received);
+
+ assert(sfinfo[0].id == 1);
+ assert(tcp_info[0].tcpi_bytes_sent == s->tcp_info.tcpi_bytes_sent);
+ assert(tcp_info[0].tcpi_bytes_received == s->tcp_info.tcpi_bytes_received);
+ assert(!memcmp(&sfinfo->addrs, &s->addrs, sizeof(struct mptcp_subflow_addrs)));
+}
+
static void do_getsockopts(struct so_state *s, int fd, size_t r, size_t w)
{
do_getsockopt_mptcp_info(s, fd, w);
do_getsockopt_tcp_info(s, fd, r, w);
- do_getsockopt_subflow_addrs(fd);
+ do_getsockopt_subflow_addrs(s, fd);
+
+ if (r)
+ do_getsockopt_mptcp_full_info(s, fd);
}
static void connect_one_server(int fd, int pipefd)
@@ -556,6 +659,23 @@ static void process_one_client(int fd, int pipefd)
do_getsockopts(&s, fd, ret, ret2);
if (s.mptcpi_rcv_delta != (uint64_t)ret + 1)
xerror("mptcpi_rcv_delta %" PRIu64 ", expect %" PRIu64, s.mptcpi_rcv_delta, ret + 1, s.mptcpi_rcv_delta - ret);
+
+ /* be nice when running on top of older kernel */
+ if (s.pkt_stats_avail) {
+ if (s.last_sample.mptcpi_bytes_sent != ret2)
+ xerror("mptcpi_bytes_sent %" PRIu64 ", expect %" PRIu64,
+ s.last_sample.mptcpi_bytes_sent, ret2,
+ s.last_sample.mptcpi_bytes_sent - ret2);
+ if (s.last_sample.mptcpi_bytes_received != ret)
+ xerror("mptcpi_bytes_received %" PRIu64 ", expect %" PRIu64,
+ s.last_sample.mptcpi_bytes_received, ret,
+ s.last_sample.mptcpi_bytes_received - ret);
+ if (s.last_sample.mptcpi_bytes_acked != ret)
+ xerror("mptcpi_bytes_acked %" PRIu64 ", expect %" PRIu64,
+ s.last_sample.mptcpi_bytes_acked, ret2,
+ s.last_sample.mptcpi_bytes_acked - ret2);
+ }
+
close(fd);
}
diff --git a/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh b/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh
index 1b70c0a304ce..f295a371ff14 100755
--- a/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh
+++ b/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh
@@ -1,6 +1,8 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
+. "$(dirname "${0}")/mptcp_lib.sh"
+
ret=0
sin=""
sout=""
@@ -84,6 +86,9 @@ cleanup()
rm -f "$sin" "$sout"
}
+mptcp_lib_check_mptcp
+mptcp_lib_check_kallsyms
+
ip -Version > /dev/null 2>&1
if [ $? -ne 0 ];then
echo "SKIP: Could not run test without ip tool"
@@ -182,9 +187,14 @@ do_transfer()
local_addr="0.0.0.0"
fi
+ cmsg="TIMESTAMPNS"
+ if mptcp_lib_kallsyms_has "mptcp_ioctl$"; then
+ cmsg+=",TCPINQ"
+ fi
+
timeout ${timeout_test} \
ip netns exec ${listener_ns} \
- $mptcp_connect -t ${timeout_poll} -l -M 1 -p $port -s ${srv_proto} -c TIMESTAMPNS,TCPINQ \
+ $mptcp_connect -t ${timeout_poll} -l -M 1 -p $port -s ${srv_proto} -c "${cmsg}" \
${local_addr} < "$sin" > "$sout" &
local spid=$!
@@ -192,7 +202,7 @@ do_transfer()
timeout ${timeout_test} \
ip netns exec ${connector_ns} \
- $mptcp_connect -t ${timeout_poll} -M 2 -p $port -s ${cl_proto} -c TIMESTAMPNS,TCPINQ \
+ $mptcp_connect -t ${timeout_poll} -M 2 -p $port -s ${cl_proto} -c "${cmsg}" \
$connect_addr < "$cin" > "$cout" &
local cpid=$!
@@ -249,6 +259,11 @@ do_mptcp_sockopt_tests()
{
local lret=0
+ if ! mptcp_lib_kallsyms_has "mptcp_diag_fill_info$"; then
+ echo "INFO: MPTCP sockopt not supported: SKIP"
+ return
+ fi
+
ip netns exec "$ns_sbox" ./mptcp_sockopt
lret=$?
@@ -303,6 +318,11 @@ do_tcpinq_tests()
{
local lret=0
+ if ! mptcp_lib_kallsyms_has "mptcp_ioctl$"; then
+ echo "INFO: TCP_INQ not supported: SKIP"
+ return
+ fi
+
local args
for args in "-t tcp" "-r tcp"; do
do_tcpinq_test $args
diff --git a/tools/testing/selftests/net/mptcp/pm_netlink.sh b/tools/testing/selftests/net/mptcp/pm_netlink.sh
index 89839d1ff9d8..d02e0d63a8f9 100755
--- a/tools/testing/selftests/net/mptcp/pm_netlink.sh
+++ b/tools/testing/selftests/net/mptcp/pm_netlink.sh
@@ -1,6 +1,8 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
+. "$(dirname "${0}")/mptcp_lib.sh"
+
ksft_skip=4
ret=0
@@ -34,6 +36,8 @@ cleanup()
ip netns del $ns1
}
+mptcp_lib_check_mptcp
+
ip -Version > /dev/null 2>&1
if [ $? -ne 0 ];then
echo "SKIP: Could not run test without ip tool"
@@ -69,8 +73,12 @@ check()
}
check "ip netns exec $ns1 ./pm_nl_ctl dump" "" "defaults addr list"
-check "ip netns exec $ns1 ./pm_nl_ctl limits" "accept 0
+
+default_limits="$(ip netns exec $ns1 ./pm_nl_ctl limits)"
+if mptcp_lib_expect_all_features; then
+ check "ip netns exec $ns1 ./pm_nl_ctl limits" "accept 0
subflows 2" "defaults limits"
+fi
ip netns exec $ns1 ./pm_nl_ctl add 10.0.1.1
ip netns exec $ns1 ./pm_nl_ctl add 10.0.1.2 flags subflow dev lo
@@ -117,12 +125,10 @@ ip netns exec $ns1 ./pm_nl_ctl flush
check "ip netns exec $ns1 ./pm_nl_ctl dump" "" "flush addrs"
ip netns exec $ns1 ./pm_nl_ctl limits 9 1
-check "ip netns exec $ns1 ./pm_nl_ctl limits" "accept 0
-subflows 2" "rcv addrs above hard limit"
+check "ip netns exec $ns1 ./pm_nl_ctl limits" "$default_limits" "rcv addrs above hard limit"
ip netns exec $ns1 ./pm_nl_ctl limits 1 9
-check "ip netns exec $ns1 ./pm_nl_ctl limits" "accept 0
-subflows 2" "subflows above hard limit"
+check "ip netns exec $ns1 ./pm_nl_ctl limits" "$default_limits" "subflows above hard limit"
ip netns exec $ns1 ./pm_nl_ctl limits 8 8
check "ip netns exec $ns1 ./pm_nl_ctl limits" "accept 8
@@ -172,14 +178,19 @@ subflow,backup 10.0.1.1" "set flags (backup)"
ip netns exec $ns1 ./pm_nl_ctl set 10.0.1.1 flags nobackup
check "ip netns exec $ns1 ./pm_nl_ctl dump" "id 1 flags \
subflow 10.0.1.1" " (nobackup)"
+
+# fullmesh support has been added later
ip netns exec $ns1 ./pm_nl_ctl set id 1 flags fullmesh
-check "ip netns exec $ns1 ./pm_nl_ctl dump" "id 1 flags \
+if ip netns exec $ns1 ./pm_nl_ctl dump | grep -q "fullmesh" ||
+ mptcp_lib_expect_all_features; then
+ check "ip netns exec $ns1 ./pm_nl_ctl dump" "id 1 flags \
subflow,fullmesh 10.0.1.1" " (fullmesh)"
-ip netns exec $ns1 ./pm_nl_ctl set id 1 flags nofullmesh
-check "ip netns exec $ns1 ./pm_nl_ctl dump" "id 1 flags \
+ ip netns exec $ns1 ./pm_nl_ctl set id 1 flags nofullmesh
+ check "ip netns exec $ns1 ./pm_nl_ctl dump" "id 1 flags \
subflow 10.0.1.1" " (nofullmesh)"
-ip netns exec $ns1 ./pm_nl_ctl set id 1 flags backup,fullmesh
-check "ip netns exec $ns1 ./pm_nl_ctl dump" "id 1 flags \
+ ip netns exec $ns1 ./pm_nl_ctl set id 1 flags backup,fullmesh
+ check "ip netns exec $ns1 ./pm_nl_ctl dump" "id 1 flags \
subflow,backup,fullmesh 10.0.1.1" " (backup,fullmesh)"
+fi
exit $ret
diff --git a/tools/testing/selftests/net/mptcp/simult_flows.sh b/tools/testing/selftests/net/mptcp/simult_flows.sh
index 9f22f7e5027d..36a3c9d92e20 100755
--- a/tools/testing/selftests/net/mptcp/simult_flows.sh
+++ b/tools/testing/selftests/net/mptcp/simult_flows.sh
@@ -1,6 +1,8 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
+. "$(dirname "${0}")/mptcp_lib.sh"
+
sec=$(date +%s)
rndh=$(printf %x $sec)-$(mktemp -u XXXXXX)
ns1="ns1-$rndh"
@@ -34,6 +36,8 @@ cleanup()
done
}
+mptcp_lib_check_mptcp
+
ip -Version > /dev/null 2>&1
if [ $? -ne 0 ];then
echo "SKIP: Could not run test without ip tool"
diff --git a/tools/testing/selftests/net/mptcp/userspace_pm.sh b/tools/testing/selftests/net/mptcp/userspace_pm.sh
index b1eb7bce599d..98d9e4d2d3fc 100755
--- a/tools/testing/selftests/net/mptcp/userspace_pm.sh
+++ b/tools/testing/selftests/net/mptcp/userspace_pm.sh
@@ -1,10 +1,20 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
+. "$(dirname "${0}")/mptcp_lib.sh"
+
+mptcp_lib_check_mptcp
+mptcp_lib_check_kallsyms
+
+if ! mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then
+ echo "userspace pm tests are not supported by the kernel: SKIP"
+ exit ${KSFT_SKIP}
+fi
+
ip -Version > /dev/null 2>&1
if [ $? -ne 0 ];then
echo "SKIP: Cannot not run test without ip tool"
- exit 1
+ exit ${KSFT_SKIP}
fi
ANNOUNCED=6 # MPTCP_EVENT_ANNOUNCED
@@ -905,6 +915,11 @@ test_listener()
{
print_title "Listener tests"
+ if ! mptcp_lib_kallsyms_has "mptcp_event_pm_listener$"; then
+ stdbuf -o0 -e0 printf "LISTENER events \t[SKIP] Not supported\n"
+ return
+ fi
+
# Capture events on the network namespace running the client
:>$client_evts
diff --git a/tools/testing/selftests/net/test_vxlan_nolocalbypass.sh b/tools/testing/selftests/net/test_vxlan_nolocalbypass.sh
index 46067db53068..f75212bf142c 100755
--- a/tools/testing/selftests/net/test_vxlan_nolocalbypass.sh
+++ b/tools/testing/selftests/net/test_vxlan_nolocalbypass.sh
@@ -130,7 +130,7 @@ nolocalbypass()
run_cmd "tc -n ns1 qdisc add dev lo clsact"
run_cmd "tc -n ns1 filter add dev lo ingress pref 1 handle 101 proto ip flower ip_proto udp dst_port 4790 action drop"
- run_cmd "ip -n ns1 -d link show dev vx0 | grep ' localbypass'"
+ run_cmd "ip -n ns1 -d -j link show dev vx0 | jq -e '.[][\"linkinfo\"][\"info_data\"][\"localbypass\"] == true'"
log_test $? 0 "localbypass enabled"
run_cmd "ip netns exec ns1 mausezahn vx0 -a $smac -b $dmac -c 1 -p 100 -q"
@@ -140,7 +140,7 @@ nolocalbypass()
run_cmd "ip -n ns1 link set dev vx0 type vxlan nolocalbypass"
- run_cmd "ip -n ns1 -d link show dev vx0 | grep 'nolocalbypass'"
+ run_cmd "ip -n ns1 -d -j link show dev vx0 | jq -e '.[][\"linkinfo\"][\"info_data\"][\"localbypass\"] == false'"
log_test $? 0 "localbypass disabled"
run_cmd "ip netns exec ns1 mausezahn vx0 -a $smac -b $dmac -c 1 -p 100 -q"
@@ -150,7 +150,7 @@ nolocalbypass()
run_cmd "ip -n ns1 link set dev vx0 type vxlan localbypass"
- run_cmd "ip -n ns1 -d link show dev vx0 | grep ' localbypass'"
+ run_cmd "ip -n ns1 -d -j link show dev vx0 | jq -e '.[][\"linkinfo\"][\"info_data\"][\"localbypass\"] == true'"
log_test $? 0 "localbypass enabled"
run_cmd "ip netns exec ns1 mausezahn vx0 -a $smac -b $dmac -c 1 -p 100 -q"
diff --git a/tools/testing/selftests/net/tls.c b/tools/testing/selftests/net/tls.c
index e699548d4247..a3c57004344c 100644
--- a/tools/testing/selftests/net/tls.c
+++ b/tools/testing/selftests/net/tls.c
@@ -15,6 +15,7 @@
#include <linux/tcp.h>
#include <linux/socket.h>
+#include <sys/epoll.h>
#include <sys/types.h>
#include <sys/sendfile.h>
#include <sys/socket.h>
@@ -25,6 +26,8 @@
#define TLS_PAYLOAD_MAX_LEN 16384
#define SOL_TLS 282
+static int fips_enabled;
+
struct tls_crypto_info_keys {
union {
struct tls12_crypto_info_aes_gcm_128 aes128;
@@ -235,7 +238,7 @@ FIXTURE_VARIANT(tls)
{
uint16_t tls_version;
uint16_t cipher_type;
- bool nopad;
+ bool nopad, fips_non_compliant;
};
FIXTURE_VARIANT_ADD(tls, 12_aes_gcm)
@@ -254,24 +257,28 @@ FIXTURE_VARIANT_ADD(tls, 12_chacha)
{
.tls_version = TLS_1_2_VERSION,
.cipher_type = TLS_CIPHER_CHACHA20_POLY1305,
+ .fips_non_compliant = true,
};
FIXTURE_VARIANT_ADD(tls, 13_chacha)
{
.tls_version = TLS_1_3_VERSION,
.cipher_type = TLS_CIPHER_CHACHA20_POLY1305,
+ .fips_non_compliant = true,
};
FIXTURE_VARIANT_ADD(tls, 13_sm4_gcm)
{
.tls_version = TLS_1_3_VERSION,
.cipher_type = TLS_CIPHER_SM4_GCM,
+ .fips_non_compliant = true,
};
FIXTURE_VARIANT_ADD(tls, 13_sm4_ccm)
{
.tls_version = TLS_1_3_VERSION,
.cipher_type = TLS_CIPHER_SM4_CCM,
+ .fips_non_compliant = true,
};
FIXTURE_VARIANT_ADD(tls, 12_aes_ccm)
@@ -311,6 +318,9 @@ FIXTURE_SETUP(tls)
int one = 1;
int ret;
+ if (fips_enabled && variant->fips_non_compliant)
+ SKIP(return, "Unsupported cipher in FIPS mode");
+
tls_crypto_info_init(variant->tls_version, variant->cipher_type,
&tls12);
@@ -1637,6 +1647,136 @@ TEST_F(tls_err, timeo)
}
}
+TEST_F(tls_err, poll_partial_rec)
+{
+ struct pollfd pfd = { };
+ ssize_t rec_len;
+ char rec[256];
+ char buf[128];
+
+ if (self->notls)
+ SKIP(return, "no TLS support");
+
+ pfd.fd = self->cfd2;
+ pfd.events = POLLIN;
+ EXPECT_EQ(poll(&pfd, 1, 1), 0);
+
+ memrnd(buf, sizeof(buf));
+ EXPECT_EQ(send(self->fd, buf, sizeof(buf), 0), sizeof(buf));
+ rec_len = recv(self->cfd, rec, sizeof(rec), 0);
+ EXPECT_GT(rec_len, sizeof(buf));
+
+ /* Write 100B, not the full record ... */
+ EXPECT_EQ(send(self->fd2, rec, 100, 0), 100);
+ /* ... no full record should mean no POLLIN */
+ pfd.fd = self->cfd2;
+ pfd.events = POLLIN;
+ EXPECT_EQ(poll(&pfd, 1, 1), 0);
+ /* Now write the rest, and it should all pop out of the other end. */
+ EXPECT_EQ(send(self->fd2, rec + 100, rec_len - 100, 0), rec_len - 100);
+ pfd.fd = self->cfd2;
+ pfd.events = POLLIN;
+ EXPECT_EQ(poll(&pfd, 1, 1), 1);
+ EXPECT_EQ(recv(self->cfd2, rec, sizeof(rec), 0), sizeof(buf));
+ EXPECT_EQ(memcmp(buf, rec, sizeof(buf)), 0);
+}
+
+TEST_F(tls_err, epoll_partial_rec)
+{
+ struct epoll_event ev, events[10];
+ ssize_t rec_len;
+ char rec[256];
+ char buf[128];
+ int epollfd;
+
+ if (self->notls)
+ SKIP(return, "no TLS support");
+
+ epollfd = epoll_create1(0);
+ ASSERT_GE(epollfd, 0);
+
+ memset(&ev, 0, sizeof(ev));
+ ev.events = EPOLLIN;
+ ev.data.fd = self->cfd2;
+ ASSERT_GE(epoll_ctl(epollfd, EPOLL_CTL_ADD, self->cfd2, &ev), 0);
+
+ EXPECT_EQ(epoll_wait(epollfd, events, 10, 0), 0);
+
+ memrnd(buf, sizeof(buf));
+ EXPECT_EQ(send(self->fd, buf, sizeof(buf), 0), sizeof(buf));
+ rec_len = recv(self->cfd, rec, sizeof(rec), 0);
+ EXPECT_GT(rec_len, sizeof(buf));
+
+ /* Write 100B, not the full record ... */
+ EXPECT_EQ(send(self->fd2, rec, 100, 0), 100);
+ /* ... no full record should mean no POLLIN */
+ EXPECT_EQ(epoll_wait(epollfd, events, 10, 0), 0);
+ /* Now write the rest, and it should all pop out of the other end. */
+ EXPECT_EQ(send(self->fd2, rec + 100, rec_len - 100, 0), rec_len - 100);
+ EXPECT_EQ(epoll_wait(epollfd, events, 10, 0), 1);
+ EXPECT_EQ(recv(self->cfd2, rec, sizeof(rec), 0), sizeof(buf));
+ EXPECT_EQ(memcmp(buf, rec, sizeof(buf)), 0);
+
+ close(epollfd);
+}
+
+TEST_F(tls_err, poll_partial_rec_async)
+{
+ struct pollfd pfd = { };
+ ssize_t rec_len;
+ char rec[256];
+ char buf[128];
+ char token;
+ int p[2];
+ int ret;
+
+ if (self->notls)
+ SKIP(return, "no TLS support");
+
+ ASSERT_GE(pipe(p), 0);
+
+ memrnd(buf, sizeof(buf));
+ EXPECT_EQ(send(self->fd, buf, sizeof(buf), 0), sizeof(buf));
+ rec_len = recv(self->cfd, rec, sizeof(rec), 0);
+ EXPECT_GT(rec_len, sizeof(buf));
+
+ ret = fork();
+ ASSERT_GE(ret, 0);
+
+ if (ret) {
+ int status, pid2;
+
+ close(p[1]);
+ usleep(1000); /* Give child a head start */
+
+ EXPECT_EQ(send(self->fd2, rec, 100, 0), 100);
+
+ EXPECT_EQ(read(p[0], &token, 1), 1); /* Barrier #1 */
+
+ EXPECT_EQ(send(self->fd2, rec + 100, rec_len - 100, 0),
+ rec_len - 100);
+
+ pid2 = wait(&status);
+ EXPECT_EQ(pid2, ret);
+ EXPECT_EQ(status, 0);
+ } else {
+ close(p[0]);
+
+ /* Child should sleep in poll(), never get a wake */
+ pfd.fd = self->cfd2;
+ pfd.events = POLLIN;
+ EXPECT_EQ(poll(&pfd, 1, 5), 0);
+
+ EXPECT_EQ(write(p[1], &token, 1), 1); /* Barrier #1 */
+
+ pfd.fd = self->cfd2;
+ pfd.events = POLLIN;
+ EXPECT_EQ(poll(&pfd, 1, 5), 1);
+
+ exit(!_metadata->passed);
+ }
+}
+
TEST(non_established) {
struct tls12_crypto_info_aes_gcm_256 tls12;
struct sockaddr_in addr;
@@ -1865,4 +2005,17 @@ TEST(prequeue) {
close(cfd);
}
+static void __attribute__((constructor)) fips_check(void) {
+ int res;
+ FILE *f;
+
+ f = fopen("/proc/sys/crypto/fips_enabled", "r");
+ if (f) {
+ res = fscanf(f, "%d", &fips_enabled);
+ if (res != 1)
+ ksft_print_msg("ERROR: Couldn't read /proc/sys/crypto/fips_enabled\n");
+ fclose(f);
+ }
+}
+
TEST_HARNESS_MAIN
diff --git a/tools/testing/selftests/net/vrf-xfrm-tests.sh b/tools/testing/selftests/net/vrf-xfrm-tests.sh
index 184da81f554f..452638ae8aed 100755
--- a/tools/testing/selftests/net/vrf-xfrm-tests.sh
+++ b/tools/testing/selftests/net/vrf-xfrm-tests.sh
@@ -264,60 +264,60 @@ setup_xfrm()
ip -netns host1 xfrm state add src ${HOST1_4} dst ${HOST2_4} \
proto esp spi ${SPI_1} reqid 0 mode tunnel \
replay-window 4 replay-oseq 0x4 \
- auth-trunc 'hmac(md5)' ${AUTH_1} 96 \
- enc 'cbc(des3_ede)' ${ENC_1} \
+ auth-trunc 'hmac(sha1)' ${AUTH_1} 96 \
+ enc 'cbc(aes)' ${ENC_1} \
sel src ${h1_4} dst ${h2_4} ${devarg}
ip -netns host2 xfrm state add src ${HOST1_4} dst ${HOST2_4} \
proto esp spi ${SPI_1} reqid 0 mode tunnel \
replay-window 4 replay-oseq 0x4 \
- auth-trunc 'hmac(md5)' ${AUTH_1} 96 \
- enc 'cbc(des3_ede)' ${ENC_1} \
+ auth-trunc 'hmac(sha1)' ${AUTH_1} 96 \
+ enc 'cbc(aes)' ${ENC_1} \
sel src ${h1_4} dst ${h2_4}
ip -netns host1 xfrm state add src ${HOST2_4} dst ${HOST1_4} \
proto esp spi ${SPI_2} reqid 0 mode tunnel \
replay-window 4 replay-oseq 0x4 \
- auth-trunc 'hmac(md5)' ${AUTH_2} 96 \
- enc 'cbc(des3_ede)' ${ENC_2} \
+ auth-trunc 'hmac(sha1)' ${AUTH_2} 96 \
+ enc 'cbc(aes)' ${ENC_2} \
sel src ${h2_4} dst ${h1_4} ${devarg}
ip -netns host2 xfrm state add src ${HOST2_4} dst ${HOST1_4} \
proto esp spi ${SPI_2} reqid 0 mode tunnel \
replay-window 4 replay-oseq 0x4 \
- auth-trunc 'hmac(md5)' ${AUTH_2} 96 \
- enc 'cbc(des3_ede)' ${ENC_2} \
+ auth-trunc 'hmac(sha1)' ${AUTH_2} 96 \
+ enc 'cbc(aes)' ${ENC_2} \
sel src ${h2_4} dst ${h1_4}
ip -6 -netns host1 xfrm state add src ${HOST1_6} dst ${HOST2_6} \
proto esp spi ${SPI_1} reqid 0 mode tunnel \
replay-window 4 replay-oseq 0x4 \
- auth-trunc 'hmac(md5)' ${AUTH_1} 96 \
- enc 'cbc(des3_ede)' ${ENC_1} \
+ auth-trunc 'hmac(sha1)' ${AUTH_1} 96 \
+ enc 'cbc(aes)' ${ENC_1} \
sel src ${h1_6} dst ${h2_6} ${devarg}
ip -6 -netns host2 xfrm state add src ${HOST1_6} dst ${HOST2_6} \
proto esp spi ${SPI_1} reqid 0 mode tunnel \
replay-window 4 replay-oseq 0x4 \
- auth-trunc 'hmac(md5)' ${AUTH_1} 96 \
- enc 'cbc(des3_ede)' ${ENC_1} \
+ auth-trunc 'hmac(sha1)' ${AUTH_1} 96 \
+ enc 'cbc(aes)' ${ENC_1} \
sel src ${h1_6} dst ${h2_6}
ip -6 -netns host1 xfrm state add src ${HOST2_6} dst ${HOST1_6} \
proto esp spi ${SPI_2} reqid 0 mode tunnel \
replay-window 4 replay-oseq 0x4 \
- auth-trunc 'hmac(md5)' ${AUTH_2} 96 \
- enc 'cbc(des3_ede)' ${ENC_2} \
+ auth-trunc 'hmac(sha1)' ${AUTH_2} 96 \
+ enc 'cbc(aes)' ${ENC_2} \
sel src ${h2_6} dst ${h1_6} ${devarg}
ip -6 -netns host2 xfrm state add src ${HOST2_6} dst ${HOST1_6} \
proto esp spi ${SPI_2} reqid 0 mode tunnel \
replay-window 4 replay-oseq 0x4 \
- auth-trunc 'hmac(md5)' ${AUTH_2} 96 \
- enc 'cbc(des3_ede)' ${ENC_2} \
+ auth-trunc 'hmac(sha1)' ${AUTH_2} 96 \
+ enc 'cbc(aes)' ${ENC_2} \
sel src ${h2_6} dst ${h1_6}
}
diff --git a/tools/testing/selftests/ptp/testptp.c b/tools/testing/selftests/ptp/testptp.c
index 198ad5f32187..e9438a1862ad 100644
--- a/tools/testing/selftests/ptp/testptp.c
+++ b/tools/testing/selftests/ptp/testptp.c
@@ -110,7 +110,7 @@ static long ppb_to_scaled_ppm(int ppb)
static int64_t pctns(struct ptp_clock_time *t)
{
- return t->sec * 1000000000LL + t->nsec;
+ return t->sec * NSEC_PER_SEC + t->nsec;
}
static void usage(char *progname)
@@ -134,6 +134,7 @@ static void usage(char *progname)
" 1 - external time stamp\n"
" 2 - periodic output\n"
" -n val shift the ptp clock time by 'val' nanoseconds\n"
+ " -o val phase offset (in nanoseconds) to be provided to the PHC servo\n"
" -p val enable output with a period of 'val' nanoseconds\n"
" -H val set output phase to 'val' nanoseconds (requires -p)\n"
" -w val set output pulse width to 'val' nanoseconds (requires -p)\n"
@@ -167,6 +168,7 @@ int main(int argc, char *argv[])
int adjfreq = 0x7fffffff;
int adjtime = 0;
int adjns = 0;
+ int adjphase = 0;
int capabilities = 0;
int extts = 0;
int flagtest = 0;
@@ -188,7 +190,7 @@ int main(int argc, char *argv[])
progname = strrchr(argv[0], '/');
progname = progname ? 1+progname : argv[0];
- while (EOF != (c = getopt(argc, argv, "cd:e:f:ghH:i:k:lL:n:p:P:sSt:T:w:z"))) {
+ while (EOF != (c = getopt(argc, argv, "cd:e:f:ghH:i:k:lL:n:o:p:P:sSt:T:w:z"))) {
switch (c) {
case 'c':
capabilities = 1;
@@ -228,6 +230,9 @@ int main(int argc, char *argv[])
case 'n':
adjns = atoi(optarg);
break;
+ case 'o':
+ adjphase = atoi(optarg);
+ break;
case 'p':
perout = atoll(optarg);
break;
@@ -287,7 +292,8 @@ int main(int argc, char *argv[])
" %d pulse per second\n"
" %d programmable pins\n"
" %d cross timestamping\n"
- " %d adjust_phase\n",
+ " %d adjust_phase\n"
+ " %d maximum phase adjustment (ns)\n",
caps.max_adj,
caps.n_alarm,
caps.n_ext_ts,
@@ -295,7 +301,8 @@ int main(int argc, char *argv[])
caps.pps,
caps.n_pins,
caps.cross_timestamping,
- caps.adjust_phase);
+ caps.adjust_phase,
+ caps.max_phase_adj);
}
}
@@ -317,7 +324,7 @@ int main(int argc, char *argv[])
tx.time.tv_usec = adjns;
while (tx.time.tv_usec < 0) {
tx.time.tv_sec -= 1;
- tx.time.tv_usec += 1000000000;
+ tx.time.tv_usec += NSEC_PER_SEC;
}
if (clock_adjtime(clkid, &tx) < 0) {
@@ -327,6 +334,18 @@ int main(int argc, char *argv[])
}
}
+ if (adjphase) {
+ memset(&tx, 0, sizeof(tx));
+ tx.modes = ADJ_OFFSET | ADJ_NANO;
+ tx.offset = adjphase;
+
+ if (clock_adjtime(clkid, &tx) < 0) {
+ perror("clock_adjtime");
+ } else {
+ puts("phase adjustment okay");
+ }
+ }
+
if (gettime) {
if (clock_gettime(clkid, &ts)) {
perror("clock_gettime");
@@ -502,11 +521,11 @@ int main(int argc, char *argv[])
interval = t2 - t1;
offset = (t2 + t1) / 2 - tp;
- printf("system time: %lld.%u\n",
+ printf("system time: %lld.%09u\n",
(pct+2*i)->sec, (pct+2*i)->nsec);
- printf("phc time: %lld.%u\n",
+ printf("phc time: %lld.%09u\n",
(pct+2*i+1)->sec, (pct+2*i+1)->nsec);
- printf("system time: %lld.%u\n",
+ printf("system time: %lld.%09u\n",
(pct+2*i+2)->sec, (pct+2*i+2)->nsec);
printf("system/phc clock time offset is %" PRId64 " ns\n"
"system clock time delay is %" PRId64 " ns\n",
diff --git a/tools/testing/selftests/tc-testing/config b/tools/testing/selftests/tc-testing/config
index 4638c63a339f..6e73b09c20c8 100644
--- a/tools/testing/selftests/tc-testing/config
+++ b/tools/testing/selftests/tc-testing/config
@@ -6,20 +6,18 @@ CONFIG_NF_CONNTRACK_MARK=y
CONFIG_NF_CONNTRACK_ZONES=y
CONFIG_NF_CONNTRACK_LABELS=y
CONFIG_NF_NAT=m
+CONFIG_NETFILTER_XT_TARGET_LOG=m
CONFIG_NET_SCHED=y
#
# Queueing/Scheduling
#
-CONFIG_NET_SCH_ATM=m
CONFIG_NET_SCH_CAKE=m
-CONFIG_NET_SCH_CBQ=m
CONFIG_NET_SCH_CBS=m
CONFIG_NET_SCH_CHOKE=m
CONFIG_NET_SCH_CODEL=m
CONFIG_NET_SCH_DRR=m
-CONFIG_NET_SCH_DSMARK=m
CONFIG_NET_SCH_ETF=m
CONFIG_NET_SCH_FQ=m
CONFIG_NET_SCH_FQ_CODEL=m
@@ -57,8 +55,6 @@ CONFIG_NET_CLS_FLOW=m
CONFIG_NET_CLS_FLOWER=m
CONFIG_NET_CLS_MATCHALL=m
CONFIG_NET_CLS_ROUTE4=m
-CONFIG_NET_CLS_RSVP=m
-CONFIG_NET_CLS_TCINDEX=m
CONFIG_NET_EMATCH=y
CONFIG_NET_EMATCH_STACK=32
CONFIG_NET_EMATCH_CMP=m
diff --git a/tools/testing/selftests/tc-testing/tc-tests/infra/filter.json b/tools/testing/selftests/tc-testing/tc-tests/infra/filter.json
new file mode 100644
index 000000000000..c4c778e83da2
--- /dev/null
+++ b/tools/testing/selftests/tc-testing/tc-tests/infra/filter.json
@@ -0,0 +1,25 @@
+[
+ {
+ "id": "c2b4",
+ "name": "soft lockup alarm will be not generated after delete the prio 0 filter of the chain",
+ "category": [
+ "filter",
+ "chain"
+ ],
+ "setup": [
+ "$IP link add dev $DUMMY type dummy || /bin/true",
+ "$TC qdisc add dev $DUMMY root handle 1: htb default 1",
+ "$TC chain add dev $DUMMY",
+ "$TC filter del dev $DUMMY chain 0 parent 1: prio 0"
+ ],
+ "cmdUnderTest": "$TC filter add dev $DUMMY chain 0 parent 1:",
+ "expExitCode": "2",
+ "verifyCmd": "$TC chain ls dev $DUMMY",
+ "matchPattern": "chain parent 1: chain 0",
+ "matchCount": "1",
+ "teardown": [
+ "$TC qdisc del dev $DUMMY root handle 1: htb default 1",
+ "$IP link del dev $DUMMY type dummy"
+ ]
+ }
+]
diff --git a/tools/testing/selftests/tc-testing/tc-tests/qdiscs/mq.json b/tools/testing/selftests/tc-testing/tc-tests/qdiscs/mq.json
index 44fbfc6caec7..e3d2de5c184f 100644
--- a/tools/testing/selftests/tc-testing/tc-tests/qdiscs/mq.json
+++ b/tools/testing/selftests/tc-testing/tc-tests/qdiscs/mq.json
@@ -155,5 +155,28 @@
"teardown": [
"echo \"1\" > /sys/bus/netdevsim/del_device"
]
- }
+ },
+ {
+ "id": "0531",
+ "name": "Replace mq with invalid parent ID",
+ "category": [
+ "qdisc",
+ "mq"
+ ],
+ "plugins": {
+ "requires": "nsPlugin"
+ },
+ "setup": [
+ "echo \"1 1 16\" > /sys/bus/netdevsim/new_device",
+ "$TC qdisc add dev $ETH root handle ffff: mq"
+ ],
+ "cmdUnderTest": "$TC qdisc replace dev $ETH parent ffff:fff1 handle ffff: mq",
+ "expExitCode": "2",
+ "verifyCmd": "$TC qdisc show dev $ETH",
+ "matchPattern": "qdisc [a-zA-Z0-9_]+ 0: parent ffff",
+ "matchCount": "16",
+ "teardown": [
+ "echo \"1\" > /sys/bus/netdevsim/del_device"
+ ]
+ }
]
diff --git a/tools/testing/selftests/tc-testing/tc-tests/qdiscs/sfb.json b/tools/testing/selftests/tc-testing/tc-tests/qdiscs/sfb.json
index ba2f5e79cdbf..e21c7f22c6d4 100644
--- a/tools/testing/selftests/tc-testing/tc-tests/qdiscs/sfb.json
+++ b/tools/testing/selftests/tc-testing/tc-tests/qdiscs/sfb.json
@@ -58,10 +58,10 @@
"setup": [
"$IP link add dev $DUMMY type dummy || /bin/true"
],
- "cmdUnderTest": "$TC qdisc add dev $DUMMY handle 1: root sfb db 10",
+ "cmdUnderTest": "$TC qdisc add dev $DUMMY handle 1: root sfb db 100",
"expExitCode": "0",
"verifyCmd": "$TC qdisc show dev $DUMMY",
- "matchPattern": "qdisc sfb 1: root refcnt [0-9]+ rehash 600s db 10ms",
+ "matchPattern": "qdisc sfb 1: root refcnt [0-9]+ rehash 600s db 100ms",
"matchCount": "1",
"teardown": [
"$TC qdisc del dev $DUMMY handle 1: root",
diff --git a/tools/testing/selftests/tc-testing/tdc.sh b/tools/testing/selftests/tc-testing/tdc.sh
index afb0cd86fa3d..eb357bd7923c 100755
--- a/tools/testing/selftests/tc-testing/tdc.sh
+++ b/tools/testing/selftests/tc-testing/tdc.sh
@@ -2,5 +2,6 @@
# SPDX-License-Identifier: GPL-2.0
modprobe netdevsim
+modprobe sch_teql
./tdc.py -c actions --nobuildebpf
./tdc.py -c qdisc
diff --git a/tools/testing/selftests/user_events/dyn_test.c b/tools/testing/selftests/user_events/dyn_test.c
index 8879a7b04c6a..d6979a48478f 100644
--- a/tools/testing/selftests/user_events/dyn_test.c
+++ b/tools/testing/selftests/user_events/dyn_test.c
@@ -16,42 +16,140 @@
#include "../kselftest_harness.h"
-const char *dyn_file = "/sys/kernel/tracing/dynamic_events";
-const char *clear = "!u:__test_event";
+const char *abi_file = "/sys/kernel/tracing/user_events_data";
+const char *enable_file = "/sys/kernel/tracing/events/user_events/__test_event/enable";
-static int Append(const char *value)
+static bool wait_for_delete(void)
{
- int fd = open(dyn_file, O_RDWR | O_APPEND);
- int ret = write(fd, value, strlen(value));
+ int i;
+
+ for (i = 0; i < 1000; ++i) {
+ int fd = open(enable_file, O_RDONLY);
+
+ if (fd == -1)
+ return true;
+
+ close(fd);
+ usleep(1000);
+ }
+
+ return false;
+}
+
+static int reg_event(int fd, int *check, int bit, const char *value)
+{
+ struct user_reg reg = {0};
+
+ reg.size = sizeof(reg);
+ reg.name_args = (__u64)value;
+ reg.enable_bit = bit;
+ reg.enable_addr = (__u64)check;
+ reg.enable_size = sizeof(*check);
+
+ if (ioctl(fd, DIAG_IOCSREG, &reg) == -1)
+ return -1;
+
+ return 0;
+}
+
+static int unreg_event(int fd, int *check, int bit)
+{
+ struct user_unreg unreg = {0};
+
+ unreg.size = sizeof(unreg);
+ unreg.disable_bit = bit;
+ unreg.disable_addr = (__u64)check;
+
+ return ioctl(fd, DIAG_IOCSUNREG, &unreg);
+}
+
+static int parse(int *check, const char *value)
+{
+ int fd = open(abi_file, O_RDWR);
+ int ret;
+
+ if (fd == -1)
+ return -1;
+
+ /* Until we have persist flags via dynamic events, use the base name */
+ if (value[0] != 'u' || value[1] != ':') {
+ close(fd);
+ return -1;
+ }
+
+ ret = reg_event(fd, check, 31, value + 2);
+
+ if (ret != -1) {
+ if (unreg_event(fd, check, 31) == -1)
+ printf("WARN: Couldn't unreg event\n");
+ }
close(fd);
+
return ret;
}
-#define CLEAR() \
+static int check_match(int *check, const char *first, const char *second, bool *match)
+{
+ int fd = open(abi_file, O_RDWR);
+ int ret = -1;
+
+ if (fd == -1)
+ return -1;
+
+ if (reg_event(fd, check, 31, first) == -1)
+ goto cleanup;
+
+ if (reg_event(fd, check, 30, second) == -1) {
+ if (errno == EADDRINUSE) {
+ /* Name is in use, with different fields */
+ *match = false;
+ ret = 0;
+ }
+
+ goto cleanup;
+ }
+
+ *match = true;
+ ret = 0;
+cleanup:
+ unreg_event(fd, check, 31);
+ unreg_event(fd, check, 30);
+
+ close(fd);
+
+ wait_for_delete();
+
+ return ret;
+}
+
+#define TEST_MATCH(x, y) \
do { \
- int ret = Append(clear); \
- if (ret == -1) \
- ASSERT_EQ(ENOENT, errno); \
+ bool match; \
+ ASSERT_NE(-1, check_match(&self->check, x, y, &match)); \
+ ASSERT_EQ(true, match); \
} while (0)
-#define TEST_PARSE(x) \
+#define TEST_NMATCH(x, y) \
do { \
- ASSERT_NE(-1, Append(x)); \
- CLEAR(); \
+ bool match; \
+ ASSERT_NE(-1, check_match(&self->check, x, y, &match)); \
+ ASSERT_EQ(false, match); \
} while (0)
-#define TEST_NPARSE(x) ASSERT_EQ(-1, Append(x))
+#define TEST_PARSE(x) ASSERT_NE(-1, parse(&self->check, x))
+
+#define TEST_NPARSE(x) ASSERT_EQ(-1, parse(&self->check, x))
FIXTURE(user) {
+ int check;
};
FIXTURE_SETUP(user) {
- CLEAR();
}
FIXTURE_TEARDOWN(user) {
- CLEAR();
+ wait_for_delete();
}
TEST_F(user, basic_types) {
@@ -95,33 +193,30 @@ TEST_F(user, size_types) {
TEST_NPARSE("u:__test_event char a 20");
}
-TEST_F(user, flags) {
- /* Should work */
- TEST_PARSE("u:__test_event:BPF_ITER u32 a");
- /* Forward compat */
- TEST_PARSE("u:__test_event:BPF_ITER,FLAG_FUTURE u32 a");
-}
-
TEST_F(user, matching) {
- /* Register */
- ASSERT_NE(-1, Append("u:__test_event struct custom a 20"));
- /* Should not match */
- TEST_NPARSE("!u:__test_event struct custom b");
- /* Should match */
- TEST_PARSE("!u:__test_event struct custom a");
- /* Multi field reg */
- ASSERT_NE(-1, Append("u:__test_event u32 a; u32 b"));
- /* Non matching cases */
- TEST_NPARSE("!u:__test_event u32 a");
- TEST_NPARSE("!u:__test_event u32 b");
- TEST_NPARSE("!u:__test_event u32 a; u32 ");
- TEST_NPARSE("!u:__test_event u32 a; u32 a");
- /* Matching case */
- TEST_PARSE("!u:__test_event u32 a; u32 b");
- /* Register */
- ASSERT_NE(-1, Append("u:__test_event u32 a; u32 b"));
- /* Ensure trailing semi-colon case */
- TEST_PARSE("!u:__test_event u32 a; u32 b;");
+ /* Single name matches */
+ TEST_MATCH("__test_event u32 a",
+ "__test_event u32 a");
+
+ /* Multiple names match */
+ TEST_MATCH("__test_event u32 a; u32 b",
+ "__test_event u32 a; u32 b");
+
+ /* Multiple names match with dangling ; */
+ TEST_MATCH("__test_event u32 a; u32 b",
+ "__test_event u32 a; u32 b;");
+
+ /* Single name doesn't match */
+ TEST_NMATCH("__test_event u32 a",
+ "__test_event u32 b");
+
+ /* Multiple names don't match */
+ TEST_NMATCH("__test_event u32 a; u32 b",
+ "__test_event u32 b; u32 a");
+
+ /* Types don't match */
+ TEST_NMATCH("__test_event u64 a; u64 b",
+ "__test_event u32 a; u32 b");
}
int main(int argc, char **argv)
diff --git a/tools/testing/selftests/user_events/ftrace_test.c b/tools/testing/selftests/user_events/ftrace_test.c
index 7c99cef94a65..eb6904d89f14 100644
--- a/tools/testing/selftests/user_events/ftrace_test.c
+++ b/tools/testing/selftests/user_events/ftrace_test.c
@@ -102,30 +102,56 @@ err:
return -1;
}
+static bool wait_for_delete(void)
+{
+ int i;
+
+ for (i = 0; i < 1000; ++i) {
+ int fd = open(enable_file, O_RDONLY);
+
+ if (fd == -1)
+ return true;
+
+ close(fd);
+ usleep(1000);
+ }
+
+ return false;
+}
+
static int clear(int *check)
{
struct user_unreg unreg = {0};
+ int fd;
unreg.size = sizeof(unreg);
unreg.disable_bit = 31;
unreg.disable_addr = (__u64)check;
- int fd = open(data_file, O_RDWR);
+ fd = open(data_file, O_RDWR);
if (fd == -1)
return -1;
if (ioctl(fd, DIAG_IOCSUNREG, &unreg) == -1)
if (errno != ENOENT)
- return -1;
-
- if (ioctl(fd, DIAG_IOCSDEL, "__test_event") == -1)
- if (errno != ENOENT)
- return -1;
+ goto fail;
+
+ if (ioctl(fd, DIAG_IOCSDEL, "__test_event") == -1) {
+ if (errno == EBUSY) {
+ if (!wait_for_delete())
+ goto fail;
+ } else if (errno != ENOENT)
+ goto fail;
+ }
close(fd);
return 0;
+fail:
+ close(fd);
+
+ return -1;
}
static int check_print_fmt(const char *event, const char *expected, int *check)
@@ -155,9 +181,8 @@ static int check_print_fmt(const char *event, const char *expected, int *check)
/* Register should work */
ret = ioctl(fd, DIAG_IOCSREG, &reg);
- close(fd);
-
if (ret != 0) {
+ close(fd);
printf("Reg failed in fmt\n");
return ret;
}
@@ -165,6 +190,8 @@ static int check_print_fmt(const char *event, const char *expected, int *check)
/* Ensure correct print_fmt */
ret = get_print_fmt(print_fmt, sizeof(print_fmt));
+ close(fd);
+
if (ret != 0)
return ret;
@@ -228,6 +255,12 @@ TEST_F(user, register_events) {
ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, &reg));
ASSERT_EQ(0, reg.write_index);
+ /* Multiple registers to same name but different args should fail */
+ reg.enable_bit = 29;
+ reg.name_args = (__u64)"__test_event u32 field1;";
+ ASSERT_EQ(-1, ioctl(self->data_fd, DIAG_IOCSREG, &reg));
+ ASSERT_EQ(EADDRINUSE, errno);
+
/* Ensure disabled */
self->enable_fd = open(enable_file, O_RDWR);
ASSERT_NE(-1, self->enable_fd);
@@ -250,10 +283,10 @@ TEST_F(user, register_events) {
unreg.disable_bit = 30;
ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSUNREG, &unreg));
- /* Delete should work only after close and unregister */
+ /* Delete should have been auto-done after close and unregister */
close(self->data_fd);
- self->data_fd = open(data_file, O_RDWR);
- ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSDEL, "__test_event"));
+
+ ASSERT_EQ(true, wait_for_delete());
}
TEST_F(user, write_events) {
@@ -310,6 +343,39 @@ TEST_F(user, write_events) {
ASSERT_EQ(EINVAL, errno);
}
+TEST_F(user, write_empty_events) {
+ struct user_reg reg = {0};
+ struct iovec io[1];
+ int before = 0, after = 0;
+
+ reg.size = sizeof(reg);
+ reg.name_args = (__u64)"__test_event";
+ reg.enable_bit = 31;
+ reg.enable_addr = (__u64)&self->check;
+ reg.enable_size = sizeof(self->check);
+
+ io[0].iov_base = &reg.write_index;
+ io[0].iov_len = sizeof(reg.write_index);
+
+ /* Register should work */
+ ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, &reg));
+ ASSERT_EQ(0, reg.write_index);
+ ASSERT_EQ(0, self->check);
+
+ /* Enable event */
+ self->enable_fd = open(enable_file, O_RDWR);
+ ASSERT_NE(-1, write(self->enable_fd, "1", sizeof("1")))
+
+ /* Event should now be enabled */
+ ASSERT_EQ(1 << reg.enable_bit, self->check);
+
+ /* Write should make it out to ftrace buffers */
+ before = trace_bytes();
+ ASSERT_NE(-1, writev(self->data_fd, (const struct iovec *)io, 1));
+ after = trace_bytes();
+ ASSERT_GT(after, before);
+}
+
TEST_F(user, write_fault) {
struct user_reg reg = {0};
struct iovec io[2];
diff --git a/tools/testing/selftests/user_events/perf_test.c b/tools/testing/selftests/user_events/perf_test.c
index a070258d4449..8b09be566fa2 100644
--- a/tools/testing/selftests/user_events/perf_test.c
+++ b/tools/testing/selftests/user_events/perf_test.c
@@ -81,6 +81,32 @@ static int get_offset(void)
return offset;
}
+static int clear(int *check)
+{
+ struct user_unreg unreg = {0};
+
+ unreg.size = sizeof(unreg);
+ unreg.disable_bit = 31;
+ unreg.disable_addr = (__u64)check;
+
+ int fd = open(data_file, O_RDWR);
+
+ if (fd == -1)
+ return -1;
+
+ if (ioctl(fd, DIAG_IOCSUNREG, &unreg) == -1)
+ if (errno != ENOENT)
+ return -1;
+
+ if (ioctl(fd, DIAG_IOCSDEL, "__test_event") == -1)
+ if (errno != ENOENT)
+ return -1;
+
+ close(fd);
+
+ return 0;
+}
+
FIXTURE(user) {
int data_fd;
int check;
@@ -93,6 +119,9 @@ FIXTURE_SETUP(user) {
FIXTURE_TEARDOWN(user) {
close(self->data_fd);
+
+ if (clear(&self->check) != 0)
+ printf("WARNING: Clear didn't work!\n");
}
TEST_F(user, perf_write) {
@@ -160,6 +189,59 @@ TEST_F(user, perf_write) {
ASSERT_EQ(0, self->check);
}
+TEST_F(user, perf_empty_events) {
+ struct perf_event_attr pe = {0};
+ struct user_reg reg = {0};
+ struct perf_event_mmap_page *perf_page;
+ int page_size = sysconf(_SC_PAGESIZE);
+ int id, fd;
+ __u32 *val;
+
+ reg.size = sizeof(reg);
+ reg.name_args = (__u64)"__test_event";
+ reg.enable_bit = 31;
+ reg.enable_addr = (__u64)&self->check;
+ reg.enable_size = sizeof(self->check);
+
+ /* Register should work */
+ ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, &reg));
+ ASSERT_EQ(0, reg.write_index);
+ ASSERT_EQ(0, self->check);
+
+ /* Id should be there */
+ id = get_id();
+ ASSERT_NE(-1, id);
+
+ pe.type = PERF_TYPE_TRACEPOINT;
+ pe.size = sizeof(pe);
+ pe.config = id;
+ pe.sample_type = PERF_SAMPLE_RAW;
+ pe.sample_period = 1;
+ pe.wakeup_events = 1;
+
+ /* Tracepoint attach should work */
+ fd = perf_event_open(&pe, 0, -1, -1, 0);
+ ASSERT_NE(-1, fd);
+
+ perf_page = mmap(NULL, page_size * 2, PROT_READ, MAP_SHARED, fd, 0);
+ ASSERT_NE(MAP_FAILED, perf_page);
+
+ /* Status should be updated */
+ ASSERT_EQ(1 << reg.enable_bit, self->check);
+
+ /* Ensure write shows up at correct offset */
+ ASSERT_NE(-1, write(self->data_fd, &reg.write_index,
+ sizeof(reg.write_index)));
+ val = (void *)(((char *)perf_page) + perf_page->data_offset);
+ ASSERT_EQ(PERF_RECORD_SAMPLE, *val);
+
+ munmap(perf_page, page_size * 2);
+ close(fd);
+
+ /* Status should be updated */
+ ASSERT_EQ(0, self->check);
+}
+
int main(int argc, char **argv)
{
return test_harness_run(argc, argv);
diff --git a/tools/virtio/ringtest/.gitignore b/tools/virtio/ringtest/.gitignore
new file mode 100644
index 000000000000..100b9e30c0f4
--- /dev/null
+++ b/tools/virtio/ringtest/.gitignore
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0-only
+/noring
+/ptr_ring
+/ring
+/virtio_ring_0_9
+/virtio_ring_inorder
+/virtio_ring_poll
diff --git a/tools/virtio/ringtest/main.h b/tools/virtio/ringtest/main.h
index b68920d52750..d18dd317e27f 100644
--- a/tools/virtio/ringtest/main.h
+++ b/tools/virtio/ringtest/main.h
@@ -8,6 +8,7 @@
#ifndef MAIN_H
#define MAIN_H
+#include <assert.h>
#include <stdbool.h>
extern int param;
@@ -95,6 +96,8 @@ extern unsigned ring_size;
#define cpu_relax() asm ("rep; nop" ::: "memory")
#elif defined(__s390x__)
#define cpu_relax() barrier()
+#elif defined(__aarch64__)
+#define cpu_relax() asm ("yield" ::: "memory")
#else
#define cpu_relax() assert(0)
#endif
@@ -112,6 +115,8 @@ static inline void busy_wait(void)
#if defined(__x86_64__) || defined(__i386__)
#define smp_mb() asm volatile("lock; addl $0,-132(%%rsp)" ::: "memory", "cc")
+#elif defined(__aarch64__)
+#define smp_mb() asm volatile("dmb ish" ::: "memory")
#else
/*
* Not using __ATOMIC_SEQ_CST since gcc docs say they are only synchronized
@@ -136,10 +141,16 @@ static inline void busy_wait(void)
#if defined(__i386__) || defined(__x86_64__) || defined(__s390x__)
#define smp_wmb() barrier()
+#elif defined(__aarch64__)
+#define smp_wmb() asm volatile("dmb ishst" ::: "memory")
#else
#define smp_wmb() smp_release()
#endif
+#ifndef __always_inline
+#define __always_inline inline __attribute__((always_inline))
+#endif
+
static __always_inline
void __read_once_size(const volatile void *p, void *res, int size)
{
diff --git a/tools/virtio/virtio-trace/README b/tools/virtio/virtio-trace/README
index 4fb9368bf751..0127ff0c54b0 100644
--- a/tools/virtio/virtio-trace/README
+++ b/tools/virtio/virtio-trace/README
@@ -95,7 +95,7 @@ Run
1) Enable ftrace in the guest
<Example>
- # echo 1 > /sys/kernel/debug/tracing/events/sched/enable
+ # echo 1 > /sys/kernel/tracing/events/sched/enable
2) Run trace agent in the guest
This agent must be operated as root.
diff --git a/tools/virtio/virtio-trace/trace-agent.c b/tools/virtio/virtio-trace/trace-agent.c
index cdfe77c2b4c8..7e2d9bbf0b84 100644
--- a/tools/virtio/virtio-trace/trace-agent.c
+++ b/tools/virtio/virtio-trace/trace-agent.c
@@ -18,8 +18,9 @@
#define PIPE_DEF_BUFS 16
#define PIPE_MIN_SIZE (PAGE_SIZE*PIPE_DEF_BUFS)
#define PIPE_MAX_SIZE (1024*1024)
-#define READ_PATH_FMT \
- "/sys/kernel/debug/tracing/per_cpu/cpu%d/trace_pipe_raw"
+#define TRACEFS "/sys/kernel/tracing"
+#define DEBUGFS "/sys/kernel/debug/tracing"
+#define READ_PATH_FMT "%s/per_cpu/cpu%d/trace_pipe_raw"
#define WRITE_PATH_FMT "/dev/virtio-ports/trace-path-cpu%d"
#define CTL_PATH "/dev/virtio-ports/agent-ctl-path"
@@ -120,9 +121,12 @@ static const char *make_path(int cpu_num, bool this_is_write_path)
if (this_is_write_path)
/* write(output) path */
ret = snprintf(buf, PATH_MAX, WRITE_PATH_FMT, cpu_num);
- else
+ else {
/* read(input) path */
- ret = snprintf(buf, PATH_MAX, READ_PATH_FMT, cpu_num);
+ ret = snprintf(buf, PATH_MAX, READ_PATH_FMT, TRACEFS, cpu_num);
+ if (ret > 0 && access(buf, F_OK) != 0)
+ ret = snprintf(buf, PATH_MAX, READ_PATH_FMT, DEBUGFS, cpu_num);
+ }
if (ret <= 0) {
pr_err("Failed to generate %s path(CPU#%d):%d\n",