From nobody Thu Oct 2 18:21:34 2025 Received: from mail-wm1-f50.google.com (mail-wm1-f50.google.com [209.85.128.50]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 16E4E2BF00D for ; Fri, 12 Sep 2025 19:53:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.50 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757706838; cv=none; b=dOwYQt5Nh6N9kfMSz/GbtThm1W/+gbMu69BvsiGiIgLIegzXGVhnp6ScjIBZxRs7u9oJJsrDPT0E2rCHydFpF9Orp4ZhOFdwJ5TVEWJ4gcSXY8n7RHWkWpB2CYUTlJt54RZ4aPqFRf7NbTWXuFWseiCsy0zOtXRisHsCQZy/lZ8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757706838; c=relaxed/simple; bh=lhd5AYLmKg8v4K7bBXuozBSRlAkojKZ1+DM9PPiC2jU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=SI96+cvJfe9GHFKzXfV2h/6i6dxjc8AeCt4XH48wq3rdujJD5DBpF3AWZrcQsh0aqcBcu8jYFiafzevuVB8JT0EVomX2Chy3JvfBLzUB4noO6HXn3zeBq0vb2Wce+CxVlcfF+6kwOpI1n8cW4owjPLbx5a7AVkMbyf3VTX7cv9E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=GJoqqZmO; arc=none smtp.client-ip=209.85.128.50 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="GJoqqZmO" Received: by mail-wm1-f50.google.com with SMTP id 5b1f17b1804b1-45b9a856dc2so15375775e9.0 for ; Fri, 12 Sep 2025 12:53:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1757706834; x=1758311634; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=AdhvlJqUr3WoGW1dbO0ZFsF3L6hbFYftz4yhGQrniP4=; b=GJoqqZmOY7G/4cLlS6yOMlnXof76O2fBigIFhHu2/SXCvFBo/2TJhAkZyIM/E0Alne QKgveCCwl9p2lEU+uSADoKujeHBN+awNfdBRu8Lua713K6IElfLgEnlVLyYkIdwOlQpr gUu3l4YnccAOt2DkJo52vXBNlnDC7ZwGbsDZ0Zmve0485U0XRd/FwlQFpZpiNKQJN7bH 5tk2K85F0Ra1lVzXNSUDMnpp6P80gQJaS+sPIQovMdlNtJsL73jVr4Hu+NgOcgkqh355 8zqgIaWZqc4xEd9HRbBYTdgk6R13takIchQmC2JiouHrH47D8jWmezi5XWb/1lnKnTnB UkoA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1757706834; x=1758311634; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=AdhvlJqUr3WoGW1dbO0ZFsF3L6hbFYftz4yhGQrniP4=; b=pACSjaAtLunv2sIBqPx7ZKNxatKUtDRxofnwF1ZPERXSjUxHFsNlQvL5uWPhIbXO8U WImPO+z9F0mFKOi+3KHSVMhewSRVzxjd4Xo6JjiPwPX5vqo/GL4UkjcH9sVJy3kwLkuF ONkMctEo6AA43Nnrhw3y8a6jlijui97AGd7Ds3kHox+ZJggskvawuddEz8d1YFGvhbW3 htvIb0xiS39+OsaWLThrws/O/4rpsPqguW1NY8QC7+lxe1h1W6I6400LUrs3iHRSBGfN X7/lJ0WsCSat1gF2AoYaXCatJhVIdmVdCjWAwnWwdqcM2tloV96PXhkpTEdBoVzez6z7 D6iw== X-Forwarded-Encrypted: i=1; AJvYcCX7uDGnZJILvqyYgm1cUZjHHnipx2ueIjjpcGkJ4Q6BIb3fpLC0TRUK0qNgCnGo/nFjYR5SRAJugBLWM0o=@vger.kernel.org X-Gm-Message-State: AOJu0YyB9CeFoyu9FRtrenk7E5V0N6OQpZ8P12uccrN9JTH2AF3bRWtO Qv75Tua4FvD+88+9BZ812CLy7gLLZKsfZwEqvIrBuzz/tzVXKOUoj44s X-Gm-Gg: ASbGncslg+kFhfauhVQhOT3SJ1ib8bcjnlJW3CyQKyVcgW5uwq1wGsa/Cmz0AqHsQ+r 34x7sRuB3bLgdHhvABGSzQM0e4IpTnzgiibpr330PK9NRTwKjNWVWT/ZEcm+IEb9aWdmTBoDQ1q nYg82zgBc7aEbMDYvpK1ugU/sAXdGpZBqUxwzI7RsN++dACguwGqxrHv7+EWmVkonQvlRBKhfUa 9PHNTeF7cQLFsTsT8++ya0ksCSk8Qcd22EJCPSkWZyuNNCw8GsQbCDd2To5tZKbVBeDsA42oDyt HfuSgIw8NHO37eWQz6fGKlPVFyUgPoRSBII8SbvXbrVW5ZUq9jy1dQHcoz8tWONyShz09WG2PJg Wy6Yz4pAifZfOk/H91O0O9BUogeteEsyeTApxp+WoV0AdfQm+n0BxGP43nGjDeA== X-Google-Smtp-Source: AGHT+IFqrA3KZsShkhOTFLrSGP4/PH2y/guZeiY2IMih0gP0HYC7djwhcyI0ThOjanigZ0fIM1AgtA== X-Received: by 2002:a05:600c:4454:b0:45d:cfee:7058 with SMTP id 5b1f17b1804b1-45f211e5f98mr44613895e9.22.1757706834189; Fri, 12 Sep 2025 12:53:54 -0700 (PDT) Received: from yanesskka.. (node-188-187-35-212.domolink.tula.net. [212.35.187.188]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45e017bfd14sm74650375e9.21.2025.09.12.12.53.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 12 Sep 2025 12:53:53 -0700 (PDT) From: Yana Bashlykova To: "David S. Miller" Cc: Yana Bashlykova , Eric Dumazet , Jakub Kicinski , Paolo Abeni , linux-kernel@vger.kernel.org, netdev@vger.kernel.org, lvc-project@linuxtesting.org Subject: [PATCH 6.1 01/15] genetlink: add sysfs test module for Generic Netlink Date: Fri, 12 Sep 2025 22:53:24 +0300 Message-Id: <20250912195339.20635-2-yana2bsh@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250912195339.20635-1-yana2bsh@gmail.com> References: <20250912195339.20635-1-yana2bsh@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add a test module that creates sysfs interfaces for Generic Netlink testing: - /sys/kernel/genl_test with value/message/info attributes - /sys/kernel/parallel_genl with message attribute - /sys/kernel/third_genl with message attribute Implements basic read/write operations with proper error handling and clean= up. Will be used as foundation for netlink testing infrastructure. Signed-off-by: Yana Bashlykova --- drivers/net/Kconfig | 2 + drivers/net/Makefile | 2 + drivers/net/genetlink/Kconfig | 8 + drivers/net/genetlink/Makefile | 3 + .../net-pf-16-proto-16-family-PARALLEL_GENL.c | 288 ++++++++++++++++++ 5 files changed, 303 insertions(+) create mode 100644 drivers/net/genetlink/Kconfig create mode 100644 drivers/net/genetlink/Makefile create mode 100644 drivers/net/genetlink/net-pf-16-proto-16-family-PARALLE= L_GENL.c diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 9e63b8c43f3e..2f5f74185da5 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -631,4 +631,6 @@ config NETDEV_LEGACY_INIT Drivers that call netdev_boot_setup_check() should select this symbol, everything else no longer needs it. =20 +source "drivers/net/genetlink/Kconfig" + endif # NETDEVICES diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 6ce076462dbf..934dff748416 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -89,3 +89,5 @@ thunderbolt-net-y +=3D thunderbolt.o obj-$(CONFIG_USB4_NET) +=3D thunderbolt-net.o obj-$(CONFIG_NETDEVSIM) +=3D netdevsim/ obj-$(CONFIG_NET_FAILOVER) +=3D net_failover.o + +obj-$(CONFIG_NETLINK_TEST) +=3D genetlink/ diff --git a/drivers/net/genetlink/Kconfig b/drivers/net/genetlink/Kconfig new file mode 100644 index 000000000000..e1fd8da50488 --- /dev/null +++ b/drivers/net/genetlink/Kconfig @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0 + +config NETLINK_TEST + tristate "Test module for netlink communication" + depends on NET + help + This module provides testing interface for netlink communication. + Used by selftests in tools/testing/selftests/net/. diff --git a/drivers/net/genetlink/Makefile b/drivers/net/genetlink/Makefile new file mode 100644 index 000000000000..0336eac4cc28 --- /dev/null +++ b/drivers/net/genetlink/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_NETLINK_TEST) +=3D net-pf-16-proto-16-family-PARALLEL_GENL.o diff --git a/drivers/net/genetlink/net-pf-16-proto-16-family-PARALLEL_GENL.= c b/drivers/net/genetlink/net-pf-16-proto-16-family-PARALLEL_GENL.c new file mode 100644 index 000000000000..c50c0daae392 --- /dev/null +++ b/drivers/net/genetlink/net-pf-16-proto-16-family-PARALLEL_GENL.c @@ -0,0 +1,288 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); + +static struct kobject *kobj_genl_test; +static struct device *dev_genl_test; +static struct kobject *kobj_parallel_genl; +static struct kobject *kobj_third_genl; + +#define MAX_DATA_LEN 256 + +struct { + char genl_test_message[MAX_DATA_LEN]; + char genl_test_info[MAX_DATA_LEN]; + u32 genl_test_value; + char parallel_genl_message[MAX_DATA_LEN]; + char third_genl_message[MAX_DATA_LEN]; +} + +sysfs_data =3D { + .genl_test_message =3D "default", + .genl_test_info =3D "default", + .genl_test_value =3D -20, + .parallel_genl_message =3D "default", + .third_genl_message =3D "default", +}; + +static ssize_t show_genl_test_info(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%s\n", sysfs_data.genl_test_info); +} + +static ssize_t store_genl_test_info(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + snprintf(sysfs_data.genl_test_info, sizeof(sysfs_data.genl_test_info), + "%.*s", (int)min(count, sizeof(sysfs_data.genl_test_info) - 1), + buf); + return count; +} + +static ssize_t show_genl_test_message(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "%s", sysfs_data.genl_test_message); +} + +static ssize_t store_genl_test_message(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + size_t len =3D min(count, sizeof(sysfs_data.genl_test_message) - 1); + + strncpy(sysfs_data.genl_test_message, buf, len); + sysfs_data.genl_test_message[len] =3D '\0'; + return count; +} + +static ssize_t show_genl_test_value(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "%d", sysfs_data.genl_test_value); +} + +static ssize_t store_genl_test_value(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + int rt; + + rt =3D kstrtouint(buf, 0, &sysfs_data.genl_test_value); + return count; +} + +static ssize_t show_parallel_genl_message(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + return sprintf(buf, "%s", sysfs_data.parallel_genl_message); +} + +static ssize_t store_parallel_genl_message(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + size_t len =3D min(count, sizeof(sysfs_data.parallel_genl_message) - 1); + + strncpy(sysfs_data.parallel_genl_message, buf, len); + sysfs_data.parallel_genl_message[len] =3D '\0'; + return count; +} + +static ssize_t show_third_genl_message(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "%s", sysfs_data.third_genl_message); +} + +static ssize_t store_third_genl_message(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + size_t len =3D min(count, sizeof(sysfs_data.third_genl_message) - 1); + + strncpy(sysfs_data.third_genl_message, buf, len); + sysfs_data.third_genl_message[len] =3D '\0'; + return count; +} + +static struct device_attribute dev_attr_info_genl_test =3D + __ATTR(some_info, 0664, show_genl_test_info, store_genl_test_info); + +static struct kobj_attribute my_attr_str_genl_test =3D + __ATTR(message, 0664, show_genl_test_message, store_genl_test_message); + +static struct kobj_attribute my_attr_u32_genl_test =3D + __ATTR(value, 0664, show_genl_test_value, store_genl_test_value); + +static struct kobj_attribute my_attr_str_parallel_genl =3D + __ATTR(message, 0664, show_parallel_genl_message, store_parallel_genl_mes= sage); + +static struct kobj_attribute my_attr_str_third_genl =3D + __ATTR(message, 0664, show_third_genl_message, store_third_genl_message); + +static int __init init_sysfs_third_genl(void) +{ + int ret; + + kobj_third_genl =3D kobject_create_and_add("third_genl", kernel_kobj); + + if (!kobj_third_genl) { + pr_err("%s: Failed to create kobject\n", __func__); + return -ENOMEM; + } + + ret =3D sysfs_create_file(kobj_third_genl, &my_attr_str_third_genl.attr); + if (ret) { + pr_err("%s: Failed to create sysfs file\n", __func__); + goto err_sysfs; + } + + return 0; + +err_sysfs: + kobject_put(kobj_third_genl); + return ret; +} + +static int __init init_sysfs_parallel_genl(void) +{ + int ret; + + kobj_parallel_genl =3D + kobject_create_and_add("parallel_genl", kernel_kobj); + + if (!kobj_parallel_genl) { + pr_err("%s: Failed to create kobject\n", __func__); + return -ENOMEM; + } + + ret =3D sysfs_create_file(kobj_parallel_genl, + &my_attr_str_parallel_genl.attr); + if (ret) { + pr_err("%s: Failed to create sysfs file\n", __func__); + goto err_sysfs; + } + + return 0; + +err_sysfs: + kobject_put(kobj_parallel_genl); + return ret; +} + +static int __init init_sysfs_genl_test(void) +{ + int ret; + + kobj_genl_test =3D kobject_create_and_add("genl_test", kernel_kobj); + dev_genl_test =3D kobj_to_dev(kobj_genl_test); + + if (!kobj_genl_test) { + pr_err("%s: Failed to create kobject\n", __func__); + return -ENOMEM; + } + + ret =3D sysfs_create_file(kobj_genl_test, &my_attr_u32_genl_test.attr); + if (ret) { + pr_err("%s: Failed to create sysfs file 1\n", __func__); + goto err_sysfs; + } + + ret =3D sysfs_create_file(kobj_genl_test, &my_attr_str_genl_test.attr); + if (ret) { + pr_err("%s: Failed to create sysfs file 2\n", __func__); + goto err_sysfs_2; + } + + ret =3D device_create_file(dev_genl_test, &dev_attr_info_genl_test); + if (ret) { + pr_err("%s: Failed to create device file\n", __func__); + goto err_device; + }; + + return 0; + +err_device: + sysfs_remove_file(kobj_genl_test, &my_attr_str_genl_test.attr); +err_sysfs_2: + sysfs_remove_file(kobj_genl_test, &my_attr_u32_genl_test.attr); +err_sysfs: + kobject_put(kobj_genl_test); + return ret; +} + +static int __init module_netlink_init(void) +{ + int ret; + + ret =3D init_sysfs_genl_test(); + if (ret) + goto err_sysfs; + + ret =3D init_sysfs_parallel_genl(); + if (ret) + goto err_sysfs; + + ret =3D init_sysfs_third_genl(); + if (ret) + goto err_sysfs; + + return 0; + +err_sysfs: + sysfs_remove_file(kobj_genl_test, &my_attr_u32_genl_test.attr); + sysfs_remove_file(kobj_genl_test, &my_attr_str_genl_test.attr); + device_remove_file(dev_genl_test, &dev_attr_info_genl_test); + kobject_put(kobj_genl_test); + + sysfs_remove_file(kobj_parallel_genl, &my_attr_str_parallel_genl.attr); + kobject_put(kobj_parallel_genl); + + sysfs_remove_file(kobj_third_genl, &my_attr_str_third_genl.attr); + kobject_put(kobj_third_genl); + return ret; +} + +static void __exit module_netlink_exit(void) +{ + sysfs_remove_file(kobj_genl_test, &my_attr_u32_genl_test.attr); + sysfs_remove_file(kobj_genl_test, &my_attr_str_genl_test.attr); + device_remove_file(dev_genl_test, &dev_attr_info_genl_test); + kobject_put(kobj_genl_test); + + sysfs_remove_file(kobj_parallel_genl, &my_attr_str_parallel_genl.attr); + kobject_put(kobj_parallel_genl); + + sysfs_remove_file(kobj_third_genl, &my_attr_str_third_genl.attr); + kobject_put(kobj_third_genl); + pr_info("%s: Module is exited\n", __func__); +} + +module_init(module_netlink_init); +module_exit(module_netlink_exit); --=20 2.34.1 From nobody Thu Oct 2 18:21:34 2025 Received: from mail-wr1-f48.google.com (mail-wr1-f48.google.com [209.85.221.48]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 54A77223316 for ; Fri, 12 Sep 2025 19:53:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.48 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757706839; cv=none; b=Jq5/zBEU2b+T63VWWeRoG03wyuCMKYljID18ysnGbWkg4Xbf3utsUA+ilE01MwYNCKZIrJfZRUpidd2gQC0z/JbNyPr72mQSeINPCWdm8HtwS8Nb8d6X0jYB4G82YwZ1soXhSXN/ZzQKZ4sbdEowX00ioV3EYNglnWoLiq7Ql2k= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757706839; c=relaxed/simple; bh=/Cagp1ejGJLtDHkq62m/CGsX+fy3cFxlMkW0wgB3n0M=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=FxSe3ynlUYSb1H3C2O8TJaKYXOQ6KdlYzQhF5mw+Ytg63JaoRenp+DSafZC4l7F3NhfuMJgG0GWouXYmOGLrMrQZeiB8dUKBCSvw7S8fNjgLZVtZaPu7L7ryna7ln35hSLO52yv2wS7wj1uuQLGobkmgWzFKx43QkK2cSTTq0KE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=kbDd/84n; arc=none smtp.client-ip=209.85.221.48 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="kbDd/84n" Received: by mail-wr1-f48.google.com with SMTP id ffacd0b85a97d-3e76766a172so929175f8f.0 for ; Fri, 12 Sep 2025 12:53:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1757706836; x=1758311636; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=1tBjQATVO5xgZ/yr5nMn7Qw/eeQsWnjOzogH+eIF8tM=; b=kbDd/84nAUyiUCf7ebIch5zkxHCn1zGhzMDolcCdDpYazKtrQpGjm2lo7EWQBeDhhU sxEGuJrob7SwNVkxEYd+duUZjx0+wWelpSv23B9b20Jc/Uo6FJ+Zkf37cmb/6vhRh0t6 PkvAHqNp8TxfM5aHMFZkTGp3Q0MnVilKgKVfZzwqRyKhkdCi14H3nrmTwWu8u4qi2rpT PCtKDhneg0Sx6W0xtuc8reWm6yqclPU4UNVXOv5RMPYFgg42Qg4j+0fevcyTG44KMKd3 kbpjAYj9U+VphQPIGziyy6Fy9uVNJU7DSygulJdYZQkFQN2RC5OYqUnl+HSNdIzsjX1/ Fspg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1757706836; x=1758311636; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=1tBjQATVO5xgZ/yr5nMn7Qw/eeQsWnjOzogH+eIF8tM=; b=CBirfbQgnvsHHln5JC0KdXrghBJ1q4cKaiLQaCdFhWOOAjCAyqLP0laCAbafhA80JP eTYjtotSL/GgbKHra98xLr0LPq3qngn/H4g+WIG05sM/IInWeLp8Am/zqcYAKEgnOGrm 1dBQvtMIkH3iXVXdpKbuxEm4KeopjMMsYmVhns0U/FZWGHF78ATT4i53iYZhKvk2ITst EEvrlRmk5pOQWWuQojj7LK0pKw6aYwU5y8yY7yhiSDe4iINV8+o8sSWBAPBhr5HX+kTE Kn8WaV79BqVB0o5e8sGQcR/5GJNiFcPMnlLoAu3/9RdUA3JiiHlV6znzumwKOym4ngBF 2Zfg== X-Forwarded-Encrypted: i=1; AJvYcCU1N/aMGJ1vvFPMwuO1byjoM6ipvIdQbgbH4qE0xqbcuxlAP8jKmKqtEiqtbChwVOmOA+zMzn6vKzl7+4s=@vger.kernel.org X-Gm-Message-State: AOJu0YwpdWq6LgxHYZgpJFX2X7jz7xgJvtI1Sxco9cMk+4STLNCiOuf9 Do7r9XAZx11morTZ/qZk3uyODcRJcu7kVs9tIJ5JJ531ewsMW9+aas0y X-Gm-Gg: ASbGncsEDwaUDt1BkQYYb/Je857brvFIaaOJ8d7rk9MyC2BMcjgKsLbNNzPQupzeaDg /pSCi5ms0ob3UEnLMsVypWIWUTg6ABgdPpsmfXfYhtNjWk/03fMKPCAJhg2z9bBxGS24gmH+OrM M5U5XyldPBYebKTB4p2KM2PyVf5n2keMTWu+53nd/KDia/gxiIp3nZQqdn4KI48wakYEBFZ2tqC MwGk7cc3pc3RZZhRFxqvB24qwa2wF16hS3QT9WaXDSWbIgiGtpJrEXYXlmWaOfJQJxxI0s0Sjb/ P3USphDH3bs2uihTAv622GAL9f90HuT1Zi6iiSB6cJLwQt+DQ1f3WL97xhpGwGeWOube+MB0grj cDVweoPd2thWrd7Da8FPmMknpqo3Zj5duGPxLnAuu8U3iHMlgzKAteGmNnBxUF/RJrSWvl7rm X-Google-Smtp-Source: AGHT+IGcBKOgx53Jm65PzbAADPlQfjhpj7kfAQIi9dZIUIhMC1gDPjWogKL7/mHKeareCdzLDUBraw== X-Received: by 2002:a05:6000:2c04:b0:3d7:cd09:ae1e with SMTP id ffacd0b85a97d-3e7657975f2mr4308727f8f.17.1757706835502; Fri, 12 Sep 2025 12:53:55 -0700 (PDT) Received: from yanesskka.. (node-188-187-35-212.domolink.tula.net. [212.35.187.188]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45e017bfd14sm74650375e9.21.2025.09.12.12.53.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 12 Sep 2025 12:53:55 -0700 (PDT) From: Yana Bashlykova To: "David S. Miller" Cc: Yana Bashlykova , Eric Dumazet , Jakub Kicinski , Paolo Abeni , linux-kernel@vger.kernel.org, netdev@vger.kernel.org, lvc-project@linuxtesting.org Subject: [PATCH 6.1 02/15] genetlink: add TEST_GENL family for netlink testing Date: Fri, 12 Sep 2025 22:53:25 +0300 Message-Id: <20250912195339.20635-3-yana2bsh@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250912195339.20635-1-yana2bsh@gmail.com> References: <20250912195339.20635-1-yana2bsh@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Implement basic Generic Netlink family with: - 4 commands (ECHO, SET/GET_VALUE, NO_ATTRS) - 1 small command (genl_small_ops) - Multicast group support - Attribute validation - Mutex-protected operations - Error handling with netlink_ext_ack Signed-off-by: Yana Bashlykova --- .../net-pf-16-proto-16-family-PARALLEL_GENL.c | 438 +++++++++++++++++- 1 file changed, 431 insertions(+), 7 deletions(-) diff --git a/drivers/net/genetlink/net-pf-16-proto-16-family-PARALLEL_GENL.= c b/drivers/net/genetlink/net-pf-16-proto-16-family-PARALLEL_GENL.c index c50c0daae392..69bcad98babc 100644 --- a/drivers/net/genetlink/net-pf-16-proto-16-family-PARALLEL_GENL.c +++ b/drivers/net/genetlink/net-pf-16-proto-16-family-PARALLEL_GENL.c @@ -71,17 +71,16 @@ static ssize_t show_genl_test_message(struct kobject *k= obj, =20 static ssize_t store_genl_test_message(struct kobject *kobj, struct kobj_attribute *attr, - const char *buf, size_t count) + const char *buf, size_t count) { - size_t len =3D min(count, sizeof(sysfs_data.genl_test_message) - 1); + size_t len =3D min(count, sizeof(sysfs_data.genl_test_message) - 1); =20 - strncpy(sysfs_data.genl_test_message, buf, len); - sysfs_data.genl_test_message[len] =3D '\0'; - return count; + strncpy(sysfs_data.genl_test_message, buf, len); + sysfs_data.genl_test_message[len] =3D '\0'; + return count; } =20 -static ssize_t show_genl_test_value(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) +static ssize_t show_genl_test_value(struct kobject *kobj, struct kobj_attr= ibute *attr, char *buf) { return sprintf(buf, "%d", sysfs_data.genl_test_value); } @@ -146,6 +145,424 @@ static struct kobj_attribute my_attr_str_parallel_gen= l =3D static struct kobj_attribute my_attr_str_third_genl =3D __ATTR(message, 0664, show_third_genl_message, store_third_genl_message); =20 +static DEFINE_MUTEX(genl_mutex); + +#define MY_GENL_FAMILY_NAME "TEST_GENL" +#define MY_GENL_VERSION 1 + +#define PATH_GENL_TEST_NUM "/sys/kernel/genl_test/value" +#define PATH_GENL_TEST_MES "/sys/kernel/genl_test/message" +#define PATH_GENL_TEST_DEV "/sys/kernel/genl_test/some_info" + +// TEST_GENL +enum { + MY_GENL_ATTR_UNSPEC, + MY_GENL_ATTR_DATA, + MY_GENL_ATTR_VALUE, + MY_GENL_ATTR_PATH, + MY_GENL_ATTR_NESTED, + __MY_GENL_ATTR_MAX, +}; + +#define MY_GENL_ATTR_MAX (__MY_GENL_ATTR_MAX - 1) + +enum { + MY_GENL_CMD_UNSPEC, + MY_GENL_CMD_ECHO, + MY_GENL_CMD_SET_VALUE, + MY_GENL_CMD_GET_VALUE, + MY_GENL_CMD_EVENT, + MY_GENL_CMD_NO_ATTRS, + __MY_GENL_CMD_MAX, +}; + +#define MY_GENL_CMD_MAX (__MY_GENL_CMD_MAX - 1) + +enum { + MY_GENL_SMALL_CMD_GET, + MY_GENL_SMALL_CMD_ERROR, + __MY_GENL_SMALL_CMD_MAX, +}; + +#define MY_GENL_SMALL_CMD_MAX (__MY_GENL_SMALL_CMD_MAX - 1) + +static const struct nla_policy my_genl_policy[MY_GENL_ATTR_MAX + 1] =3D { + [MY_GENL_ATTR_UNSPEC] =3D { .type =3D NLA_UNSPEC }, + [MY_GENL_ATTR_DATA] =3D { .type =3D NLA_STRING }, + [MY_GENL_ATTR_VALUE] =3D { .type =3D NLA_U32, + .validation_type =3D NLA_VALIDATE_RANGE, + .min =3D 0, + .max =3D 100 }, + [MY_GENL_ATTR_PATH] =3D { .type =3D NLA_STRING }, + [MY_GENL_ATTR_NESTED] =3D { .type =3D NLA_NESTED }, +}; + +/* netlink families */ +static struct genl_family my_genl_family; + +enum my_multicast_groups { + MY_MCGRP_GENL, +}; + +static const struct genl_multicast_group genl_mcgrps[] =3D { + [MY_MCGRP_GENL] =3D { .name =3D "MY_MCGRP_GENL", }, +}; + +static int my_genl_pre_doit(const struct genl_ops *ops, struct sk_buff *sk= b, + struct genl_info *info) +{ + mutex_lock(&genl_mutex); + return 0; +} + +static void my_genl_post_doit(const struct genl_ops *ops, struct sk_buff *= skb, + struct genl_info *info) +{ + mutex_unlock(&genl_mutex); +} + +static void my_genl_mcast_msg(struct sk_buff *mcast_skb, struct genl_info = *info) +{ + if (info) { + genl_notify(&my_genl_family, mcast_skb, info, MY_MCGRP_GENL, + GFP_KERNEL); + } else { + genlmsg_multicast(&my_genl_family, mcast_skb, 0, MY_MCGRP_GENL, + GFP_KERNEL); + } +} + +// Functions for Generic Netlink TEST_GENL family +static int my_genl_echo(struct sk_buff *skb, struct genl_info *info) +{ + struct sk_buff *msg; + void *data; + int ret; + char *str; + + if (info->nlhdr->nlmsg_flags & NLM_F_ECHO) { + msg =3D genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + data =3D genlmsg_put_reply(msg, info, &my_genl_family, 0, + MY_GENL_CMD_ECHO); + if (!data) + goto error; + + str =3D "Hello to mcast groups!"; + + strcpy(sysfs_data.genl_test_message, str); + + ret =3D nla_put_string(msg, MY_GENL_ATTR_DATA, str); + if (ret < 0) + goto error; + + genlmsg_end(msg, data); + + my_genl_mcast_msg(msg, info); + } + + return 0; + +error: + nlmsg_free(msg); + return -EMSGSIZE; +} + +static int my_genl_set_value(struct sk_buff *skb, struct genl_info *info) +{ + struct sk_buff *msg; + void *msg_head; + struct nlattr *na_path; + struct nlattr *na_value; + char *sysfs_path; + u32 new_value; + int err; + int code; + struct netlink_ext_ack *extack; + struct nlattr *attr; + struct nlmsghdr *nlh; + char cookie[NETLINK_MAX_COOKIE_LEN]; + + if (!info->attrs[MY_GENL_ATTR_VALUE]) { + pr_info("%s: Missing MY_GENL_ATTR_VALUE\n", __func__); + return -EINVAL; + } + + na_value =3D info->attrs[MY_GENL_ATTR_VALUE]; + new_value =3D nla_get_u32(na_value); + + if (new_value !=3D 0 && new_value !=3D 1) { + pr_err("%s: New value is incorrect\n", __func__); + goto error; + } + + na_path =3D info->attrs[MY_GENL_ATTR_PATH]; + if (!na_path) { + pr_info("%s: Missing MY_GENL_ATTR_PATH\n", __func__); + return -EINVAL; + } + sysfs_path =3D nla_data(na_path); + + sysfs_data.genl_test_value =3D new_value; + + msg =3D genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + msg_head =3D genlmsg_put(msg, info->snd_portid, info->snd_seq, + &my_genl_family, 0, MY_GENL_CMD_SET_VALUE); + if (!msg_head) { + nlmsg_free(msg); + return -ENOMEM; + } + + if (nla_put_u32(msg, MY_GENL_ATTR_VALUE, new_value)) { + genlmsg_cancel(msg, msg_head); + nlmsg_free(msg); + return -EMSGSIZE; + } + + genlmsg_end(msg, msg_head); + + err =3D netlink_unicast(skb->sk, msg, info->snd_portid, 0); + if (err < 0) { + pr_err("%s: Error in netlink_unicast, err=3D%d\n", __func__, err); + nlmsg_free(msg); + return err; + } + + return 0; + +error: + // sending error ACK + code =3D -EINVAL; + + extack =3D kmalloc(sizeof(*extack), GFP_KERNEL); + if (!extack) + return -ENOMEM; + + strcpy(cookie, "000001"); + extack->_msg =3D "Incorrect value from userspace"; + extack->bad_attr =3D na_value; + extack->policy =3D my_genl_policy; + extack->cookie_len =3D strlen(cookie); + extack->miss_type =3D MY_GENL_ATTR_VALUE; + extack->miss_nest =3D attr; + + nlh =3D nlmsg_hdr(skb); + netlink_ack(skb, nlh, code, extack); + pr_info("%s: Message with TLV was sent\n", __func__); + return -EINVAL; +} + +static int my_genl_get_value(struct sk_buff *skb, struct genl_info *info) +{ + struct sk_buff *msg; + void *msg_head; + struct nlattr *na_path; + char *sysfs_path; + u32 value; + int err; + int code; + + msg =3D genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + msg_head =3D genlmsg_put(msg, info->snd_portid, info->snd_seq, + &my_genl_family, 0, MY_GENL_CMD_GET_VALUE); + if (!msg_head) { + nlmsg_free(msg); + return -ENOMEM; + } + + if (!info->attrs[MY_GENL_ATTR_PATH]) { + nlmsg_free(msg); + return -EINVAL; + } + genl_unlock(); + na_path =3D info->attrs[MY_GENL_ATTR_PATH]; + sysfs_path =3D nla_data(na_path); + genl_lock(); + + if (strcmp(sysfs_path, PATH_GENL_TEST_NUM) !=3D 0) { + pr_err("%s: Incorrect path: %s\n", __func__, sysfs_path); + goto error; + } + + value =3D sysfs_data.genl_test_value; + + if (nla_put_u32(msg, MY_GENL_ATTR_VALUE, value)) { + genlmsg_cancel(msg, msg_head); + nlmsg_free(msg); + return -EMSGSIZE; + } + + genlmsg_end(msg, msg_head); + + if (info) { + err =3D genlmsg_reply(msg, info); + if (err !=3D 0) { + pr_err("%s: Error in genlmsg_reply, err=3D%d\n", __func__, err); + nlmsg_free(msg); + return err; + } + } + + return 0; + +error: + code =3D -EINVAL; + netlink_set_err(skb->sk, 0, MY_MCGRP_GENL, code); + return -EINVAL; +} + +static int my_genl_no_attrs(struct sk_buff *skb, struct genl_info *info) +{ + struct sk_buff *msg; + void *msg_head; + int ret; + char *str; + + msg =3D nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + msg_head =3D genlmsg_put_reply(msg, info, &my_genl_family, 0, + info->genlhdr->cmd); + if (!msg_head) + goto error; + + str =3D "Reply from GENL_TEST family function with no attrs"; + + strcpy(sysfs_data.genl_test_message, str); + + if (nla_put_string(msg, MY_GENL_ATTR_DATA, str)) { + pr_err("%s: Error with putting value to MY_GENL_ATTR_DATA\n", __func__); + goto error; + } + + genlmsg_end(msg, msg_head); + return genlmsg_reply(msg, info); + +error: + ret =3D -EMSGSIZE; + nlmsg_free(msg); + return ret; +} + +// Generic Netlink operations for TEST_GENL family +static const struct genl_ops my_genl_ops[] =3D { + { + .cmd =3D MY_GENL_CMD_ECHO, + .flags =3D 0, + .policy =3D my_genl_policy, + .doit =3D my_genl_echo, + .dumpit =3D NULL, + }, + { + .cmd =3D MY_GENL_CMD_SET_VALUE, + .policy =3D my_genl_policy, + .doit =3D my_genl_set_value, + .flags =3D GENL_ADMIN_PERM, + }, + { + .cmd =3D MY_GENL_CMD_GET_VALUE, + .flags =3D 0, + .policy =3D my_genl_policy, + .doit =3D my_genl_get_value, + .dumpit =3D NULL, + }, + { + .cmd =3D MY_GENL_CMD_NO_ATTRS, + .flags =3D 0, + .policy =3D NULL, + .doit =3D my_genl_no_attrs, + .dumpit =3D NULL, + }, +}; + +static int my_genl_small_cmd_get(struct sk_buff *skb, struct genl_info *in= fo) +{ + struct sk_buff *msg; + void *reply; + int ret; + char *str; + + msg =3D nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + reply =3D genlmsg_put_reply(msg, info, &my_genl_family, 0, + info->genlhdr->cmd); + if (!reply) + goto error; + + str =3D "IT'S ME from kernel"; + + strcpy(sysfs_data.genl_test_message, str); + + if (nla_put_string(msg, MY_GENL_ATTR_DATA, str)) { + nlmsg_free(msg); + pr_err("%s: Error with putting value to MY_GENL_ATTR_DATA\n", __func__); + return -EMSGSIZE; + } + + genlmsg_end(msg, reply); + return genlmsg_reply(msg, info); + +error: + ret =3D -EMSGSIZE; + nlmsg_free(msg); + return ret; +} + +static const struct genl_small_ops my_genl_small_ops[] =3D { + { + .cmd =3D MY_GENL_SMALL_CMD_GET, + .doit =3D my_genl_small_cmd_get, + }, +}; + +// genl_family struct for TEST_GENL family +static struct genl_family my_genl_family =3D { + .hdrsize =3D 0, + .name =3D MY_GENL_FAMILY_NAME, + .version =3D MY_GENL_VERSION, + .maxattr =3D MY_GENL_ATTR_MAX, + .netnsok =3D true, + .pre_doit =3D my_genl_pre_doit, + .post_doit =3D my_genl_post_doit, + .ops =3D my_genl_ops, + .n_ops =3D ARRAY_SIZE(my_genl_ops), + .small_ops =3D my_genl_small_ops, + .n_small_ops =3D ARRAY_SIZE(my_genl_small_ops), + .policy =3D my_genl_policy, + .mcgrps =3D genl_mcgrps, + .n_mcgrps =3D ARRAY_SIZE(genl_mcgrps), +}; + +static int __init init_netlink(void) +{ + int rc; + + pr_info("%s: My module. Initializing Netlink\n", __func__); + + rc =3D genl_register_family(&my_genl_family); + if (rc) { + pr_err("%s: Failed to register Generic Netlink family\n", __func__); + goto failure_1; + } + + return 0; + +failure_1: + pr_debug("%s: My module. Error occurred in %s\n", __func__, __func__); + return rc; +} + static int __init init_sysfs_third_genl(void) { int ret; @@ -253,6 +670,11 @@ static int __init module_netlink_init(void) if (ret) goto err_sysfs; =20 + ret =3D init_netlink(); + if (ret) + goto err_sysfs; + pr_info("%s: New families are registered\n", __func__); + return 0; =20 err_sysfs: @@ -271,6 +693,8 @@ static int __init module_netlink_init(void) =20 static void __exit module_netlink_exit(void) { + genl_unregister_family(&my_genl_family); + sysfs_remove_file(kobj_genl_test, &my_attr_u32_genl_test.attr); sysfs_remove_file(kobj_genl_test, &my_attr_str_genl_test.attr); device_remove_file(dev_genl_test, &dev_attr_info_genl_test); --=20 2.34.1 From nobody Thu Oct 2 18:21:34 2025 Received: from mail-wr1-f45.google.com (mail-wr1-f45.google.com [209.85.221.45]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C45C7280338 for ; Fri, 12 Sep 2025 19:53:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.45 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757706841; cv=none; b=BlWRdWvolrZ5U4tBMkTJCvXc57FaUA2bi7Z6kdIBYLvRfalz0xrWuJTiQ1VjXxT+rKVmwdp9aqtURJavRwqcUYhfsJmpj6j5chGVkTd1GJDaeg4Zq+mcWM1gOdFrHSF2OEhYoTZeHP+jRogBFTTAceeK+5m9yOk7Sex/eNyNm4k= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757706841; c=relaxed/simple; bh=TNwvDQajDJwinfMN+rc6pDxOnb11XL5FJGmkglwQ850=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=G+67KXpJhG8zlbj558H1uKCvR4R9JLiQ0nCOwGU89se239M1icHIvI5mJ/iA10V8PnUi7x/SiON7pofMWPAYrcJzc8XL7jus9mLVVXFMcV6fLHxJnNnZGG1rayqc4RIGdCF3dVsXlxfcRXwRkQmHEJojwUzQ0Vqg4/uBEcBv9Gc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=ZK/4lTVy; arc=none smtp.client-ip=209.85.221.45 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="ZK/4lTVy" Received: by mail-wr1-f45.google.com with SMTP id ffacd0b85a97d-3d44d734cabso1831076f8f.3 for ; Fri, 12 Sep 2025 12:53:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1757706837; x=1758311637; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=OPWRU5hljCQOOfEb+EXXggcIU6tx3t1+caDvvYD1FG4=; b=ZK/4lTVy470vdkEKBTDhMdyDfMbEWwSBfi1lTrG4QJPdfey2vUSJ6mXgFT3MybT/ER NORB5QnzL/Up63RSAenU8IybMdzgtWO6ZoUusqX2JoYbHQNRj2dxRW+21DjlnN8E+cAk AxFGS9f5cHniLWeGhodRMJI5LZR1pzqu5v73FYbC8YF9udKHzy1dxBRbLu3pYJKiHKG3 S5DfrCTuk1QR4ZWTwf0IMO2Sm2HGovWSc+mJeUp6V/o0NysE9diq5bjn94WiPll1/PZO eIZc3AKjXsfcKnsBAPOYtPybiOM5IBasn8+iWatkD5VakG4x+jUykblvxccSaO5pcLeZ nSkQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1757706837; x=1758311637; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=OPWRU5hljCQOOfEb+EXXggcIU6tx3t1+caDvvYD1FG4=; b=Go1efF3/UNenTC7hyLYiUovJ9AvAPnzoS2qyGkmtuJUQdheQ/3Sj63czY2bAgGWNAX nxDK/nmR7/KoNAu6nDmZnhVGIGefhGmpFEROEnrQ39cUQ+nR7l+xigQSOew3jgWmsYE9 /d1o889ajLc0uhZ64qdqhjAtNCsU7+s6aH0cdnjryqDsAVCfKBBjH0SiTlriB/jKyZPr P/ozZArWo+A8sycGOgDZymbBCHD8ZvNtg6uexvbUoqEB+RSxfVKcbfWIbIndpaUr6Qy3 zyOAJX3fvg8tDArjOgGLx1ze/UVmasjHOek40zQE59KVeWiEioKyyBxw2xnnHGEzrYhO vvgw== X-Forwarded-Encrypted: i=1; AJvYcCVRJDEUePgTcoA5MoA2ECIZY8RhuHf7Anat6UzN5Dcs+C/87GxRIgrOU+tb/LvPL6o3DeFVEnA1YD5NlGI=@vger.kernel.org X-Gm-Message-State: AOJu0YzXxHt/oSg8KMWbbQYH7CY5EwPBHhmGLg08CGOJZajJ6mR7hOOh KtkH/tcTMfxzR1vNgTeicOn6mcMcPKYXzFIFEZWZKT0114sTvi2P3KKV X-Gm-Gg: ASbGncsX8Qn8BefFbqX7U8S+EgALwMb2RjJApeMwqiMgkaB8g9BWG5PUu4iYPhYxAP9 eWUYcf56aozJVtQR+7AVzzSRYIjFidgNTYijeyrCJHl48W2Xq2imGXK83IZcsgabvq8k5O7gWGr CCa8C8Tw3NFNkdx0aL8D0H7Dga1yLHSr+9svBcalfIW1Zl/9yeSW3k4NPILc5rpPb4mkTWTq6JD PmfrnlWFa/jp25SEwLVy0yTxd7ughiCYj7J5Ea7WpoVDh4dYJyT5nr9p16UVsF1WvrnG71sfjQB Rd1JcwIeaHPuNhitx5qHHH6ExfA7ISD6XT46fVx2IC5HlsMGSCvJ2XNBOth4fPrXoo6I34rnQ1v 21Yst6e17chWiTSXHLmiQPGpO8yACho4+RvnOm+paz7K1STm+nheBfMzrBbK+Mg== X-Google-Smtp-Source: AGHT+IHVc0vSQuTGul1kjR1NEWN+wdKOnJm4ZMECOAgedHoMAITsiioS4A+FpNwFGvjZtFNBcl9gaQ== X-Received: by 2002:a5d:5d8a:0:b0:3dc:eb5:51f6 with SMTP id ffacd0b85a97d-3e7659d37b9mr4149963f8f.39.1757706836871; Fri, 12 Sep 2025 12:53:56 -0700 (PDT) Received: from yanesskka.. (node-188-187-35-212.domolink.tula.net. [212.35.187.188]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45e017bfd14sm74650375e9.21.2025.09.12.12.53.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 12 Sep 2025 12:53:56 -0700 (PDT) From: Yana Bashlykova To: "David S. Miller" Cc: Yana Bashlykova , Eric Dumazet , Jakub Kicinski , Paolo Abeni , linux-kernel@vger.kernel.org, netdev@vger.kernel.org, lvc-project@linuxtesting.org Subject: [PATCH 6.1 03/15] genetlink: add PARALLEL_GENL test family Date: Fri, 12 Sep 2025 22:53:26 +0300 Message-Id: <20250912195339.20635-4-yana2bsh@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250912195339.20635-1-yana2bsh@gmail.com> References: <20250912195339.20635-1-yana2bsh@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Implement PARALLEL_GENL Generic Netlink family with: - Parallel operations support (parallel dump) - 4 commands (SEND, DUMP_INFO, SET/GET_VALUE) - Command with reject policy - Advanced attribute types (binary, nested, flags) - Multicast group support - Proper error handling Signed-off-by: Yana Bashlykova --- .../net-pf-16-proto-16-family-PARALLEL_GENL.c | 547 +++++++++++++++++- 1 file changed, 544 insertions(+), 3 deletions(-) diff --git a/drivers/net/genetlink/net-pf-16-proto-16-family-PARALLEL_GENL.= c b/drivers/net/genetlink/net-pf-16-proto-16-family-PARALLEL_GENL.c index 69bcad98babc..17f869ece2d6 100644 --- a/drivers/net/genetlink/net-pf-16-proto-16-family-PARALLEL_GENL.c +++ b/drivers/net/genetlink/net-pf-16-proto-16-family-PARALLEL_GENL.c @@ -71,7 +71,7 @@ static ssize_t show_genl_test_message(struct kobject *kob= j, =20 static ssize_t store_genl_test_message(struct kobject *kobj, struct kobj_attribute *attr, - const char *buf, size_t count) + const char *buf, size_t count) { size_t len =3D min(count, sizeof(sysfs_data.genl_test_message) - 1); =20 @@ -150,9 +150,12 @@ static DEFINE_MUTEX(genl_mutex); #define MY_GENL_FAMILY_NAME "TEST_GENL" #define MY_GENL_VERSION 1 =20 +#define PARALLEL_GENL_FAMILY_NAME "PARALLEL_GENL" + #define PATH_GENL_TEST_NUM "/sys/kernel/genl_test/value" #define PATH_GENL_TEST_MES "/sys/kernel/genl_test/message" #define PATH_GENL_TEST_DEV "/sys/kernel/genl_test/some_info" +#define PATH_PARALLEL_GENL_MES "/sys/kernel/parallel_genl/message" =20 // TEST_GENL enum { @@ -200,6 +203,8 @@ static const struct nla_policy my_genl_policy[MY_GENL_A= TTR_MAX + 1] =3D { /* netlink families */ static struct genl_family my_genl_family; =20 +static struct genl_family my_genl_family_parallel; + enum my_multicast_groups { MY_MCGRP_GENL, }; @@ -544,6 +549,534 @@ static struct genl_family my_genl_family =3D { .n_mcgrps =3D ARRAY_SIZE(genl_mcgrps), }; =20 +// PARALLEL_GENL family +enum { + PARALLEL_GENL_ATTR_UNSPEC, + PARALLEL_GENL_ATTR_DATA, + PARALLEL_GENL_ATTR_BINARY, + PARALLEL_GENL_ATTR_NAME, + PARALLEL_GENL_ATTR_DESC, + PARALLEL_GENL_ATTR_BITFIELD32, + PARALLEL_GENL_ATTR_SIGN_NUM, + PARALLEL_GENL_ATTR_ARRAY, + PARALLEL_GENL_ATTR_NESTED, + PARALLEL_GENL_ATTR_FLAG_NONBLOCK, + PARALLEL_GENL_ATTR_FLAG_BLOCK, + PARALLEL_GENL_ATTR_REJECT, + PARALLEL_GENL_ATTR_PATH, + __PARALLEL_GENL_ATTR_MAX, +}; + +#define PARALLEL_GENL_ATTR_MAX (__PARALLEL_GENL_ATTR_MAX - 1) + +enum { + PARALLEL_GENL_CMD_UNSPEC, + PARALLEL_GENL_CMD_SEND, + PARALLEL_GENL_CMD_DUMP_INFO, + PARALLEL_GENL_CMD_SET_VALUE, + PARALLEL_GENL_CMD_GET_VALUE, + __PARALLEL_GENL_CMD_MAX, +}; + +#define PARALLEL_GENL_CMD_MAX (__PARALLEL_GENL_CMD_MAX - 1) + +static const struct nla_policy parallel_genl_policy[PARALLEL_GENL_ATTR_MAX= + + 1] =3D { + [PARALLEL_GENL_ATTR_UNSPEC] =3D { .type =3D NLA_UNSPEC }, + [PARALLEL_GENL_ATTR_DATA] =3D { .type =3D NLA_STRING }, + [PARALLEL_GENL_ATTR_BINARY] =3D { .type =3D NLA_BINARY }, + [PARALLEL_GENL_ATTR_NAME] =3D { .type =3D NLA_NUL_STRING }, + [PARALLEL_GENL_ATTR_DESC] =3D { .type =3D NLA_NUL_STRING }, + [PARALLEL_GENL_ATTR_BITFIELD32] =3D { .type =3D NLA_BITFIELD32 }, + [PARALLEL_GENL_ATTR_SIGN_NUM] =3D { .type =3D NLA_S32, + .validation_type =3D NLA_VALIDATE_RANGE, + .min =3D -100, + .max =3D 100 }, + [PARALLEL_GENL_ATTR_ARRAY] =3D { .type =3D NLA_NESTED_ARRAY }, + [PARALLEL_GENL_ATTR_NESTED] =3D { .type =3D NLA_NESTED }, + [PARALLEL_GENL_ATTR_FLAG_NONBLOCK] =3D { .type =3D NLA_FLAG }, + [PARALLEL_GENL_ATTR_FLAG_BLOCK] =3D { .type =3D NLA_FLAG }, + [PARALLEL_GENL_ATTR_REJECT] =3D { .type =3D NLA_REJECT }, + [PARALLEL_GENL_ATTR_PATH] =3D { .type =3D NLA_STRING }, +}; + +static int parallel_genl_send(struct sk_buff *skb, struct genl_info *info) +{ + struct sk_buff *msg; + void *reply; + int ret; + char *str; + + msg =3D nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + + if (!msg) + return -ENOMEM; + + reply =3D genlmsg_put_reply(msg, info, &my_genl_family, 0, + info->genlhdr->cmd); + if (!reply) + goto error; + + str =3D "NEW family - parallel_genl"; + + strcpy(sysfs_data.parallel_genl_message, str); + + if (nla_put_string(msg, PARALLEL_GENL_ATTR_DATA, str)) { + nlmsg_free(msg); + pr_err("%s: Error with putting value to PARALLEL_GENL_ATTR_DATA\n", __fu= nc__); + return -EMSGSIZE; + } + + genlmsg_end(msg, reply); + + if (nla_get_flag(info->attrs[PARALLEL_GENL_ATTR_FLAG_NONBLOCK])) + goto overrun_nonblock; + if (nla_get_flag(info->attrs[PARALLEL_GENL_ATTR_FLAG_BLOCK])) + goto overrun_block; + + return genlmsg_reply(msg, info); + +error: + ret =3D -EMSGSIZE; + nlmsg_free(msg); + return ret; + +overrun_nonblock: + skb->sk->sk_sndtimeo =3D 1000; + ret =3D netlink_unicast(skb->sk, msg, info->snd_portid, 1); + if (ret < 0) + return ret; + + return 0; + +overrun_block: + ret =3D netlink_unicast(skb->sk, msg, info->snd_portid, 0); + if (ret < 0) + return ret; + + return 0; +} + +static int parallel_genl_set_str_value(struct sk_buff *skb, + struct genl_info *info) +{ + struct sk_buff *msg; + void *msg_head; + struct nlattr *na_path; + struct nlattr *na_value; + char *sysfs_path; + char *new_value =3D NULL; + int err; + int data_len; + + if (!info->attrs[PARALLEL_GENL_ATTR_DATA]) { + pr_info("%s: Missing PARALLEL_GENL_ATTR_DATA\n", __func__); + return -EINVAL; + } + + na_value =3D info->attrs[PARALLEL_GENL_ATTR_DATA]; + data_len =3D nla_len(na_value); + + new_value =3D kmalloc(data_len + 1, GFP_KERNEL); + if (!new_value) + return -ENOMEM; + + strncpy(new_value, nla_data(na_value), data_len); + new_value[data_len] =3D '\0'; + + na_path =3D info->attrs[PARALLEL_GENL_ATTR_PATH]; + if (!na_path) { + pr_info("%s: Missing PARALLEL_GENL_ATTR_PATH\n", __func__); + return -EINVAL; + } + sysfs_path =3D nla_data(na_path); + + strcpy(sysfs_data.parallel_genl_message, new_value); + + msg =3D genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + msg_head =3D genlmsg_put(msg, info->snd_portid, info->snd_seq, + &my_genl_family_parallel, 0, + PARALLEL_GENL_CMD_SET_VALUE); + if (!msg_head) { + nlmsg_free(msg); + return -ENOMEM; + } + + if (nla_put_string(msg, PARALLEL_GENL_ATTR_DATA, new_value)) { + genlmsg_cancel(msg, msg_head); + nlmsg_free(msg); + return -EMSGSIZE; + } + + genlmsg_end(msg, msg_head); + + err =3D netlink_unicast(skb->sk, msg, info->snd_portid, 0); + if (err < 0) { + pr_err("%s: Error in netlink_unicast, err=3D%d\n", __func__, err); + nlmsg_free(msg); + return err; + } + + kfree(new_value); + return 0; +} + +static int parallel_genl_get_str_value(struct sk_buff *skb, + struct genl_info *info) +{ + struct sk_buff *msg; + void *msg_head; + struct nlattr *na_path; + char *sysfs_path; + char *value; + int err; + int code; + + msg =3D genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + msg_head =3D genlmsg_put(msg, info->snd_portid, info->snd_seq, + &my_genl_family_parallel, 0, + PARALLEL_GENL_CMD_GET_VALUE); + if (!msg_head) { + nlmsg_free(msg); + return -ENOMEM; + } + + if (!info->attrs[PARALLEL_GENL_ATTR_PATH]) { + nlmsg_free(msg); + return -EINVAL; + } + genl_unlock(); + na_path =3D info->attrs[PARALLEL_GENL_ATTR_PATH]; + sysfs_path =3D nla_data(na_path); + genl_lock(); + + if (strcmp(sysfs_path, PATH_PARALLEL_GENL_MES) !=3D 0) { + pr_err("%s: Incorrect path: %s\n", __func__, sysfs_path); + goto error; + } + + value =3D kmalloc(MAX_DATA_LEN, GFP_KERNEL); + if (!value) + return -ENOMEM; + + strcpy(value, sysfs_data.parallel_genl_message); + + if (nla_put_string(msg, PARALLEL_GENL_ATTR_DATA, value)) { + genlmsg_cancel(msg, msg_head); + nlmsg_free(msg); + kfree(value); + return -EMSGSIZE; + } + + genlmsg_end(msg, msg_head); + + if (info) { + err =3D genlmsg_reply(msg, info); + if (err !=3D 0) { + pr_err("%s: Error in genlmsg_reply, err=3D%d\n", + __func__, err); + nlmsg_free(msg); + kfree(value); + return err; + } + } + kfree(value); + + return 0; + +error: + nlmsg_free(msg); + code =3D -ENOENT; + netlink_set_err(skb->sk, 0, MY_MCGRP_GENL, code); + return -ENOENT; +} + +struct parallel_data { + char *name; + char *desc; +}; + +struct parallel_data data[] =3D { + { "TEST_GENL", "one" }, + { "PARALLEL_GENL", "two" }, + { "THIRD_GENL", "three" }, + { "LARGE_GENL", "four" }, +}; + +#define DATA_SIZE ARRAY_SIZE(data) + +static int parallel_genl_dump_start(struct netlink_callback *cb) +{ + pr_info("%s: Dump is started", __func__); + return 0; +} + +static int __parallel_genl_fill_info(struct parallel_data *info, + struct sk_buff *msg) +{ + if (nla_put_string(msg, PARALLEL_GENL_ATTR_NAME, info->name) || + nla_put_string(msg, PARALLEL_GENL_ATTR_DESC, info->desc)) + return -EMSGSIZE; + + return 0; +} + +static int __parallel_genl_dump_element(struct parallel_data *info, u32 po= rtid, + u32 seq, u32 flags, struct sk_buff *skb, + u8 cmd) +{ + void *hdr; + + hdr =3D genlmsg_put(skb, portid, seq, &my_genl_family_parallel, flags, + cmd); + if (!hdr) + return -ENOMEM; + + if (__parallel_genl_fill_info(info, skb) < 0) + goto nla_put_failure; + + genlmsg_end(skb, hdr); + return 0; + +nla_put_failure: + genlmsg_cancel(skb, hdr); + return -EMSGSIZE; +} + +static int parallel_genl_dump_info(struct sk_buff *skb, + struct netlink_callback *cb) +{ + int ret; + int idx =3D cb->args[0]; + + for (;;) { + if (idx >=3D DATA_SIZE) + return 0; + + ret =3D __parallel_genl_dump_element(&data[idx], + NETLINK_CB(cb->skb).portid, + cb->nlh->nlmsg_seq, + NLM_F_MULTI, skb, + PARALLEL_GENL_CMD_DUMP_INFO); + + if (ret) { + pr_err("%s: __parallel_genl_dump_element failed: %d\n", __func__, ret); + return ret; + } + + cb->args[0]++; + idx++; + } + + return ret; +} + +static int parallel_genl_dump_done(struct netlink_callback *cb) +{ + pr_info("%s: Dump is done", __func__); + return 0; +} + +// Generic Netlink operations for PARALLEL_GENL family +static const struct genl_ops parallel_genl_ops[] =3D { + { + .cmd =3D PARALLEL_GENL_CMD_SEND, + .flags =3D 0, + .policy =3D parallel_genl_policy, + .doit =3D parallel_genl_send, + .dumpit =3D NULL, + }, + { + .cmd =3D PARALLEL_GENL_CMD_DUMP_INFO, + .flags =3D 0, + .policy =3D parallel_genl_policy, + .start =3D parallel_genl_dump_start, + .dumpit =3D parallel_genl_dump_info, + .done =3D parallel_genl_dump_done, + }, + { + .cmd =3D PARALLEL_GENL_CMD_SET_VALUE, + .flags =3D 0, + .policy =3D NULL, + .doit =3D parallel_genl_set_str_value, + .dumpit =3D NULL, + }, + { + .cmd =3D PARALLEL_GENL_CMD_GET_VALUE, + .flags =3D GENL_UNS_ADMIN_PERM, + .policy =3D parallel_genl_policy, + .doit =3D parallel_genl_get_str_value, + }, +}; + +enum my_multicast_many_groups_two { + MCGRP_TWO_1, + MCGRP_TWO_2, + MCGRP_TWO_3, + MCGRP_TWO_4, + MCGRP_TWO_5, + MCGRP_TWO_6, + MCGRP_TWO_7, + MCGRP_TWO_8, + MCGRP_TWO_9, + MCGRP_TWO_10, + MCGRP_TWO_11, + MCGRP_TWO_12, + MCGRP_TWO_13, + MCGRP_TWO_14, + MCGRP_TWO_15, + MCGRP_TWO_16, + MCGRP_TWO_17, + MCGRP_TWO_18, + MCGRP_TWO_19, + MCGRP_TWO_20, + MCGRP_TWO_21, + MCGRP_TWO_22, + MCGRP_TWO_23, + MCGRP_TWO_24, + MCGRP_TWO_25, + MCGRP_TWO_26, + MCGRP_TWO_27, + MCGRP_TWO_28, + MCGRP_TWO_29, + MCGRP_TWO_30, + MCGRP_TWO_31, + MCGRP_TWO_32, + MCGRP_TWO_33, + MCGRP_TWO_34, + MCGRP_TWO_35, + MCGRP_TWO_36, + MCGRP_TWO_37, + MCGRP_TWO_38, + MCGRP_TWO_39, + MCGRP_TWO_40, + MCGRP_TWO_41, + MCGRP_TWO_42, + MCGRP_TWO_43, + MCGRP_TWO_44, + MCGRP_TWO_45, + MCGRP_TWO_46, + MCGRP_TWO_47, + MCGRP_TWO_48, + MCGRP_TWO_49, + MCGRP_TWO_50, + MCGRP_TWO_51, + MCGRP_TWO_52, + MCGRP_TWO_53, + MCGRP_TWO_54, + MCGRP_TWO_55, + MCGRP_TWO_56, + MCGRP_TWO_57, + MCGRP_TWO_58, + MCGRP_TWO_59, + MCGRP_TWO_60, + MCGRP_TWO_61, + MCGRP_TWO_62, + MCGRP_TWO_63, + MCGRP_TWO_64, + MCGRP_TWO_65, + MCGRP_TWO_66, + MCGRP_TWO_67, + MCGRP_TWO_68, + MCGRP_TWO_69, +}; + +static const struct genl_multicast_group genl_many_mcgrps_two[] =3D { + [MCGRP_TWO_1] =3D { .name =3D "MCGRP_TWO_1", }, + [MCGRP_TWO_2] =3D { .name =3D "MCGRP_TWO_2", }, + [MCGRP_TWO_3] =3D { .name =3D "MCGRP_TWO_3", }, + [MCGRP_TWO_4] =3D { .name =3D "MCGRP_TWO_4", }, + [MCGRP_TWO_5] =3D { .name =3D "MCGRP_TWO_5", }, + [MCGRP_TWO_6] =3D { .name =3D "MCGRP_TWO_6", }, + [MCGRP_TWO_7] =3D { .name =3D "MCGRP_TWO_7", }, + [MCGRP_TWO_8] =3D { .name =3D "MCGRP_TWO_8", }, + [MCGRP_TWO_9] =3D { .name =3D "MCGRP_TWO_9", }, + [MCGRP_TWO_10] =3D { .name =3D "MCGRP_TWO_10", }, + [MCGRP_TWO_11] =3D { .name =3D "MCGRP_TWO_11", }, + [MCGRP_TWO_12] =3D { .name =3D "MCGRP_TWO_12", }, + [MCGRP_TWO_13] =3D { .name =3D "MCGRP_TWO_13", }, + [MCGRP_TWO_14] =3D { .name =3D "MCGRP_TWO_14", }, + [MCGRP_TWO_15] =3D { .name =3D "MCGRP_TWO_15", }, + [MCGRP_TWO_16] =3D { .name =3D "MCGRP_TWO_16", }, + [MCGRP_TWO_17] =3D { .name =3D "MCGRP_TWO_17", }, + [MCGRP_TWO_18] =3D { .name =3D "MCGRP_TWO_18", }, + [MCGRP_TWO_19] =3D { .name =3D "MCGRP_TWO_19", }, + [MCGRP_TWO_20] =3D { .name =3D "MCGRP_TWO_20", }, + [MCGRP_TWO_21] =3D { .name =3D "MCGRP_TWO_21", }, + [MCGRP_TWO_22] =3D { .name =3D "MCGRP_TWO_22", }, + [MCGRP_TWO_23] =3D { .name =3D "MCGRP_TWO_23", }, + [MCGRP_TWO_24] =3D { .name =3D "MCGRP_TWO_24", }, + [MCGRP_TWO_25] =3D { .name =3D "MCGRP_TWO_25", }, + [MCGRP_TWO_26] =3D { .name =3D "MCGRP_TWO_26", }, + [MCGRP_TWO_27] =3D { .name =3D "MCGRP_TWO_27", }, + [MCGRP_TWO_28] =3D { .name =3D "MCGRP_TWO_28", }, + [MCGRP_TWO_29] =3D { .name =3D "MCGRP_TWO_29", }, + [MCGRP_TWO_30] =3D { .name =3D "MCGRP_TWO_30", }, + [MCGRP_TWO_31] =3D { .name =3D "MCGRP_TWO_31", }, + [MCGRP_TWO_32] =3D { .name =3D "MCGRP_TWO_32", }, + [MCGRP_TWO_33] =3D { .name =3D "MCGRP_TWO_33", }, + [MCGRP_TWO_34] =3D { .name =3D "MCGRP_TWO_34", }, + [MCGRP_TWO_35] =3D { .name =3D "MCGRP_TWO_35", }, + [MCGRP_TWO_36] =3D { .name =3D "MCGRP_TWO_36", }, + [MCGRP_TWO_37] =3D { .name =3D "MCGRP_TWO_37", }, + [MCGRP_TWO_38] =3D { .name =3D "MCGRP_TWO_38", }, + [MCGRP_TWO_39] =3D { .name =3D "MCGRP_TWO_39", }, + [MCGRP_TWO_40] =3D { .name =3D "MCGRP_TWO_40", }, + [MCGRP_TWO_41] =3D { .name =3D "MCGRP_TWO_41", }, + [MCGRP_TWO_42] =3D { .name =3D "MCGRP_TWO_42", }, + [MCGRP_TWO_43] =3D { .name =3D "MCGRP_TWO_43", }, + [MCGRP_TWO_44] =3D { .name =3D "MCGRP_TWO_44", }, + [MCGRP_TWO_45] =3D { .name =3D "MCGRP_TWO_45", }, + [MCGRP_TWO_46] =3D { .name =3D "MCGRP_TWO_46", }, + [MCGRP_TWO_47] =3D { .name =3D "MCGRP_TWO_47", }, + [MCGRP_TWO_48] =3D { .name =3D "MCGRP_TWO_48", }, + [MCGRP_TWO_49] =3D { .name =3D "MCGRP_TWO_49", }, + [MCGRP_TWO_50] =3D { .name =3D "MCGRP_TWO_50", }, + [MCGRP_TWO_51] =3D { .name =3D "MCGRP_TWO_51", }, + [MCGRP_TWO_52] =3D { .name =3D "MCGRP_TWO_52", }, + [MCGRP_TWO_53] =3D { .name =3D "MCGRP_TWO_53", }, + [MCGRP_TWO_54] =3D { .name =3D "MCGRP_TWO_54", }, + [MCGRP_TWO_55] =3D { .name =3D "MCGRP_TWO_55", }, + [MCGRP_TWO_56] =3D { .name =3D "MCGRP_TWO_56", }, + [MCGRP_TWO_57] =3D { .name =3D "MCGRP_TWO_57", }, + [MCGRP_TWO_58] =3D { .name =3D "MCGRP_TWO_58", }, + [MCGRP_TWO_59] =3D { .name =3D "MCGRP_TWO_59", }, + [MCGRP_TWO_60] =3D { .name =3D "MCGRP_TWO_60", }, + [MCGRP_TWO_61] =3D { .name =3D "MCGRP_TWO_61", }, + [MCGRP_TWO_62] =3D { .name =3D "MCGRP_TWO_62", }, + [MCGRP_TWO_63] =3D { .name =3D "MCGRP_TWO_63", }, + [MCGRP_TWO_64] =3D { .name =3D "MCGRP_TWO_64", }, + [MCGRP_TWO_65] =3D { .name =3D "MCGRP_TWO_65", }, + [MCGRP_TWO_66] =3D { .name =3D "MCGRP_TWO_66", }, + [MCGRP_TWO_67] =3D { .name =3D "MCGRP_TWO_67", }, + [MCGRP_TWO_68] =3D { .name =3D "MCGRP_TWO_68", }, + [MCGRP_TWO_69] =3D { .name =3D "MCGRP_TWO_69", }, +}; + +// genl_family struct for PARALLEL_GENL family +static struct genl_family my_genl_family_parallel =3D { + .hdrsize =3D 0, + .name =3D PARALLEL_GENL_FAMILY_NAME, + .version =3D 1, + .maxattr =3D PARALLEL_GENL_ATTR_MAX, + .netnsok =3D true, + .parallel_ops =3D true, + .ops =3D parallel_genl_ops, + .n_ops =3D ARRAY_SIZE(parallel_genl_ops), + /** .policy =3D parallel_genl_policy, + * needs to delete policy from family to test reject policy + */ + .resv_start_op =3D PARALLEL_GENL_CMD_DUMP_INFO + 1, + .mcgrps =3D genl_many_mcgrps_two, + .n_mcgrps =3D ARRAY_SIZE(genl_many_mcgrps_two), +}; + static int __init init_netlink(void) { int rc; @@ -556,8 +1089,16 @@ static int __init init_netlink(void) goto failure_1; } =20 + rc =3D genl_register_family(&my_genl_family_parallel); + if (rc) { + pr_err("%s: Failed to register Generic Netlink family\n", __func__); + goto failure_2; + } + return 0; =20 +failure_2: + genl_unregister_family(&my_genl_family); failure_1: pr_debug("%s: My module. Error occurred in %s\n", __func__, __func__); return rc; @@ -599,8 +1140,7 @@ static int __init init_sysfs_parallel_genl(void) return -ENOMEM; } =20 - ret =3D sysfs_create_file(kobj_parallel_genl, - &my_attr_str_parallel_genl.attr); + ret =3D sysfs_create_file(kobj_parallel_genl, &my_attr_str_parallel_genl.= attr); if (ret) { pr_err("%s: Failed to create sysfs file\n", __func__); goto err_sysfs; @@ -694,6 +1234,7 @@ static int __init module_netlink_init(void) static void __exit module_netlink_exit(void) { genl_unregister_family(&my_genl_family); + genl_unregister_family(&my_genl_family_parallel); =20 sysfs_remove_file(kobj_genl_test, &my_attr_u32_genl_test.attr); sysfs_remove_file(kobj_genl_test, &my_attr_str_genl_test.attr); --=20 2.34.1 From nobody Thu Oct 2 18:21:34 2025 Received: from mail-wm1-f53.google.com (mail-wm1-f53.google.com [209.85.128.53]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DF1542C0F71 for ; Fri, 12 Sep 2025 19:53:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.53 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757706841; cv=none; b=GaQ2OJFpV35vO9V7BmqHXk2UmTTZ6doa0IL2HC5UY3E48sN/2nx1AKGyAgiSvfJ3TP1+KlGmHwz0WYFPf6+j4WZAsIzv5DsfuVwRSPZXJyj1+3ATEDXBA3Vxea8E60JXRRFsn+KsNEJU7lJ+OiRU4sk1HavC5HbgPwN2yPN+HY0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757706841; c=relaxed/simple; bh=S++nbLXYGUNn+kPv+4a4KLGbhT3HHy1Lef48AXgBcmQ=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=SA3TXz+1DXFY7pIpDzdnEtMjcVon2P4OafKZR0h1riue5lLdnt4RxMt5qZAAgUqaVFfK1euaeqXojcNBVAV++325m2z6cdVJO0g64x/vlXEFc5n/UwNzHDzepbAx1XoMI6IGqmw8peY7LrFofXd+ifZq13Jky0jHG4ZonD37pvc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=hhl3lePw; arc=none smtp.client-ip=209.85.128.53 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="hhl3lePw" Received: by mail-wm1-f53.google.com with SMTP id 5b1f17b1804b1-45dd7b15a64so20911935e9.0 for ; Fri, 12 Sep 2025 12:53:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1757706838; x=1758311638; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=cM2EwFi4Xi2FPT3nNBJPMpu3J3wjRZsJQ3rXDogFCog=; b=hhl3lePwwlUtA7VcbLZcOvxhs54vf2r20WY5booo9eAhAnD/DirKdGvC1dWXvv7Z9r L9KoiyN/zFdw/0TilDcPPe37QaSi8QRnYpQ9opj/WNed8Y3qPs9JK6s83GIlXROwC7Ws xBGuTQGApgu/Dq9ahhe0QokBI0x92zBr5JchQUMffNC+a91+CjtReDQi638HYQtxLfk0 qSTdIn1FFLJdKaLvOI7pUaPw/2akA8qcT5qgDQndAepUOTugHOIiW7hbkeJN6RPHCoD8 ARuS2z6E0lTn1ArDoKZ0G6se39sP3xQOp88VMzBaiEUNc2G8gMqDwVoDpLBdgNFvNLcC Qd+w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1757706838; x=1758311638; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=cM2EwFi4Xi2FPT3nNBJPMpu3J3wjRZsJQ3rXDogFCog=; b=ofVuTofrezTu/Mse6+T1vcoiP6OWnBeGRSCOjB3JtylbC4FB6tYLUl/16kT1huNjI2 2kItHKAJw8ReInPw9hTyYaJBk+7QfjC9gUaBuNQknp46a1S3eKSqBklIZRNc2bHSSKk+ 0oFdq68WAKQwhs96a744trnIdsBKsbwjj9AG3Bo76N7xD+Y4qR0otclDds5M7iPyTTP3 0zdacTyjbrTXiy/nIGVswv4T4dcb/4UyQipkpLBE5ON6XQEAeT4kEkLX1zoeWzwTFwoG lZ1tO1ajEgZUVXAaDzKOgZ63zpB9k6PCDYOOK5z3TtcAe1BiGjnbaMq/sz49kHaI3C/E bWLg== X-Forwarded-Encrypted: i=1; AJvYcCVRmCQ1FGHMr4dLlSZ3ArK7s3qyQWFjpDP4stiy8Hu3c/nUK6kdbb+UY7BfQw6Ag7oI+YS104tuA7l5dto=@vger.kernel.org X-Gm-Message-State: AOJu0YzrJSQOuc5aifMJpYQItSkGAY5IF8iaS43VWfcYeC8y9yA1l5/G dd5+yviaRQpvBtRcOtdthWX5IDJeav+wWWfCpbEslsocIr3WXg/Re9YI X-Gm-Gg: ASbGncuaYg1aNv3S70YnmlzmAkiTXZ+pHdFQoA0cvLHClD9BVC5f5ypmJ3rXAs29KUt eQYcgxYKJh9Q07EoRSVusSmXYwBa97+j0kqeq5ea5dz5Wc+fwn2lkmgcUwBptf8FgXFYURKXr87 FmSWzUg1Kn3YT0TnEdRU43KyBrFjqmRo8d0BDMfmCCckcCUNyDeb1VqvZlYsbZb+JXWRo0VptHe EbogfuFm0fpP14SSNXqsgsRLWNOdjpQQaQynKMyY0+4yRbHdCNOOkIJfdKhLzsckZJaOHLKp+AU APA1FDisXdel8zuBm5gH9/W5Eho0rkaXbMR9GzKtfyaS6c89/ORg7waJmJgF3lL4K0mNjnVhX7I lZgOzJWBzxXALnDurv2xVkGkn/F/15JBYBa+vJCSOVqHRju2IbnxpFDP1PGwz1glhEvfmJsOV X-Google-Smtp-Source: AGHT+IHhUSN1KRgjO7FW8UWVga5t6VY0VlIT576vaao13oDQslNXzdFjIiW1xn/xILoGBvdikE/Pcw== X-Received: by 2002:a05:600c:3b19:b0:45c:b61a:b1bd with SMTP id 5b1f17b1804b1-45f2129bd63mr41142815e9.18.1757706838188; Fri, 12 Sep 2025 12:53:58 -0700 (PDT) Received: from yanesskka.. (node-188-187-35-212.domolink.tula.net. [212.35.187.188]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45e017bfd14sm74650375e9.21.2025.09.12.12.53.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 12 Sep 2025 12:53:57 -0700 (PDT) From: Yana Bashlykova To: "David S. Miller" Cc: Yana Bashlykova , Eric Dumazet , Jakub Kicinski , Paolo Abeni , linux-kernel@vger.kernel.org, netdev@vger.kernel.org, lvc-project@linuxtesting.org Subject: [PATCH 6.1 04/15] genetlink: add test case for duplicate genl family registration Date: Fri, 12 Sep 2025 22:53:27 +0300 Message-Id: <20250912195339.20635-5-yana2bsh@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250912195339.20635-1-yana2bsh@gmail.com> References: <20250912195339.20635-1-yana2bsh@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add incorrect_genl_family struct with duplicate name to test error handling when registering families with conflicting names. Signed-off-by: Yana Bashlykova --- .../net-pf-16-proto-16-family-PARALLEL_GENL.c | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/drivers/net/genetlink/net-pf-16-proto-16-family-PARALLEL_GENL.= c b/drivers/net/genetlink/net-pf-16-proto-16-family-PARALLEL_GENL.c index 17f869ece2d6..1db5d15a6f2c 100644 --- a/drivers/net/genetlink/net-pf-16-proto-16-family-PARALLEL_GENL.c +++ b/drivers/net/genetlink/net-pf-16-proto-16-family-PARALLEL_GENL.c @@ -1077,6 +1077,18 @@ static struct genl_family my_genl_family_parallel = =3D { .n_mcgrps =3D ARRAY_SIZE(genl_many_mcgrps_two), }; =20 +// genl_family struct with incorrect name +static struct genl_family incorrect_genl_family =3D { + .hdrsize =3D 0, + .name =3D MY_GENL_FAMILY_NAME, // such family already exists + .version =3D MY_GENL_VERSION, + .maxattr =3D MY_GENL_ATTR_MAX, + .netnsok =3D true, + .ops =3D my_genl_ops, + .n_ops =3D ARRAY_SIZE(my_genl_ops), + .policy =3D my_genl_policy, +}; + static int __init init_netlink(void) { int rc; @@ -1104,6 +1116,25 @@ static int __init init_netlink(void) return rc; } =20 +static int __init incorrect_init_netlink(void) +{ + int rc; + + pr_info("%s: My module. Initializing incorrect Netlink\n", __func__); + + rc =3D genl_register_family(&incorrect_genl_family); + if (rc) { + pr_err("%s: Failed to register incorrect Generic Netlink family\n", __fu= nc__); + goto failure; + } + + return 0; + +failure: + pr_info("%s: Error was handled correctly\n", __func__); + return -EINVAL; +} + static int __init init_sysfs_third_genl(void) { int ret; @@ -1215,6 +1246,10 @@ static int __init module_netlink_init(void) goto err_sysfs; pr_info("%s: New families are registered\n", __func__); =20 + ret =3D incorrect_init_netlink(); + if (ret) + pr_err("%s: Incorrect Generic Netlink family wasn't registered\n", __fun= c__); + return 0; =20 err_sysfs: --=20 2.34.1 From nobody Thu Oct 2 18:21:34 2025 Received: from mail-wr1-f43.google.com (mail-wr1-f43.google.com [209.85.221.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6105E2848B0 for ; Fri, 12 Sep 2025 19:54:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.43 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757706844; cv=none; b=FlC1NtRxUP26rkuP96wohTCMmLojUoVz7yCnOdytu66BKL17hauHMxVvBQQcuWIHhlPSgRFyomO9xiFA0YM0hh6ezX4aclh9Enm4KMcFU3Ft/0fcUzA+MOVMxeh7IcUa4tW96ki8zBfNMJGzcLsMqUjTP2BMWg9L5wVLKuSITYM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757706844; c=relaxed/simple; bh=6cXgFykumMGSAobanM946a8yCweHLAexqmweAhTT/O8=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=kaZNBirBNFaom18LNp06XcwAT1t1S1eVZWmPUajl4R+Zaz6plWCxGwc09hjvZ5MZbhs7/ZexvbaGZvvlLO3P5VZe30KMB7WywNMl9Reu4j+mqIN/pKnA4jCbq8yQoMhngctVTa/oLEX/RlxU92k2JY2Xh4EqGKuYjYYr3Ys6Fe0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=gNtIf5dJ; arc=none smtp.client-ip=209.85.221.43 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="gNtIf5dJ" Received: by mail-wr1-f43.google.com with SMTP id ffacd0b85a97d-3b9edf4cf6cso1819514f8f.3 for ; Fri, 12 Sep 2025 12:54:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1757706840; x=1758311640; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=JRFKheYw65XtHsXGttpFWft6Q64Fu052vOHTho4zEao=; b=gNtIf5dJ9radHwUPCFXWn2iGJxMldL+0AKbrv1R0pD4eZFo8w/mpBHtFT5Igdd8o2t vdaUTELAWEMk19ja6HaEnkkDXwaXEwAD5jFbYIHyZPC2gGA1GZahqebBHQk/NZNLucZj 1S2uNBv01l1Fmrb/bH7HLkTojIXfxTFEsHKEpl6ElOet636LfrW8q/5ISf/LZ0w50MlB Tu9E1cfRnU9gtzSccyyHEAh1rYh0+aAPabngK5LErAOfO0FFynoAYijRoebW4fHvYT0K x3B/oGw9ih+FHr1EHQRCtgLKBaS1KeRcaN0nwdohdAocr/ELTtU9Pt2+S8HIAedYc8+t Ivbw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1757706840; x=1758311640; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=JRFKheYw65XtHsXGttpFWft6Q64Fu052vOHTho4zEao=; b=roIcY00DBh7ItF46iCivWJoC6JzEKEEvzhA9b1DoRLb2lV8cyXCFxEREJhGiqhKJmG xFNAWcLFI2PwuMKbyQBDNTtLqeVgmzYu/wc9uDFp1360VGentTa6BG0DqUWu+uXWM9GD FKrWQLsM6YECnB4B7pHlR+oXRrI3MHzQ7lEXGIiiFWJOTGRJ1ZmHBs3d8sZqxYgFdYbj +5Ntym04+uG+WMya5KDWOb73e63OyACWBwtNFyZBoCg5eSb+vJIiVWDSVAO21HrYZaE3 zs8bq7D+z54dzUXlGBx1JRjwmK6td/wjWGL7pW0R9o5zdq5fWYP+XuQrl3CDHPfkRakv t34A== X-Forwarded-Encrypted: i=1; AJvYcCWUMCPERhJtJSa63Go6kfuO+tl25s9LAD1OVD3ZEGxasjtszOkaoHcFZDGA02qOKe3uQ5jCVM3mHSP1ADs=@vger.kernel.org X-Gm-Message-State: AOJu0YzSrprhoje/EVoQ5herY+vG6u5LqO1HIvtv6UrtBBQZpSGYdjMZ AgxRR4jKSMUaQGPWJomydHxr8iQN+wyAriF5bAvzhP3QB/g6GgV9HcP7 X-Gm-Gg: ASbGncudPIxF80wdNYwI4xk2mGDyEr6MPCMmRllE88MTd1Z8SM5Nf1ZnCxkD1yg5Npn ukTmUYQgGM/sPxVfG2vngw6x+FWBVOPXELf3q6tdL95OKuor2OEEXKj6ETMPg+dk0nNiR8FzAqT EMByGQZq0Ue2jPuBXeZ0CmMl14Pp7xs8TSBrtGWt5Hk1YhzOHqxN/57i0lL6bZr2P9nVYRY8bld GmMajlYkKVKxEkQUKmQVSYlHx6LWxF3Mo7tSw6vkI7buHgxhwxkUidK5mH8uUK+LurnJ2VX06h0 30fLVyXIOZmhnHrDIPSAIRH15RyrwZO5fK7Lm785KjCCtuHNq9lL9KlgIlCZ+y2Xa7/kx39GMxO niJsSXUtLv+68FlwfgxYys9pCVq26d+YHT4uz/wiu0Vn9PokGwACBiwV+iFKRtg== X-Google-Smtp-Source: AGHT+IEK0LKxCJMa3T/FE1yn9jWxr5RDOTIv2yx6yaJq5FGhArNPULJ6e1clvwsJhm+STF6/Bbsbjw== X-Received: by 2002:a5d:5886:0:b0:3e6:116a:8fdf with SMTP id ffacd0b85a97d-3e7658bcb87mr4036656f8f.13.1757706839452; Fri, 12 Sep 2025 12:53:59 -0700 (PDT) Received: from yanesskka.. (node-188-187-35-212.domolink.tula.net. [212.35.187.188]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45e017bfd14sm74650375e9.21.2025.09.12.12.53.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 12 Sep 2025 12:53:59 -0700 (PDT) From: Yana Bashlykova To: "David S. Miller" Cc: Yana Bashlykova , Eric Dumazet , Jakub Kicinski , Paolo Abeni , linux-kernel@vger.kernel.org, netdev@vger.kernel.org, lvc-project@linuxtesting.org Subject: [PATCH 6.1 05/15] genetlink: add test case for family with invalid ops Date: Fri, 12 Sep 2025 22:53:28 +0300 Message-Id: <20250912195339.20635-6-yana2bsh@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250912195339.20635-1-yana2bsh@gmail.com> References: <20250912195339.20635-1-yana2bsh@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add test case that verifies error handling when registering a genetlink family with invalid operations where both doit and dumpit callbacks are NULL. The test registers incorrect_ops_genl_family which contains a command with: - .doit =3D NULL - .dumpit =3D NULL and expects the registration to fail with -EINVAL. This validates proper validation of genetlink operations during family registration. Signed-off-by: Yana Bashlykova --- .../net-pf-16-proto-16-family-PARALLEL_GENL.c | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/drivers/net/genetlink/net-pf-16-proto-16-family-PARALLEL_GENL.= c b/drivers/net/genetlink/net-pf-16-proto-16-family-PARALLEL_GENL.c index 1db5d15a6f2c..245f3b0f4fbb 100644 --- a/drivers/net/genetlink/net-pf-16-proto-16-family-PARALLEL_GENL.c +++ b/drivers/net/genetlink/net-pf-16-proto-16-family-PARALLEL_GENL.c @@ -1089,6 +1089,33 @@ static struct genl_family incorrect_genl_family =3D { .policy =3D my_genl_policy, }; =20 +enum { + INCORRECT_OP_WITH_NULL, +}; + +// Generic Netlink operations with incorrect ops +static const struct genl_ops incorrect_ops_with_null[] =3D { + { + .cmd =3D INCORRECT_OP_WITH_NULL, + .flags =3D 0, + .policy =3D my_genl_policy, // random policy + .doit =3D NULL, // doit and dumpit are NULL --> kernel will send -EINVAL + .dumpit =3D NULL, + }, +}; + +// genl_family struct with incorrect ops +static struct genl_family incorrect_ops_genl_family =3D { + .hdrsize =3D 0, + .name =3D "INCORRECT", + .version =3D 1, + .maxattr =3D 1, + .netnsok =3D true, + .ops =3D incorrect_ops_with_null, // ops contain NULL + .n_ops =3D ARRAY_SIZE(incorrect_ops_with_null), + .policy =3D my_genl_policy, // random policy +}; + static int __init init_netlink(void) { int rc; @@ -1116,6 +1143,16 @@ static int __init init_netlink(void) return rc; } =20 +static int __init incorrect_ops_netlink(void) +{ + int ret; + + ret =3D genl_register_family(&incorrect_ops_genl_family); + if (ret !=3D -EINVAL) + return ret; + return 0; +} + static int __init incorrect_init_netlink(void) { int rc; @@ -1241,6 +1278,10 @@ static int __init module_netlink_init(void) if (ret) goto err_sysfs; =20 + ret =3D incorrect_ops_netlink(); + if (ret) + goto err_sysfs; + ret =3D init_netlink(); if (ret) goto err_sysfs; --=20 2.34.1 From nobody Thu Oct 2 18:21:35 2025 Received: from mail-wr1-f47.google.com (mail-wr1-f47.google.com [209.85.221.47]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BC92C32ED41 for ; Fri, 12 Sep 2025 19:54:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.47 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757706844; cv=none; b=aULAH4VP+F2dAnA/vtKqQKQkTJGjQR5g2OL+AvvG30jKmN9385SrVkRurs/0hjGTqXcoXjrQ6RUK6eDHZX/SmYRh1Y6HS5+8kPaA2KXPzzlKikpiX8eKsmi0p4eR1FZxAk3OsF7PtXWkeQUk+3LcjSSWNZwy9sj2eioqCYcYmik= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757706844; c=relaxed/simple; bh=+Boo+k0xYpHjL8WYaZHWRNLexzGpn7oUg7CNdHKj6jk=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=dN37KAARKgUPwdGsUXLQPXZmGNswo/0oLvippFUG8BNMyjOQV7lQPPnebJAbsoVsZYLwh4cI1k5UimNkjuhk5E8/q2RrkfKy7k5P8y4m/Y1/j73+3DT1VOLl5mb/ZZF5JEaUUY/+59FWkvb/uUcbayK51luYTaws3I3/fYEp4L8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=FN5UiRR3; arc=none smtp.client-ip=209.85.221.47 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="FN5UiRR3" Received: by mail-wr1-f47.google.com with SMTP id ffacd0b85a97d-3df2f4aedc7so1537575f8f.2 for ; Fri, 12 Sep 2025 12:54:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1757706841; x=1758311641; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=oO4u4FYaZSx4aTsmPIso/KYse1z5eIT4Ei8aQ7ydUzs=; b=FN5UiRR32UvorI6pLawMz/XKl8gYxeldbqK64GyxlGtQx/Cz2v0Y92yo4IGLOYsWlP BegDggNJyIeDo3bkZjEftz5o+IZSTKayHEgurqZDGGtjUsvnxgbA4QQnmJkOvammvJg6 YHtd1PTmhEOI9WM+3RRKhe8g5Dvu8Mm1Ciwvxj2kX6OasOfG4Q7/Lij6kfKleCQtNZ0X Or/xRkNBE0p1lJt6QjGp7L9TOF4hYLvjtRJAxqZ4NCEF6jKjNHqgA5CvLnm4oIiiatNi mHtjy5ryPkvN7zDhCDYwVDpyFU28kIaLsvY/wqOyhI6/cTLNh69Da9/PMI8ID+WLGVSL H6Pg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1757706841; x=1758311641; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=oO4u4FYaZSx4aTsmPIso/KYse1z5eIT4Ei8aQ7ydUzs=; b=RKb+H/qNqQOYxzkhCVzcxyMbX9XVW+fpFkcJ2ha8gjqPG5iSy7UBxLAW0LYwa2XXDm pwMOQ4NYKczxlR5s/dcaB2FHEeiAY5FpLdaKEig8OXcW9I+4G4nE0QbVUK0kpQ7cUgR4 T2eWOkR8KLUzMGntC49KL+QoWegnLRLrSfAFERJ+6i5nUJ5rpycfNbPLBVrVTY5MIGVe iYIMYnlLfgMSYjZaS8SJgQWdgHRPuJNVWGiTWm57X3jjVgMIhIxLiKeeCApiuJ6ADavj qWFA51o2HmjvujNwdJF6F8P+FZxD6+ibcQEdl2qEGETViKTeb7xJx5bOP2kT6MyCklO5 CtjA== X-Forwarded-Encrypted: i=1; AJvYcCW1hQgciSgWCvjKZYROKL52qyALf6AjkgfxxmGckpKe1JDB3jwHS/tQ2CPRVCFa5nQU5qzWxV8OFTrB+x0=@vger.kernel.org X-Gm-Message-State: AOJu0YxOg2zV1bhdzZw5jIJNaSSFfhWhDTeU+RKqR5Vvd4RLX1b95Rh/ 6pDk2BrnH0qy8bg7DIKmmc2LERf9D3TxPwiId8tvIX0zVADgH4fWYMjB X-Gm-Gg: ASbGnculK9dSOvlw02yrl405OSOZ6M3Kj36J3D+oXwB3AGxOwnYhM3qGrAzbgEp2/Aq JWMB1xNjK5CG3DIrCgtPTOJQB5m65IACTCrmUO4Wxlpq+dddEoYjLXbV5Qzl7jM1n4H9A6iRbS3 xzH97LjyNZDuqkZmPx6/e+cQHYGi0L7tUjMSQFyxP6FvFtOePdwXs51Y50e9iui+ayk7Mxj91gb KrjIolO8/Jxxf2SIEhGD+/4zGu95DwOIwxjcqlRpFihXab3ugcq9PIR+dkoKO8N7KKrVbiy0MUn 74tSMMQZS6Anry/oB7Zs/Es3trytAQWOOrct01/bcPO5iVBQqa3EcYlA/w5tKMy2LImsWd+iO+X nsG+taE1yIxzR4ycl+eq2WM+LUnP9+6w3YpI8N8wDeGu28ynz4Jb16AcEIOC9h6gkdZIGCoGI X-Google-Smtp-Source: AGHT+IGdFk9BCXQgcCSNLpqk6aqpiGjSFef9ADNz7e0+I/JWZ5lLT7g+GRXlT2NPW59FSecWmq1UlQ== X-Received: by 2002:a05:6000:26c8:b0:3e4:f194:2872 with SMTP id ffacd0b85a97d-3e765a140damr3473035f8f.31.1757706840813; Fri, 12 Sep 2025 12:54:00 -0700 (PDT) Received: from yanesskka.. (node-188-187-35-212.domolink.tula.net. [212.35.187.188]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45e017bfd14sm74650375e9.21.2025.09.12.12.53.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 12 Sep 2025 12:54:00 -0700 (PDT) From: Yana Bashlykova To: "David S. Miller" Cc: Yana Bashlykova , Eric Dumazet , Jakub Kicinski , Paolo Abeni , linux-kernel@vger.kernel.org, netdev@vger.kernel.org, lvc-project@linuxtesting.org Subject: [PATCH 6.1 06/15] genetlink: add netlink notifier support Date: Fri, 12 Sep 2025 22:53:29 +0300 Message-Id: <20250912195339.20635-7-yana2bsh@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250912195339.20635-1-yana2bsh@gmail.com> References: <20250912195339.20635-1-yana2bsh@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add basic netlink notifier to monitor genetlink events: - Simple ntf_genl_event() callback returning NOTIFY_OK - Register/unregister in module init/exit - Error handling for registration Prepares infrastructure for tracking family registration events. Signed-off-by: Yana Bashlykova --- .../net-pf-16-proto-16-family-PARALLEL_GENL.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/net/genetlink/net-pf-16-proto-16-family-PARALLEL_GENL.= c b/drivers/net/genetlink/net-pf-16-proto-16-family-PARALLEL_GENL.c index 245f3b0f4fbb..cdedd77b2a1b 100644 --- a/drivers/net/genetlink/net-pf-16-proto-16-family-PARALLEL_GENL.c +++ b/drivers/net/genetlink/net-pf-16-proto-16-family-PARALLEL_GENL.c @@ -1116,6 +1116,16 @@ static struct genl_family incorrect_ops_genl_family = =3D { .policy =3D my_genl_policy, // random policy }; =20 +static int ntf_genl_event(struct notifier_block *nb, unsigned long state, + void *_notify) +{ + return NOTIFY_OK; +} + +static struct notifier_block genl_notifier =3D { + .notifier_call =3D ntf_genl_event, +}; + static int __init init_netlink(void) { int rc; @@ -1291,8 +1301,16 @@ static int __init module_netlink_init(void) if (ret) pr_err("%s: Incorrect Generic Netlink family wasn't registered\n", __fun= c__); =20 + ret =3D netlink_register_notifier(&genl_notifier); + if (ret) + goto err_family; + return 0; =20 + // netlink_unregister_notifier(&genl_notifier); +err_family: + genl_unregister_family(&my_genl_family); + genl_unregister_family(&my_genl_family_parallel); err_sysfs: sysfs_remove_file(kobj_genl_test, &my_attr_u32_genl_test.attr); sysfs_remove_file(kobj_genl_test, &my_attr_str_genl_test.attr); @@ -1309,6 +1327,7 @@ static int __init module_netlink_init(void) =20 static void __exit module_netlink_exit(void) { + netlink_unregister_notifier(&genl_notifier); genl_unregister_family(&my_genl_family); genl_unregister_family(&my_genl_family_parallel); =20 --=20 2.34.1 From nobody Thu Oct 2 18:21:35 2025 Received: from mail-wm1-f47.google.com (mail-wm1-f47.google.com [209.85.128.47]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DC4A93375AB for ; Fri, 12 Sep 2025 19:54:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.47 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757706845; cv=none; b=bGZGQKloh+AQWvGoizmSMYYKDtDPvwTPxJKlLFvobLq3Y1FSWg/yqBU3ZdYzPvkZkGNHWicjG/iIF4wrKJoXth9TBJShQX50BPstcj1TbuFD2s/l5/qcPPixVkR3/+w21LKALJ2lE0qfhe5icecd7EvSVDqLk17yxl4b6QzzjtM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757706845; c=relaxed/simple; bh=vtDr/kO1KchOCd5UEjGrTzcH3EcLOyUzNxhEjmZWIks=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=rjm035nGjQ6B2Y43dp/wW5Ylub00zAPz7xSxdZ6sHpiTj8zymRcIru+o9OI3KJHRH/Ln/rvWnNxPiFeLqt2PoArvCct23rkdtfmHdyD0pIX9S164Y+6APociXQyUsQpS8QnfpPjf1LlvG7AImCpdMFUZre9X82+na7xSml5gXiU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=DjxY9xfs; arc=none smtp.client-ip=209.85.128.47 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="DjxY9xfs" Received: by mail-wm1-f47.google.com with SMTP id 5b1f17b1804b1-45b4d89217aso16434255e9.2 for ; Fri, 12 Sep 2025 12:54:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1757706842; x=1758311642; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=RMaCvv0Npwgx9oOEe08/7S4E7IejpQl1+Xgtp1j/Fs0=; b=DjxY9xfsTYSWk4yR99ILE8xz3o2YSg36NeLT/0A2zoMV3EWUuOrsgn1WIyXCR6ANPo UYyLI6YmX1CE6xVed3nBQyAt0A6is/FMJ/Q5g/DEJDDoMmkEkPdijK+A0J0q7OBB4rwz ao0Ubnqb49/zIRFbcuJGVOvYy0AIXEeQ06wEQCJaNHDQswIy0JICDIZLzwlh58zNmNkS KBj5/TlTzGm79+LWErw8FPdnSzmR2MWhRJiosaZh/CryQAfQfMYf4wLsObNr40kdOsrT C+RrSBMBvYu7A3ZT8o70mVOUP8W0JK9FHpS1HXmQwaIawQXHynkVc+tBUjGxuZNMrrv5 6x9Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1757706842; x=1758311642; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=RMaCvv0Npwgx9oOEe08/7S4E7IejpQl1+Xgtp1j/Fs0=; b=c3EClZOju1vOrRMo5FdCtnU3oC0+1/Qf4TKW87OJN5SAfs3IvuAZCykw+H2kZkTxXt Sc7k5XhaRyG4qNHUEFvuYGpI2NDaSAd6oE272w+sJKAdt59h2ib2pMaAcv72NbMSbU9i xIT+4F6V3UetYajv1+0tX98q4UxyT9KqbDUF+kxYTGgK0dXekMC7IiagmSPdJ/V2UtP/ E+565TpYfXZfRh7wOQh/Z79NI9UzQ6i1H+LKnr3khBcfYY9TyDSz9Ogmsc4VcLMgxlcq VTLbPgyRebxbEEWDt6pSTKcc3cQjn+xNTFtValKklTAOE8dGxO54Wi5CiR6VEDVuHZvd ixbg== X-Forwarded-Encrypted: i=1; AJvYcCUwQnc3DZfJctwLheRAOvCSebc9+Skjo7RxSelbICPGyhFENLlQEQE+JZ2ocKCmzZaqVgIAg4CYrPzQx0Y=@vger.kernel.org X-Gm-Message-State: AOJu0YwZkJfQtDbMEe3t9M2YSbmuYSrMB3htiVpR/lQXc2b9uN+nDftV T6mC/3mRpeSPdtWAoAzzF2Cli5AejBiVCdqLB1bJWTiK1f0CvIlK3gTu X-Gm-Gg: ASbGncvbcnEiDbQ5/sF+5Gl79URw3fpGhBh3jPgxZsAjP8Fpg2NNVnakFYE6G81io3Y 7vCXhQ7J3ZMarGUHaarvalxLm0oJlr5yfzpt4H/psW5Xr5EtigFsi4kNskVVCNJ7bjnufTueoKC lsTvAdUeLippWV1joAFGz21ePXB7BL4nVqlEBEmWmyKDq8A2qI8vk9mBDpBP9qp2GCcAanCT9lg LdXdOn3AE+1eD/jvl0qUUzyeTFBY5Aqjws15h5BBZOAGzAHJNloAubd8qnWuhPRwX+1A02trB5p VYTPzk5QlbK02yDBc6w+txiLE8Kd3RyIfth/mMY0ea0IdvhWuZ+vZhqKUsBJIWYDXwVU3m3vo4F iSyJoh9uUuoy5c11vil08CpWzUbryfR3Iat7AmSb+r//PxXGWZPHMqFt6RrvEVDwkiqujHIas X-Google-Smtp-Source: AGHT+IHOezLJRLoDEw/gyTNCxGzG6tpMAlxv09ll/ErrKIIhPmloNLfh1ZLyplu0Cr/e++Aufdl6nA== X-Received: by 2002:a05:6000:178e:b0:3d6:212b:9ae2 with SMTP id ffacd0b85a97d-3e765a53ca5mr3716925f8f.63.1757706842098; Fri, 12 Sep 2025 12:54:02 -0700 (PDT) Received: from yanesskka.. (node-188-187-35-212.domolink.tula.net. [212.35.187.188]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45e017bfd14sm74650375e9.21.2025.09.12.12.54.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 12 Sep 2025 12:54:01 -0700 (PDT) From: Yana Bashlykova To: "David S. Miller" Cc: Yana Bashlykova , Eric Dumazet , Jakub Kicinski , Paolo Abeni , linux-kernel@vger.kernel.org, netdev@vger.kernel.org, lvc-project@linuxtesting.org Subject: [PATCH 6.1 07/15] genetlink: add THIRD_GENL family Date: Fri, 12 Sep 2025 22:53:30 +0300 Message-Id: <20250912195339.20635-8-yana2bsh@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250912195339.20635-1-yana2bsh@gmail.com> References: <20250912195339.20635-1-yana2bsh@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" - New family with echo command - Supports string and flag attributes - Sysfs interface at /sys/kernel/third_genl/message Signed-off-by: Yana Bashlykova --- .../net-pf-16-proto-16-family-PARALLEL_GENL.c | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/drivers/net/genetlink/net-pf-16-proto-16-family-PARALLEL_GENL.= c b/drivers/net/genetlink/net-pf-16-proto-16-family-PARALLEL_GENL.c index cdedd77b2a1b..f651159a311c 100644 --- a/drivers/net/genetlink/net-pf-16-proto-16-family-PARALLEL_GENL.c +++ b/drivers/net/genetlink/net-pf-16-proto-16-family-PARALLEL_GENL.c @@ -152,10 +152,13 @@ static DEFINE_MUTEX(genl_mutex); =20 #define PARALLEL_GENL_FAMILY_NAME "PARALLEL_GENL" =20 +#define THIRD_GENL_FAMILY_NAME "THIRD_GENL" + #define PATH_GENL_TEST_NUM "/sys/kernel/genl_test/value" #define PATH_GENL_TEST_MES "/sys/kernel/genl_test/message" #define PATH_GENL_TEST_DEV "/sys/kernel/genl_test/some_info" #define PATH_PARALLEL_GENL_MES "/sys/kernel/parallel_genl/message" +#define PATH_THIRD_GENL_MES "/sys/kernel/third_genl/message" =20 // TEST_GENL enum { @@ -205,6 +208,8 @@ static struct genl_family my_genl_family; =20 static struct genl_family my_genl_family_parallel; =20 +static struct genl_family third_genl_family; + enum my_multicast_groups { MY_MCGRP_GENL, }; @@ -1077,6 +1082,94 @@ static struct genl_family my_genl_family_parallel = =3D { .n_mcgrps =3D ARRAY_SIZE(genl_many_mcgrps_two), }; =20 +// THIRD_GENL +enum { + THIRD_GENL_ATTR_UNSPEC, + THIRD_GENL_ATTR_DATA, + THIRD_GENL_ATTR_FLAG, + __THIRD_GENL_ATTR_MAX, +}; + +#define THIRD_GENL_ATTR_MAX (__THIRD_GENL_ATTR_MAX - 1) + +enum { + THIRD_GENL_CMD_UNSPEC, + THIRD_GENL_CMD_ECHO, + __THIRD_GENL_CMD_MAX, +}; + +#define THIRD_GENL_CMD_MAX (__THIRD_GENL_CMD_MAX - 1) + +static const struct nla_policy third_genl_policy[THIRD_GENL_ATTR_MAX + 1] = =3D { + [THIRD_GENL_ATTR_UNSPEC] =3D { .type =3D NLA_UNSPEC }, + [THIRD_GENL_ATTR_DATA] =3D { .type =3D NLA_STRING }, + [THIRD_GENL_ATTR_FLAG] =3D { .type =3D NLA_FLAG }, +}; + +// Functions for THIRD_GENL family +static int third_genl_echo(struct sk_buff *skb, struct genl_info *info) +{ + struct sk_buff *msg; + void *data; + int ret; + char *str; + + if (info->nlhdr->nlmsg_flags & NLM_F_ECHO) { + msg =3D genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + data =3D genlmsg_put_reply(msg, info, &my_genl_family, 0, + THIRD_GENL_CMD_ECHO); + if (!data) + goto error; + + str =3D "Hello from THIRD_GENL!"; + strcpy(sysfs_data.third_genl_message, str); + + ret =3D nla_put_string(msg, THIRD_GENL_ATTR_DATA, str); + if (ret < 0) + goto error; + + ret =3D nla_put_flag(msg, THIRD_GENL_ATTR_FLAG); + if (ret < 0) + goto error; + + genlmsg_end(msg, data); + + genlmsg_reply(msg, info); + } + + return 0; + +error: + nlmsg_free(msg); + return -EMSGSIZE; +} + +// Generic Netlink operations for THIRD_GENL family +static const struct genl_ops third_genl_ops[] =3D { + { + .cmd =3D THIRD_GENL_CMD_ECHO, + .flags =3D 0, + .policy =3D third_genl_policy, + .doit =3D third_genl_echo, + .dumpit =3D NULL, + }, +}; + +// genl_family struct for THIRD_GENL family +static struct genl_family third_genl_family =3D { + .hdrsize =3D 0, + .name =3D THIRD_GENL_FAMILY_NAME, + .version =3D 1, + .maxattr =3D THIRD_GENL_ATTR_MAX, + .netnsok =3D true, + .ops =3D third_genl_ops, + .n_ops =3D ARRAY_SIZE(third_genl_ops), + .policy =3D third_genl_policy, +}; + // genl_family struct with incorrect name static struct genl_family incorrect_genl_family =3D { .hdrsize =3D 0, @@ -1144,8 +1237,16 @@ static int __init init_netlink(void) goto failure_2; } =20 + rc =3D genl_register_family(&third_genl_family); + if (rc) { + pr_err("%s: Failed to register Generic Netlink family\n", __func__); + goto failure_3; + } + return 0; =20 +failure_3: + genl_unregister_family(&my_genl_family_parallel); failure_2: genl_unregister_family(&my_genl_family); failure_1: @@ -1311,6 +1412,7 @@ static int __init module_netlink_init(void) err_family: genl_unregister_family(&my_genl_family); genl_unregister_family(&my_genl_family_parallel); + genl_unregister_family(&third_genl_family); err_sysfs: sysfs_remove_file(kobj_genl_test, &my_attr_u32_genl_test.attr); sysfs_remove_file(kobj_genl_test, &my_attr_str_genl_test.attr); @@ -1330,6 +1432,7 @@ static void __exit module_netlink_exit(void) netlink_unregister_notifier(&genl_notifier); genl_unregister_family(&my_genl_family); genl_unregister_family(&my_genl_family_parallel); + genl_unregister_family(&third_genl_family); =20 sysfs_remove_file(kobj_genl_test, &my_attr_u32_genl_test.attr); sysfs_remove_file(kobj_genl_test, &my_attr_str_genl_test.attr); --=20 2.34.1 From nobody Thu Oct 2 18:21:35 2025 Received: from mail-wr1-f51.google.com (mail-wr1-f51.google.com [209.85.221.51]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 13F6E338F58 for ; Fri, 12 Sep 2025 19:54:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.51 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757706846; cv=none; b=k7hqENRHxgUD6DCurW8t3QqSrmS3lNprkFJUDWsHvflE2w4DaS/Rvix3CoRKL7GaZA0IO/HKzaAgn+K+DnPXg7qRI20qWfgiIBEcuRH63YUJktaa4sefXxNkK1epLdzBHXo/Yb/ueCHKbLbtXlwkNXqVzldJCmRyqk3cyJbKkJo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757706846; c=relaxed/simple; bh=i9K1yIVISo2iQdbGiNCGMmX6M0Ed8p2gmujg5khZUS0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=ayoPlsikNJHvRqEZvHrARmolvK02MZV0HHLY5UCz7dU68SXHBsvrELBc2/NFZEey6kGmG42qrea4Vp+2sOJoAErIQjNS5CBbyx5CG3I+FL95rU9R4JisaxxfKZroy5U8+E+DPaSRpCubo/95KaTKCI/+ApziEtEi0ulcWoTh63c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=FmB0KJpX; arc=none smtp.client-ip=209.85.221.51 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="FmB0KJpX" Received: by mail-wr1-f51.google.com with SMTP id ffacd0b85a97d-3e7512c8669so1573945f8f.0 for ; Fri, 12 Sep 2025 12:54:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1757706843; x=1758311643; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=HJf9PqzT7hCLse/9dc5RnwMhZr9VIrZ+OxaGIRW52I4=; b=FmB0KJpXntobLEh5anKKetIlT+aOKPdtezTmCZwruXA/z0THXKhk9Lzhvafj7kTBBe mox4NOch+Rgntf5TObXKiucVCHfRTKDEkpNzpAynLo25CcTnfC4eC+KZxdjMyLqh1p0L 4GtOC5MhB60kSEZdornio4QZEBH9ivwEBpBlPTPK9NIPXwMT1XCsSBUrqLJY+d0ARUlT 4LoJkYsa4iMDNbJ4475xeHp75MSBLFdQUGC5LqmMXOjQzyzUJbA2RagXjIQ5lx8sZ7EH fk+jx6HkWf/I1MmoEShVXghMJXBl6tm0i/mPExaUyeuyWj05g4eL/tciGkYeIR9T+INs dvoA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1757706843; x=1758311643; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=HJf9PqzT7hCLse/9dc5RnwMhZr9VIrZ+OxaGIRW52I4=; b=O6zyhofB3zdwez0nXmb8E4zNx+w/jfH2piKOUlOvAcNKg4+zNff2pQq0KRpGnFXrby 0U8XPtLscp/MNvphUWxk6JURWJze2vO3d2n8vopBGbyX2tACx9Q/MyOdIwel9/PO3Psz FzWTd22TgZIzQdkDCRvZsTSd7tMJI53m50rj75pIhxXT/AM1AkHBDXm6bwjfRNGOPxQM o1Te6PW1QOsK0x8G/lf8YYqtbtiqPhCu33jazfuy8ht9n4+0ekSRqjh4f3EOohiHxDxJ P/ceaxcNND9fU1GhGFpGvIIDvHWFSeBqkHYzfM1fV9xDB6AapgXlA9QJ0WHizGAKmv9m atnA== X-Forwarded-Encrypted: i=1; AJvYcCU5pLbK5yaP40hJAa+2SOKDLcC5Svl5bOWcijiZ2Eyc4IWixRl4Wzvkqul4KZuSNLg4+ce6QyE2p37Muwg=@vger.kernel.org X-Gm-Message-State: AOJu0Yx+KwXUGtMl5L+SM9ae/A88xbFtULTRRhXiNJqnwkUnurYvwwA0 V0uCUo3XOtm40CGj7Tr5jEzK9HeqNhufJmjntR/NloWJGduys5uB+JLe X-Gm-Gg: ASbGncuQWmaxusO2AFH2QCToo5e4ZKIXjlvIDH7YmydV9O0AH10bNqQf6PQW4XFiuVe 36bM8LGhMnbjNMKwTZjnW13e3q8ZnkNiQGXf/uqcnKow3KD6nzj07jwxmKPEvwfWp4O7MGbTwzE CvxoxWM9CxUl0U87iVm00eIbn5gMGgAy/4a9ZyzMysdHi7EYbAKLpjjSV7pfo9E+9JbDad3zJeO 3IMxC3WUOyd118H+vkQ6JjWNVxZ8vNeUXXp8Jf75xr4O20dRNrsNMrPVu/KsChFLhmCvIl1p2mH NbnmC7M8z5/zVg4E/TZUzFg5nyoZmYBMMdBCB49BOoqtT8yOep/io+h9ZsWVJjvfhubn6mDKB3Q lRJQG6bFQO8bZsZB5X8Eppb7AaPpGDCtQIeFrcc6ObhTLmOnExNYT+g9nrpY8O7Yi7AzR1ZSL X-Google-Smtp-Source: AGHT+IEPloYMebO2+94+EujzqnwtJ3qCQMiLzStQnR21n7BZH1TIPhWvC/p9EdtNP7maaHHDBFj5RQ== X-Received: by 2002:a05:6000:26c8:b0:3e4:f194:2872 with SMTP id ffacd0b85a97d-3e765a140damr3473105f8f.31.1757706843387; Fri, 12 Sep 2025 12:54:03 -0700 (PDT) Received: from yanesskka.. (node-188-187-35-212.domolink.tula.net. [212.35.187.188]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45e017bfd14sm74650375e9.21.2025.09.12.12.54.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 12 Sep 2025 12:54:03 -0700 (PDT) From: Yana Bashlykova To: "David S. Miller" Cc: Yana Bashlykova , Eric Dumazet , Jakub Kicinski , Paolo Abeni , linux-kernel@vger.kernel.org, netdev@vger.kernel.org, lvc-project@linuxtesting.org Subject: [PATCH 6.1 08/15] genetlink: verify unregister fails for non-registered family Date: Fri, 12 Sep 2025 22:53:31 +0300 Message-Id: <20250912195339.20635-9-yana2bsh@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250912195339.20635-1-yana2bsh@gmail.com> References: <20250912195339.20635-1-yana2bsh@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Test that genl_unregister_family() returns error when called on non-registered family. Signed-off-by: Yana Bashlykova --- .../net/genetlink/net-pf-16-proto-16-family-PARALLEL_GENL.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/genetlink/net-pf-16-proto-16-family-PARALLEL_GENL.= c b/drivers/net/genetlink/net-pf-16-proto-16-family-PARALLEL_GENL.c index f651159a311c..ad4228eda2d5 100644 --- a/drivers/net/genetlink/net-pf-16-proto-16-family-PARALLEL_GENL.c +++ b/drivers/net/genetlink/net-pf-16-proto-16-family-PARALLEL_GENL.c @@ -1402,6 +1402,10 @@ static int __init module_netlink_init(void) if (ret) pr_err("%s: Incorrect Generic Netlink family wasn't registered\n", __fun= c__); =20 + ret =3D genl_unregister_family(&incorrect_genl_family); + if (ret) + pr_err("%s: Incorrect Generic Netlink family wasn't unregistered\n", __f= unc__); + ret =3D netlink_register_notifier(&genl_notifier); if (ret) goto err_family; --=20 2.34.1 From nobody Thu Oct 2 18:21:35 2025 Received: from mail-wr1-f44.google.com (mail-wr1-f44.google.com [209.85.221.44]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7B686340D83 for ; Fri, 12 Sep 2025 19:54:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.44 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757706849; cv=none; b=QeZ7S+wV5yz44ZGSjrABhK1KvB4W8tGbd5GQFA6pYWJ58q60xvUIZs0EeHinvvnf8YZb+KKNecEbmybk3LoA6XHLfCmc+LCMnxhxzJjCAMijUCvDoRHPn5Mp1vvEeI4f90kW9BNswklZULTsLfTRdoifwO00159TE0VuFCfarHg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757706849; c=relaxed/simple; bh=LDIDm6amXRvxKfZLhIo6Dy6odk1hkniA5SESLkBZmT0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=nLr6h8TvSxexx7GnKUCGYWqaXKF+/WuMYgkCGB+FDq3FJ4g1ygGkStnZ4tk+AA70zr6gTZyEzZ/2fDP9NSSuV5xquzqKSZ64EVuoTJQX0h9OvBDTlpcSroEDDnB/XBi+T2qnTZMt5+ZlNyaKXVt6nw5WeGjG2d4zfg+9n1XTF+0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=U/yFJEa9; arc=none smtp.client-ip=209.85.221.44 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="U/yFJEa9" Received: by mail-wr1-f44.google.com with SMTP id ffacd0b85a97d-3e249a4d605so2514124f8f.3 for ; Fri, 12 Sep 2025 12:54:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1757706845; x=1758311645; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=ZNO8VaIq1C1v07zJmcrQFMbo3suLUEzGA3AO6uFPvqU=; b=U/yFJEa9QyP6eTJV8mu8QyeVy0eBH+jEjUVCT+MchegCc8Q3g1A+sQd6dT4Jy8NDZT 2Z+0D2tlW+bH44P8TszE7mM2YOPrOS8B+Zp+NDi5KNw7/x+BxMwFk07ExIf6mJHtAAXT OpfAM1HNr52yDYEoePbxyRZ6Wn1cx0INRizGnaqj4q4AfTG1I6gSQQJriIjqOYcPhfO3 wJlLaQp3QhubgXdTfG2DdfYQJlG0akWPEd/1cJi4tPar00JQ5CXpKSRJv/1IivCAwQ2D HYzSWAYPqrLvFwTc1LXEdKlEaSpakaJ+jJSqWFWk5PgN5B5YY2i7BYhyRan4HCqwyTkj p1+Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1757706845; x=1758311645; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=ZNO8VaIq1C1v07zJmcrQFMbo3suLUEzGA3AO6uFPvqU=; b=hJkEtqoudwrS6llYr2emHWX5F9pLEddR+tWPgHUNN6ziqaoXyJjy0yvtrn+zuhMi4r zo8poYKc39MUgfEH+405I7F6J8MaLaA9fLFaAPxfdh4/YCvjU8RS/bimdxMUvQGE0R9U z5WbGFivjMvTA2XGTkxvuRBADa01R27Te2Gwyddyoo0IQUW2dhi3x/BrGlI8tBTOvAg1 pJT9dbftYuMUbkoO5btpfr64jQhSjnIoVcNtUBQqjrCUZyrw5CKsID472/4YbdNH+THx qGDqcGMkzFVBxVXV0AGtmx9U2vXG382q11B/b+ZL8ZkKQDTBZpZkB05j8rrvged9373P WLaQ== X-Forwarded-Encrypted: i=1; AJvYcCX65Cvmep4xIOxMoWwUbnoLiOyDsWpg/hujGByP7M5t7kVW3wDW5JNo0483ZJxNLJBy7RgNwbJjv43fndo=@vger.kernel.org X-Gm-Message-State: AOJu0Yx8gzJ5nm+ZgZ7TI9TgyudWUkqI+7WcRlJqL6maPJJ51MTgNdH7 VNcF0z9l+dd6gQfwLAWB5fxM+0u9jvBWB5oOPkiPf8UC9eDHgTe2h5CU X-Gm-Gg: ASbGncv02bLWuxbq+l5p2F4axV7GlUF4IS56VgO/gCV9pW+jKdksUccsf33Dwv22o3h r3fuxTOiKu3U2uYzZAs7ZGH472nahLWiH3e76FXJ7/NQ39KT/5DHEQqqLqYJ1DRX6ViK46dt0Bo 8MdWygdOu6ZOwrLYMQHynyDG2MshdF51kttnc8O5XwWtsLnuIZIWpHICMXxjRqCKEI6lr6qT6ym ibvCuHzgCewNNadgC2xLkQVpMB97QugRezTrzw80pVdKXCERjz0CGgwdATzq3H5W3P0a3WKEb7n rp+mwJpSlJ/ckWC8MjYi0y9wtIksFAmoKOnW/WQ2SkUkGQnqPIdhhF79H6tnTHjiIB+/ihpziBT BF1mKskRb32ZCamHFNr1Z5UEjVMPcImuBShk3t/hnqBjToncZ9TvvyfPsnXYd1g== X-Google-Smtp-Source: AGHT+IGz1qVTn0To3grwW4TfAfgqimwJnbIU2emM/F6SBm49eHIR3hDrHSQxK4zAZ9ajlAEeYcN81g== X-Received: by 2002:a05:6000:208a:b0:3d7:eb95:b1e1 with SMTP id ffacd0b85a97d-3e7659eb4admr2844230f8f.32.1757706844710; Fri, 12 Sep 2025 12:54:04 -0700 (PDT) Received: from yanesskka.. (node-188-187-35-212.domolink.tula.net. [212.35.187.188]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45e017bfd14sm74650375e9.21.2025.09.12.12.54.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 12 Sep 2025 12:54:04 -0700 (PDT) From: Yana Bashlykova To: "David S. Miller" Cc: Yana Bashlykova , Eric Dumazet , Jakub Kicinski , Paolo Abeni , linux-kernel@vger.kernel.org, netdev@vger.kernel.org, lvc-project@linuxtesting.org Subject: [PATCH 6.1 09/15] genetlink: add LARGE_GENL stress test family Date: Fri, 12 Sep 2025 22:53:32 +0300 Message-Id: <20250912195339.20635-10-yana2bsh@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250912195339.20635-1-yana2bsh@gmail.com> References: <20250912195339.20635-1-yana2bsh@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Added new test family with 190+ multicast groups to verify: - Handling of large number of multicast groups - Family registration with many groups The family serves as a stress test for Generic Netlink scalability. Signed-off-by: Yana Bashlykova --- .../net-pf-16-proto-16-family-PARALLEL_GENL.c | 468 +++++++++++++++++- 1 file changed, 467 insertions(+), 1 deletion(-) diff --git a/drivers/net/genetlink/net-pf-16-proto-16-family-PARALLEL_GENL.= c b/drivers/net/genetlink/net-pf-16-proto-16-family-PARALLEL_GENL.c index ad4228eda2d5..0023aeaf4d42 100644 --- a/drivers/net/genetlink/net-pf-16-proto-16-family-PARALLEL_GENL.c +++ b/drivers/net/genetlink/net-pf-16-proto-16-family-PARALLEL_GENL.c @@ -1,4 +1,16 @@ // SPDX-License-Identifier: GPL-2.0 +/* + * Generic Netlink Test Module + * + * Implements test families for Generic Netlink functionality: + * - TEST_GENL: Basic commands with mutex protection + * - PARALLEL_GENL: Advanced ops with parallel dump support + * - THIRD_GENL: Simple message handling supporting many multicast groups + * - LARGE_GENL: Stress test with 190+ multicast groups + * + * Includes sysfs interfaces for manual testing and validation + * of error cases and edge conditions. + */ =20 #include #include @@ -146,6 +158,7 @@ static struct kobj_attribute my_attr_str_third_genl =3D __ATTR(message, 0664, show_third_genl_message, store_third_genl_message); =20 static DEFINE_MUTEX(genl_mutex); +static DEFINE_MUTEX(sysfs_mutex); =20 #define MY_GENL_FAMILY_NAME "TEST_GENL" #define MY_GENL_VERSION 1 @@ -154,6 +167,8 @@ static DEFINE_MUTEX(genl_mutex); =20 #define THIRD_GENL_FAMILY_NAME "THIRD_GENL" =20 +#define LARGE_GENL_FAMILY_NAME "LARGE_GENL" + #define PATH_GENL_TEST_NUM "/sys/kernel/genl_test/value" #define PATH_GENL_TEST_MES "/sys/kernel/genl_test/message" #define PATH_GENL_TEST_DEV "/sys/kernel/genl_test/some_info" @@ -920,6 +935,410 @@ static const struct genl_ops parallel_genl_ops[] =3D { }, }; =20 +enum my_multicast_many_groups_one { + MCGRP_1, + MCGRP_2, + MCGRP_3, + MCGRP_4, + MCGRP_5, + MCGRP_6, + MCGRP_7, + MCGRP_8, + MCGRP_9, + MCGRP_10, + MCGRP_11, + MCGRP_12, + MCGRP_13, + MCGRP_14, + MCGRP_15, + MCGRP_16, + MCGRP_17, + MCGRP_18, + MCGRP_19, + MCGRP_20, + MCGRP_21, + MCGRP_22, + MCGRP_23, + MCGRP_24, + MCGRP_25, + MCGRP_26, + MCGRP_27, + MCGRP_28, + MCGRP_29, + MCGRP_30, + MCGRP_31, + MCGRP_32, + MCGRP_33, + MCGRP_34, + MCGRP_35, + MCGRP_36, + MCGRP_37, + MCGRP_38, + MCGRP_39, + MCGRP_40, + MCGRP_41, + MCGRP_42, + MCGRP_43, + MCGRP_44, + MCGRP_45, + MCGRP_46, + MCGRP_47, + MCGRP_48, + MCGRP_49, + MCGRP_50, + MCGRP_51, + MCGRP_52, + MCGRP_53, + MCGRP_54, + MCGRP_55, + MCGRP_56, + MCGRP_57, + MCGRP_58, + MCGRP_59, + MCGRP_60, + MCGRP_61, + MCGRP_62, + MCGRP_63, + MCGRP_64, + MCGRP_65, + MCGRP_66, + MCGRP_67, + MCGRP_68, + MCGRP_69, + MCGRP_70, + MCGRP_71, + MCGRP_72, + MCGRP_73, + MCGRP_74, + MCGRP_75, + MCGRP_76, + MCGRP_77, + MCGRP_78, + MCGRP_79, + MCGRP_80, + MCGRP_81, + MCGRP_82, + MCGRP_83, + MCGRP_84, + MCGRP_85, + MCGRP_86, + MCGRP_87, + MCGRP_88, + MCGRP_89, + MCGRP_90, + MCGRP_91, + MCGRP_92, + MCGRP_93, + MCGRP_94, + MCGRP_95, + MCGRP_96, + MCGRP_97, + MCGRP_98, + MCGRP_99, + MCGRP_100, + MCGRP_101, + MCGRP_102, + MCGRP_103, + MCGRP_104, + MCGRP_105, + MCGRP_106, + MCGRP_107, + MCGRP_108, + MCGRP_109, + MCGRP_110, + MCGRP_111, + MCGRP_112, + MCGRP_113, + MCGRP_114, + MCGRP_115, + MCGRP_116, + MCGRP_117, + MCGRP_118, + MCGRP_119, + MCGRP_120, + MCGRP_121, + MCGRP_122, + MCGRP_123, + MCGRP_124, + MCGRP_125, + MCGRP_126, + MCGRP_127, + MCGRP_128, + MCGRP_129, + MCGRP_130, + MCGRP_131, + MCGRP_132, + MCGRP_133, + MCGRP_134, + MCGRP_135, + MCGRP_136, + MCGRP_137, + MCGRP_138, + MCGRP_139, + MCGRP_140, + MCGRP_141, + MCGRP_142, + MCGRP_143, + MCGRP_144, + MCGRP_145, + MCGRP_146, + MCGRP_147, + MCGRP_148, + MCGRP_149, + MCGRP_150, + MCGRP_151, + MCGRP_152, + MCGRP_153, + MCGRP_154, + MCGRP_155, + MCGRP_156, + MCGRP_157, + MCGRP_158, + MCGRP_159, + MCGRP_160, + MCGRP_161, + MCGRP_162, + MCGRP_163, + MCGRP_164, + MCGRP_165, + MCGRP_166, + MCGRP_167, + MCGRP_168, + MCGRP_169, + MCGRP_170, + MCGRP_171, + MCGRP_172, + MCGRP_173, + MCGRP_174, + MCGRP_175, + MCGRP_176, + MCGRP_177, + MCGRP_178, + MCGRP_179, + MCGRP_180, + MCGRP_181, + MCGRP_182, + MCGRP_183, + MCGRP_184, + MCGRP_185, + MCGRP_186, + MCGRP_187, + MCGRP_188, + MCGRP_189, + MCGRP_190, + MCGRP_191, + MCGRP_192, + MCGRP_193, + MCGRP_194, + MCGRP_195, + MCGRP_196, + MCGRP_197, + MCGRP_198, + MCGRP_199, +}; + +static const struct genl_multicast_group genl_many_mcgrps_one[] =3D { + [MCGRP_1] =3D { .name =3D "MCGRP_1", }, + [MCGRP_2] =3D { .name =3D "MCGRP_2", }, + [MCGRP_3] =3D { .name =3D "MCGRP_3", }, + [MCGRP_4] =3D { .name =3D "MCGRP_4", }, + [MCGRP_5] =3D { .name =3D "MCGRP_5", }, + [MCGRP_6] =3D { .name =3D "MCGRP_6", }, + [MCGRP_7] =3D { .name =3D "MCGRP_7", }, + [MCGRP_8] =3D { .name =3D "MCGRP_8", }, + [MCGRP_9] =3D { .name =3D "MCGRP_9", }, + [MCGRP_10] =3D { .name =3D "MCGRP_10", }, + [MCGRP_11] =3D { .name =3D "MCGRP_11", }, + [MCGRP_12] =3D { .name =3D "MCGRP_12", }, + [MCGRP_13] =3D { .name =3D "MCGRP_13", }, + [MCGRP_14] =3D { .name =3D "MCGRP_14", }, + [MCGRP_15] =3D { .name =3D "MCGRP_15", }, + [MCGRP_16] =3D { .name =3D "MCGRP_16", }, + [MCGRP_17] =3D { .name =3D "MCGRP_17", }, + [MCGRP_18] =3D { .name =3D "MCGRP_18", }, + [MCGRP_19] =3D { .name =3D "MCGRP_19", }, + [MCGRP_20] =3D { .name =3D "MCGRP_20", }, + [MCGRP_21] =3D { .name =3D "MCGRP_21", }, + [MCGRP_22] =3D { .name =3D "MCGRP_22", }, + [MCGRP_23] =3D { .name =3D "MCGRP_23", }, + [MCGRP_24] =3D { .name =3D "MCGRP_24", }, + [MCGRP_25] =3D { .name =3D "MCGRP_25", }, + [MCGRP_26] =3D { .name =3D "MCGRP_26", }, + [MCGRP_27] =3D { .name =3D "MCGRP_27", }, + [MCGRP_28] =3D { .name =3D "MCGRP_28", }, + [MCGRP_29] =3D { .name =3D "MCGRP_29", }, + [MCGRP_30] =3D { .name =3D "MCGRP_30", }, + [MCGRP_31] =3D { .name =3D "MCGRP_31", }, + [MCGRP_32] =3D { .name =3D "MCGRP_32", }, + [MCGRP_33] =3D { .name =3D "MCGRP_33", }, + [MCGRP_34] =3D { .name =3D "MCGRP_34", }, + [MCGRP_35] =3D { .name =3D "MCGRP_35", }, + [MCGRP_36] =3D { .name =3D "MCGRP_36", }, + [MCGRP_37] =3D { .name =3D "MCGRP_37", }, + [MCGRP_38] =3D { .name =3D "MCGRP_38", }, + [MCGRP_39] =3D { .name =3D "MCGRP_39", }, + [MCGRP_40] =3D { .name =3D "MCGRP_40", }, + [MCGRP_41] =3D { .name =3D "MCGRP_41", }, + [MCGRP_42] =3D { .name =3D "MCGRP_42", }, + [MCGRP_43] =3D { .name =3D "MCGRP_43", }, + [MCGRP_44] =3D { .name =3D "MCGRP_44", }, + [MCGRP_45] =3D { .name =3D "MCGRP_45", }, + [MCGRP_46] =3D { .name =3D "MCGRP_46", }, + [MCGRP_47] =3D { .name =3D "MCGRP_47", }, + [MCGRP_48] =3D { .name =3D "MCGRP_48", }, + [MCGRP_49] =3D { .name =3D "MCGRP_49", }, + [MCGRP_50] =3D { .name =3D "MCGRP_50", }, + [MCGRP_51] =3D { .name =3D "MCGRP_51", }, + [MCGRP_52] =3D { .name =3D "MCGRP_52", }, + [MCGRP_53] =3D { .name =3D "MCGRP_53", }, + [MCGRP_54] =3D { .name =3D "MCGRP_54", }, + [MCGRP_55] =3D { .name =3D "MCGRP_55", }, + [MCGRP_56] =3D { .name =3D "MCGRP_56", }, + [MCGRP_57] =3D { .name =3D "MCGRP_57", }, + [MCGRP_58] =3D { .name =3D "MCGRP_58", }, + [MCGRP_59] =3D { .name =3D "MCGRP_59", }, + [MCGRP_60] =3D { .name =3D "MCGRP_60", }, + [MCGRP_61] =3D { .name =3D "MCGRP_61", }, + [MCGRP_62] =3D { .name =3D "MCGRP_62", }, + [MCGRP_63] =3D { .name =3D "MCGRP_63", }, + [MCGRP_64] =3D { .name =3D "MCGRP_64", }, + [MCGRP_65] =3D { .name =3D "MCGRP_65", }, + [MCGRP_66] =3D { .name =3D "MCGRP_66", }, + [MCGRP_67] =3D { .name =3D "MCGRP_67", }, + [MCGRP_68] =3D { .name =3D "MCGRP_68", }, + [MCGRP_69] =3D { .name =3D "MCGRP_69", }, + [MCGRP_70] =3D { .name =3D "MCGRP_70", }, + [MCGRP_71] =3D { .name =3D "MCGRP_71", }, + [MCGRP_72] =3D { .name =3D "MCGRP_72", }, + [MCGRP_73] =3D { .name =3D "MCGRP_73", }, + [MCGRP_74] =3D { .name =3D "MCGRP_74", }, + [MCGRP_75] =3D { .name =3D "MCGRP_75", }, + [MCGRP_76] =3D { .name =3D "MCGRP_76", }, + [MCGRP_77] =3D { .name =3D "MCGRP_77", }, + [MCGRP_78] =3D { .name =3D "MCGRP_78", }, + [MCGRP_79] =3D { .name =3D "MCGRP_79", }, + [MCGRP_80] =3D { .name =3D "MCGRP_80", }, + [MCGRP_81] =3D { .name =3D "MCGRP_81", }, + [MCGRP_82] =3D { .name =3D "MCGRP_82", }, + [MCGRP_83] =3D { .name =3D "MCGRP_83", }, + [MCGRP_84] =3D { .name =3D "MCGRP_84", }, + [MCGRP_85] =3D { .name =3D "MCGRP_85", }, + [MCGRP_86] =3D { .name =3D "MCGRP_86", }, + [MCGRP_87] =3D { .name =3D "MCGRP_87", }, + [MCGRP_88] =3D { .name =3D "MCGRP_88", }, + [MCGRP_89] =3D { .name =3D "MCGRP_89", }, + [MCGRP_90] =3D { .name =3D "MCGRP_90", }, + [MCGRP_91] =3D { .name =3D "MCGRP_91", }, + [MCGRP_92] =3D { .name =3D "MCGRP_92", }, + [MCGRP_93] =3D { .name =3D "MCGRP_93", }, + [MCGRP_94] =3D { .name =3D "MCGRP_94", }, + [MCGRP_95] =3D { .name =3D "MCGRP_95", }, + [MCGRP_96] =3D { .name =3D "MCGRP_96", }, + [MCGRP_97] =3D { .name =3D "MCGRP_97", }, + [MCGRP_98] =3D { .name =3D "MCGRP_98", }, + [MCGRP_99] =3D { .name =3D "MCGRP_99", }, + [MCGRP_100] =3D { .name =3D "MCGRP_100", }, + [MCGRP_101] =3D { .name =3D "MCGRP_101", }, + [MCGRP_102] =3D { .name =3D "MCGRP_102", }, + [MCGRP_103] =3D { .name =3D "MCGRP_103", }, + [MCGRP_104] =3D { .name =3D "MCGRP_104", }, + [MCGRP_105] =3D { .name =3D "MCGRP_105", }, + [MCGRP_106] =3D { .name =3D "MCGRP_106", }, + [MCGRP_107] =3D { .name =3D "MCGRP_107", }, + [MCGRP_108] =3D { .name =3D "MCGRP_108", }, + [MCGRP_109] =3D { .name =3D "MCGRP_109", }, + [MCGRP_110] =3D { .name =3D "MCGRP_100", }, + [MCGRP_111] =3D { .name =3D "MCGRP_111", }, + [MCGRP_112] =3D { .name =3D "MCGRP_112", }, + [MCGRP_113] =3D { .name =3D "MCGRP_113", }, + [MCGRP_114] =3D { .name =3D "MCGRP_114", }, + [MCGRP_115] =3D { .name =3D "MCGRP_115", }, + [MCGRP_116] =3D { .name =3D "MCGRP_116", }, + [MCGRP_117] =3D { .name =3D "MCGRP_117", }, + [MCGRP_118] =3D { .name =3D "MCGRP_118", }, + [MCGRP_119] =3D { .name =3D "MCGRP_119", }, + [MCGRP_120] =3D { .name =3D "MCGRP_120", }, + [MCGRP_121] =3D { .name =3D "MCGRP_121", }, + [MCGRP_122] =3D { .name =3D "MCGRP_122", }, + [MCGRP_123] =3D { .name =3D "MCGRP_123", }, + [MCGRP_124] =3D { .name =3D "MCGRP_124", }, + [MCGRP_125] =3D { .name =3D "MCGRP_125", }, + [MCGRP_126] =3D { .name =3D "MCGRP_126", }, + [MCGRP_127] =3D { .name =3D "MCGRP_127", }, + [MCGRP_128] =3D { .name =3D "MCGRP_128", }, + [MCGRP_129] =3D { .name =3D "MCGRP_129", }, + [MCGRP_130] =3D { .name =3D "MCGRP_130", }, + [MCGRP_131] =3D { .name =3D "MCGRP_131", }, + [MCGRP_132] =3D { .name =3D "MCGRP_132", }, + [MCGRP_133] =3D { .name =3D "MCGRP_133", }, + [MCGRP_134] =3D { .name =3D "MCGRP_134", }, + [MCGRP_135] =3D { .name =3D "MCGRP_135", }, + [MCGRP_136] =3D { .name =3D "MCGRP_136", }, + [MCGRP_137] =3D { .name =3D "MCGRP_137", }, + [MCGRP_138] =3D { .name =3D "MCGRP_138", }, + [MCGRP_139] =3D { .name =3D "MCGRP_139", }, + [MCGRP_140] =3D { .name =3D "MCGRP_140", }, + [MCGRP_141] =3D { .name =3D "MCGRP_141", }, + [MCGRP_142] =3D { .name =3D "MCGRP_142", }, + [MCGRP_143] =3D { .name =3D "MCGRP_143", }, + [MCGRP_144] =3D { .name =3D "MCGRP_144", }, + [MCGRP_145] =3D { .name =3D "MCGRP_145", }, + [MCGRP_146] =3D { .name =3D "MCGRP_146", }, + [MCGRP_147] =3D { .name =3D "MCGRP_147", }, + [MCGRP_148] =3D { .name =3D "MCGRP_148", }, + [MCGRP_149] =3D { .name =3D "MCGRP_149", }, + [MCGRP_150] =3D { .name =3D "MCGRP_150", }, + [MCGRP_151] =3D { .name =3D "MCGRP_151", }, + [MCGRP_152] =3D { .name =3D "MCGRP_152", }, + [MCGRP_153] =3D { .name =3D "MCGRP_153", }, + [MCGRP_154] =3D { .name =3D "MCGRP_154", }, + [MCGRP_155] =3D { .name =3D "MCGRP_155", }, + [MCGRP_156] =3D { .name =3D "MCGRP_156", }, + [MCGRP_157] =3D { .name =3D "MCGRP_157", }, + [MCGRP_158] =3D { .name =3D "MCGRP_158", }, + [MCGRP_159] =3D { .name =3D "MCGRP_159", }, + [MCGRP_160] =3D { .name =3D "MCGRP_160", }, + [MCGRP_161] =3D { .name =3D "MCGRP_161", }, + [MCGRP_162] =3D { .name =3D "MCGRP_162", }, + [MCGRP_163] =3D { .name =3D "MCGRP_163", }, + [MCGRP_164] =3D { .name =3D "MCGRP_164", }, + [MCGRP_165] =3D { .name =3D "MCGRP_165", }, + [MCGRP_166] =3D { .name =3D "MCGRP_166", }, + [MCGRP_167] =3D { .name =3D "MCGRP_167", }, + [MCGRP_168] =3D { .name =3D "MCGRP_168", }, + [MCGRP_169] =3D { .name =3D "MCGRP_169", }, + [MCGRP_170] =3D { .name =3D "MCGRP_170", }, + [MCGRP_171] =3D { .name =3D "MCGRP_171", }, + [MCGRP_172] =3D { .name =3D "MCGRP_172", }, + [MCGRP_173] =3D { .name =3D "MCGRP_173", }, + [MCGRP_174] =3D { .name =3D "MCGRP_174", }, + [MCGRP_175] =3D { .name =3D "MCGRP_175", }, + [MCGRP_176] =3D { .name =3D "MCGRP_176", }, + [MCGRP_177] =3D { .name =3D "MCGRP_177", }, + [MCGRP_178] =3D { .name =3D "MCGRP_178", }, + [MCGRP_179] =3D { .name =3D "MCGRP_179", }, + [MCGRP_180] =3D { .name =3D "MCGRP_180", }, + [MCGRP_181] =3D { .name =3D "MCGRP_181", }, + [MCGRP_182] =3D { .name =3D "MCGRP_182", }, + [MCGRP_183] =3D { .name =3D "MCGRP_183", }, + [MCGRP_184] =3D { .name =3D "MCGRP_184", }, + [MCGRP_185] =3D { .name =3D "MCGRP_185", }, + [MCGRP_186] =3D { .name =3D "MCGRP_186", }, + [MCGRP_187] =3D { .name =3D "MCGRP_187", }, + [MCGRP_188] =3D { .name =3D "MCGRP_188", }, + [MCGRP_189] =3D { .name =3D "MCGRP_189", }, + [MCGRP_190] =3D { .name =3D "MCGRP_190", }, + [MCGRP_191] =3D { .name =3D "MCGRP_191", }, + [MCGRP_192] =3D { .name =3D "MCGRP_192", }, + [MCGRP_193] =3D { .name =3D "MCGRP_193", }, + [MCGRP_194] =3D { .name =3D "MCGRP_194", }, + [MCGRP_195] =3D { .name =3D "MCGRP_195", }, + [MCGRP_196] =3D { .name =3D "MCGRP_196", }, + [MCGRP_197] =3D { .name =3D "MCGRP_197", }, + [MCGRP_198] =3D { .name =3D "MCGRP_198", }, + [MCGRP_199] =3D { .name =3D "MCGRP_199", }, +}; + enum my_multicast_many_groups_two { MCGRP_TWO_1, MCGRP_TWO_2, @@ -1170,6 +1589,43 @@ static struct genl_family third_genl_family =3D { .policy =3D third_genl_policy, }; =20 +// LARGE_GENL +enum { + LARGE_GENL_CMD_UNSPEC, + LARGE_GENL_CMD_ECHO, + __LARGE_GENL_CMD_MAX, +}; + +#define LARGE_GENL_CMD_MAX (__LARGE_GENL_CMD_MAX - 1) + +static int large_genl_echo(struct sk_buff *skb, struct genl_info *info) +{ + return 0; +} + +// Generic Netlink operations for LARGE_GENL family +static const struct genl_ops large_genl_ops[] =3D { + { + .cmd =3D LARGE_GENL_CMD_ECHO, + .flags =3D 0, + .doit =3D large_genl_echo, + .dumpit =3D NULL, + }, +}; + +// genl_family struct for LARGE_GENL family +static struct genl_family large_genl_family =3D { + .hdrsize =3D 0, + .name =3D LARGE_GENL_FAMILY_NAME, + .version =3D 1, + .maxattr =3D 1, + .netnsok =3D true, + .ops =3D large_genl_ops, + .n_ops =3D ARRAY_SIZE(large_genl_ops), + .mcgrps =3D genl_many_mcgrps_one, + .n_mcgrps =3D ARRAY_SIZE(genl_many_mcgrps_one), +}; + // genl_family struct with incorrect name static struct genl_family incorrect_genl_family =3D { .hdrsize =3D 0, @@ -1237,14 +1693,22 @@ static int __init init_netlink(void) goto failure_2; } =20 - rc =3D genl_register_family(&third_genl_family); + rc =3D genl_register_family(&large_genl_family); if (rc) { pr_err("%s: Failed to register Generic Netlink family\n", __func__); goto failure_3; } =20 + rc =3D genl_register_family(&third_genl_family); + if (rc) { + pr_err("%s: Failed to register Generic Netlink family\n", __func__); + goto failure_4; + } + return 0; =20 +failure_4: + genl_unregister_family(&large_genl_family); failure_3: genl_unregister_family(&my_genl_family_parallel); failure_2: @@ -1417,6 +1881,7 @@ static int __init module_netlink_init(void) genl_unregister_family(&my_genl_family); genl_unregister_family(&my_genl_family_parallel); genl_unregister_family(&third_genl_family); + genl_unregister_family(&large_genl_family); err_sysfs: sysfs_remove_file(kobj_genl_test, &my_attr_u32_genl_test.attr); sysfs_remove_file(kobj_genl_test, &my_attr_str_genl_test.attr); @@ -1437,6 +1902,7 @@ static void __exit module_netlink_exit(void) genl_unregister_family(&my_genl_family); genl_unregister_family(&my_genl_family_parallel); genl_unregister_family(&third_genl_family); + genl_unregister_family(&large_genl_family); =20 sysfs_remove_file(kobj_genl_test, &my_attr_u32_genl_test.attr); sysfs_remove_file(kobj_genl_test, &my_attr_str_genl_test.attr); --=20 2.34.1 From nobody Thu Oct 2 18:21:35 2025 Received: from mail-wr1-f47.google.com (mail-wr1-f47.google.com [209.85.221.47]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 721DC343D63 for ; Fri, 12 Sep 2025 19:54:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.47 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757706851; cv=none; b=WKLkj2UPWJXegVptWZTtcIxZ4QjBynvkQWobPUB6z71Dlj4QoWOrSUX76FISIyZuK1xZObYNJaG04lfv7YcZXoEtwwbFILVv0X4zSzY3EQUGf2y5A99ronPIqxTOkRY0xmLs5wXJp6VJFloGW+riVc4BYeA4K/XDkF2M1WQU9vA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757706851; c=relaxed/simple; bh=UaxWZRT2eVzBCGKMziU2Aq9Id91zLIcnt32JB283AaM=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=p0Hqu/D6+pE1hx8VHVJBr6dJI2Vt0BdE9hoaaU4pD+z12tal4E3oIHGQdKWmdM6TJW3YOoHScCWHL2maLj3MAnFdoAcKXr1tiWgCyLazndTs5FBj56xyB1deJKk15YpPO7uPH32eh3tv8NNy/avfP3NNgEFwONQJvqdV7Y4+whU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=mMhclOse; arc=none smtp.client-ip=209.85.221.47 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="mMhclOse" Received: by mail-wr1-f47.google.com with SMTP id ffacd0b85a97d-3d3ff4a4d6fso1759084f8f.0 for ; Fri, 12 Sep 2025 12:54:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1757706847; x=1758311647; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=crP5kybyDKEP1L3Fsm57wKH5BFdIt0syo+qIG2jEqhk=; b=mMhclOseYfvl0cVXhPsgKksq+KCwHXTcQEx/CbGjJcA842LJo3sh8SJ2HiBFPdyIb6 FWH+LD7NLongLCEUYafG5+L06PRXcbjvlzmEu+IBfH0fy1JsF8lieMSGYccPhjJhbFrd o42ijR1lnTljOjxydmiyGRh6szSXeLYS+1lOGoxjakPfUF1xX2XzaPvAPmA47cGVrY3Q j13hO1dTfJWDjlTVCO0yZ1uXOTUS0+LvP7QJRY4SaqjB4ai7EB1AMtEYICwn8tRRVKjq 0PMSByvAHCN0o7KU8xcnN94Zf2DJPorJVqSRvZRbvzSCiRJUVoERPoa90rFVAiaxfYTa geqw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1757706847; x=1758311647; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=crP5kybyDKEP1L3Fsm57wKH5BFdIt0syo+qIG2jEqhk=; b=GZyXrVmIuTR4KiMb+b73M7DFH5ZXhO6dlRLLGxJv3D1YdAlOQDKX77dRtVxj/DzjGx j1O4M56DxyZ9ybmYDuoy3xAWwc/WnUzjscypi0ojn9O03DKUCsZXk4amKF3Ym4K9WVF9 PZrcHbUPnfbGT5VZeAwy2O1wCirhM6IXKHDf/R72CKjLd5lvWFXJCfV1TcX66gB/0+uw y/F2JNMgja/fVuaGI94A6PMxyV1iIACqr/VNTYm5G+QXDi8V9jRAAwpaaL4vNAytpwfn 39kkGn9Mr4TJYcsMTccmz7UpLRYimxFwZ2uSMGHrzh1ufz20KPmCcoxtFehxVxCgTcAT JMYg== X-Forwarded-Encrypted: i=1; AJvYcCWXzbZx1q+4ewnIanisWd+zWURhRhHy2wGIXZUn8VrMAAMhxKyJ/o7/Ofpm6Fdiec8EAjOGVOboYENJvec=@vger.kernel.org X-Gm-Message-State: AOJu0Yx2pVmUJCiKqSY7U8eUQdKNqqYdF4v3Z/C6JZkweBZTTiEJc1/F Ntb0a4cZZWAFdhJsGF7xIL6j6Hxmp/3SgzU9rg/xGfwnGKQdimOnPIkG X-Gm-Gg: ASbGncv3g8cZNtWpFdI4tmOAeV4LKsTxA3loynmy9A497HzFdWMK2LAtSA+a44fVHiu CwUgvhkcuBIbrWzRO3FiGKZ4GsBQ3xArCDtcaR59hQWThuwjMBbZrTQt0YRm4R2N2QrWe2kXymC /uTx8XjWXUmn5YCLAsWMSVAN6ihchTcMqksRpnDX+w81C8n1ropSfnfAXpc8begLAqRyfiQZPwz IY7uFXk4rnltOI6aIxmvL8F83+WelgCP1bLxG0mysfTwx8Wxh85D99DSa1ugIi/cY0yTmyr8fSh f/M09YCoL88wO7ujCk9Qh8NPrYc3I+aiUS0QuMArvXIXmFYQwkZvhA6Pxt6rUCGjY7GsBCQaxPj fw9sh0lc27nYTHQZQi4Fv3DdB48QRHxtNozJ1Q/WA8KTU65K51cEosxBWPWjtnA1vggIdi1EyLR IwH1LpWzE= X-Google-Smtp-Source: AGHT+IHYbSxBKDnneqMGe4B4GqdstQRPwP2TMBkU5KGjwaP3qxT6Gii/ajCV1viHAEQt0HDASC1PLw== X-Received: by 2002:a05:6000:40cb:b0:3da:d015:bf84 with SMTP id ffacd0b85a97d-3e7659cc7e2mr4361632f8f.25.1757706846599; Fri, 12 Sep 2025 12:54:06 -0700 (PDT) Received: from yanesskka.. (node-188-187-35-212.domolink.tula.net. [212.35.187.188]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45e017bfd14sm74650375e9.21.2025.09.12.12.54.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 12 Sep 2025 12:54:06 -0700 (PDT) From: Yana Bashlykova To: "David S. Miller" Cc: Yana Bashlykova , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Shuah Khan , Paul Walmsley , Palmer Dabbelt , Albert Ou , Nathan Chancellor , Nick Desaulniers , Tom Rix , linux-kernel@vger.kernel.org, netdev@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-riscv@lists.infradead.org, bpf@vger.kernel.org, llvm@lists.linux.dev, lvc-project@linuxtesting.org Subject: [PATCH 6.1 10/15] selftests: net: genetlink: add packet capture test infrastructure Date: Fri, 12 Sep 2025 22:53:33 +0300 Message-Id: <20250912195339.20635-11-yana2bsh@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250912195339.20635-1-yana2bsh@gmail.com> References: <20250912195339.20635-1-yana2bsh@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add test cases for monitoring Netlink traffic during test execution Require CONFIG_NLMON. Signed-off-by: Yana Bashlykova --- tools/testing/selftests/net/Makefile | 6 + tools/testing/selftests/net/genetlink.c | 234 ++++++++++++++++++++++++ 2 files changed, 240 insertions(+) create mode 100644 tools/testing/selftests/net/genetlink.c diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests= /net/Makefile index 69c58362c0ed..0c325ccc5f03 100644 --- a/tools/testing/selftests/net/Makefile +++ b/tools/testing/selftests/net/Makefile @@ -71,6 +71,7 @@ TEST_GEN_FILES +=3D bind_bhash TEST_GEN_PROGS +=3D sk_bind_sendto_listen TEST_GEN_PROGS +=3D sk_connect_zero_addr TEST_PROGS +=3D test_ingress_egress_chaining.sh +TEST_GEN_PROGS +=3D genetlink =20 TEST_FILES :=3D settings =20 @@ -82,3 +83,8 @@ $(OUTPUT)/reuseport_bpf_numa: LDLIBS +=3D -lnuma $(OUTPUT)/tcp_mmap: LDLIBS +=3D -lpthread $(OUTPUT)/tcp_inq: LDLIBS +=3D -lpthread $(OUTPUT)/bind_bhash: LDLIBS +=3D -lpthread + +$(OUTPUT)/genetlink: LDLIBS +=3D -lnl-3 -lnl-genl-3 +$(OUTPUT)/genetlink: CFLAGS +=3D $(shell pkg-config --cflags libnl-3.0 lib= nl-genl-3.0) + +EXTRA_CLEAN :=3D $(SCRATCH_DIR) $(OUTPUT)/genetlink.pcap diff --git a/tools/testing/selftests/net/genetlink.c b/tools/testing/selfte= sts/net/genetlink.c new file mode 100644 index 000000000000..5be9ca68accd --- /dev/null +++ b/tools/testing/selftests/net/genetlink.c @@ -0,0 +1,234 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Generic Netlink and Netlink test cases + * + * This test suite validates various aspects of Generic Netlink and Netlin= k communication + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../kselftest_harness.h" + +#define MY_GENL_FAMILY_NAME "TEST_GENL" +#define MY_GENL_CMD_UNSPEC 0 +#define MY_GENL_CMD_ECHO 1 +#define MY_GENL_CMD_SET_VALUE 2 +#define MY_GENL_CMD_GET_VALUE 3 +#define MY_GENL_CMD_EVENT 4 +#define MY_GENL_CMD_NO_ATTRS 5 + +#define MY_GENL_SMALL_CMD_GET 0 + +#define MY_GENL_ATTR_UNSPEC 0 +#define MY_GENL_ATTR_DATA 1 +#define MY_GENL_ATTR_VALUE 2 +#define MY_GENL_ATTR_PATH 3 +#define MY_GENL_ATTR_NESTED 4 +#define MY_GENL_ATTR_MAX 4 + +#define THIRD_GENL_FAMILY_NAME "THIRD_GENL" + +#define THIRD_GENL_CMD_ECHO 1 + +#define THIRD_GENL_ATTR_UNSPEC 0 +#define THIRD_GENL_ATTR_DATA 1 +#define THIRD_GENL_ATTR_FLAG 2 +#define THIRD_GENL_ATTR_MAX 2 + +#define PATH_GENL_TEST_NUM "/sys/kernel/genl_test/value" +#define PATH_GENL_TEST_MES "/sys/kernel/genl_test/message" +#define PATH_GENL_TEST_DEV "/sys/kernel/genl_test/some_info" +#define PATH_PARALLEL_GENL_MES "/sys/kernel/parallel_genl/message" +#define PATH_THIRD_GENL_MES "/sys/kernel/third_genl/message" + +#define MY_MCGRP_NAME "MY_MCGRP_GENL" + +#define GENL_CTRL "nlctrl" +#define CTRL_ATTR_POLICY_MAX (__CTRL_ATTR_POLICY_DUMP_MAX - 1) + +#define PARALLEL_GENL_FAMILY_NAME "PARALLEL_GENL" +#define PARALLEL_GENL_ATTR_UNSPEC 0 +#define PARALLEL_GENL_CMD_SEND 1 +#define PARALLEL_GENL_CMD_DUMP_INFO 2 +#define PARALLEL_GENL_CMD_SET_VALUE 3 +#define PARALLEL_GENL_CMD_GET_VALUE 4 + +#define PARALLEL_GENL_ATTR_DATA 1 +#define PARALLEL_GENL_ATTR_BINARY 2 +#define PARALLEL_GENL_ATTR_NAME 3 +#define PARALLEL_GENL_ATTR_DESC 4 +#define PARALLEL_GENL_ATTR_FLAG_NONBLOCK 9 +#define PARALLEL_GENL_ATTR_FLAG_BLOCK 10 +#define PARALLEL_GENL_ATTR_PATH 12 +#define PARALLEL_GENL_ATTR_MAX 12 + +#define LARGE_GENL_FAMILY_NAME "LARGE_GENL" + +/* + * Test cases + */ + +/** + * TEST(capture_start) - Starts Netlink traffic capture using nlmon interf= ace + * + * Creates a virtual nlmon interface, enables it and starts packet capture + * with tcpdump. Captured packets are saved to 'genetlink.pcap' file. + * + * Note: + * - Requires root privileges + * - Creates temporary interface 'nlmon0' + * - Runs tcpdump in background + * - Adds small delay to ensure capture starts + */ + +TEST(capture_start) +{ + printf("Running Test: starting Netlink traffic capture...\n"); + + // Only root can monitor Netlink traffic + if (geteuid()) { + SKIP(return, "test requires root"); + return; + } + + char command[256]; + int result; + + snprintf(command, sizeof(command), "ip link add nlmon0 type nlmon"); + result =3D system(command); + ASSERT_EQ(WEXITSTATUS(result), 0); + if (result =3D=3D -1) { + perror("system"); + return; + } + + snprintf(command, sizeof(command), "ip link set nlmon0 up"); + result =3D system(command); + ASSERT_EQ(WEXITSTATUS(result), 0); + if (result =3D=3D -1) { + perror("system"); + return; + } + + snprintf(command, sizeof(command), + "tcpdump -i nlmon0 -w genetlink.pcap &"); + result =3D system(command); + ASSERT_EQ(WEXITSTATUS(result), 0); + if (result =3D=3D -1) { + perror("system"); + return; + } + + printf("nlmon is up. Starting netlink process...\n"); + + sleep(2); + + printf("Starting Netlink tests...\n"); +} + +/** + * TEST(capture_end) - Terminates Netlink traffic monitoring session + * + * Performs controlled shutdown of nlmon capture interface by: + * 1. Stopping tcpdump capture process + * 2. Bringing down nlmon interface + * 3. Deleting nlmon interface + * + * Test Procedure: + * 1. Privilege Check: + * - Verifies root privileges (required for nlmon operations) + * - Gracefully skips if not root + * + * 2. Capture Termination: + * - Stops tcpdump process (2-second delay for cleanup) + * - Brings nlmon0 interface down + * - Deletes nlmon0 interface + * - Validates each operation succeeds + * + * 3. Cleanup Verification: + * - Checks system command exit statuses + * - Provides detailed error reporting + * + * Key Validations: + * - Proper termination of monitoring session + * - Correct interface teardown + * - Root privilege enforcement + * - System command error handling + * + * Expected Behavior: + * - tcpdump process should terminate successfully + * - nlmon0 interface should deactivate cleanly + * - Interface should be removable + * - Non-root execution should skip gracefully + * + * Security Considerations: + * - Requires root for network interface control + * - Ensures complete capture session cleanup + * - Verifies proper resource release + * + * Note: + * - Should be paired with capture_start test + * - Includes 2-second delay for process stabilization + * - Provides status feedback through printf + */ + +TEST(capture_end) +{ + printf("Running Test: stopping Netlink traffic capture...\n"); + + // Only root can monitor Netlink traffic + if (geteuid()) { + SKIP(return, "test requires root"); + return; + } + + char command[256]; + int result; + + sleep(2); + + snprintf(command, sizeof(command), "pkill tcpdump"); + result =3D system(command); + ASSERT_EQ(WEXITSTATUS(result), 0); + if (result =3D=3D -1) { + perror("system"); + return; + } + + snprintf(command, sizeof(command), "ip link set nlmon0 down"); + result =3D system(command); + ASSERT_EQ(WEXITSTATUS(result), 0); + if (result =3D=3D -1) { + perror("system"); + return; + } + + snprintf(command, sizeof(command), "ip link delete nlmon0 type nlmon"); + result =3D system(command); + ASSERT_EQ(WEXITSTATUS(result), 0); + if (result =3D=3D -1) { + perror("system"); + return; + } + + printf("The capturing is over\n"); +} + +TEST_HARNESS_MAIN --=20 2.34.1 From nobody Thu Oct 2 18:21:35 2025 Received: from mail-wm1-f46.google.com (mail-wm1-f46.google.com [209.85.128.46]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EA11734A309 for ; Fri, 12 Sep 2025 19:54:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.46 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757706851; cv=none; b=Bi7eNThEqnKvSb2bfeOgOvl/rIEZyNOJ7srSNaimzVNI+UwaJ5iOiURSBpBSVIeCIDEM6yKM9l0uQLNOQ3eTExlLylWaGZyhKzh0oE4YYYS/sTeeZCL/hDO9u/MLnVWfdApj3Zsu85N0TSuYNyXR4/i/+t5oUL1YGqUgh/6Qqao= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757706851; c=relaxed/simple; bh=6L6KchES0/naZZVCLZ0vGuIX8JBrK81BunZ0ve9LFn8=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=ZzzAFmk87TXyfoVWIiTKvNMs6SnO7s2e2o8s8XusKFSqC/bkivotBhfz9Fbt/Ie6nUGhwHInKAN5xNsYrdFYjICbYvIOL0kFmWl4y8ZJBYN+Luosdf6/Lbx+G184q0b2fSe9nnUtyfNpD3SzLtqSOn/43hblJTd8ZgTNvacmd2Q= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=DpwGrJZ9; arc=none smtp.client-ip=209.85.128.46 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="DpwGrJZ9" Received: by mail-wm1-f46.google.com with SMTP id 5b1f17b1804b1-45dfe95bbb7so21613705e9.1 for ; Fri, 12 Sep 2025 12:54:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1757706848; x=1758311648; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=NQCdu2qqA5L2SEaa+R2ExFgFn5V27LFp3SRYw/lxCRA=; b=DpwGrJZ9lRzNgNehBz1gj1WOlg93536Y346VoX9xDOHyXNwsFnt5x9LLCzVzuJMwQw /G2jnPD0BnRfS6kRayVkBPmr8bxxDp1CsgtDZL2twlqsQXaXQ1O2t8qLvFuVFzVns3Ta LzbNHek95TtEf5FriYW+WDxWyUWNwrTTEIu4OHr4o0FWHmMd5naIJbuynX5G6yXbm+uj 6GQsbRKlc2tKigGMi/Wj9kwgrboFTxmbcqsHJZ0Yr7oX4sdTOxv0o0WeMT4MeZbg329M aKaHRYz11XRdUSoPWN5+zTcnGVrwEMZzNpt5xRvFDhsncpfYrOw67D4HLaTio49WG5m2 9WiQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1757706848; x=1758311648; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=NQCdu2qqA5L2SEaa+R2ExFgFn5V27LFp3SRYw/lxCRA=; b=XlWIAjEkXBjf1mW5hJgkNy+GqpmRXI45punm5CcLqjkNC5L+XKy0J9XWv17u9ehkzB BfoHt5uRdUkL9QL6J3cSqmFZcz85tIj7T6eNnL3hpwLg99xx1dpHfjcXK49KuFIqiUr1 W5AA4TY5XSK5upQjn5TlamhiRMWaY5fHpOgfj0QjK7o/59sHzRwS9Q+BvKtwFRiMIeXG QkuaWp1wucc4eoGLDBJUkB+76GB9vhBxvDEYXhA5DXA1F8fkhicWYOCccFxWRYQGe5Sh HgRjRDKb4SwWZy5yyyX9xJPyYsyk/1Vu3vKXoeVQEKGoe4nHu417iZK/ZLj+WZHvozK6 0Kpw== X-Forwarded-Encrypted: i=1; AJvYcCWozZEzVHYggvIReMOVuRdpC8xisFOmJ9+3ovdemAFGSzjxo7Uimg+9RXAkhKFwSGimMxcUXuWlYDFoKZQ=@vger.kernel.org X-Gm-Message-State: AOJu0Yw7ZRB0LAI2Xs93EHmyiXTjxcv1TuqVc8Q8zuRV4UDukVeahGy+ j8klvC7hgZI8NOJ1PgoLUzzdwIWEF7c77ukxe3mdnAzQsjNFk3DLwxrG X-Gm-Gg: ASbGnctCSnJxhtGf9uJDD+iAt0CK+YVx3LTOd8pduhS2fBneeX9aPqWFHEBHjOii74L hfa8Sd3foYbtdCX9mwB99vFxSJ1sJxWcWl+dCKdUI+JiRQTKWm7E9v4I4++1Jk3EX5hOnmD2JnO 36+25PZjXaegLXzzipzsL963/kNp+YSR5N4FJPkB84/zp57aM646RbSWS8ynh6xndw6hz17hDFv dxw9opEztoH+7bNAQ43rjXQQSVE7MXMmcGaMMgRWiGtpgL59fkIpePJ2xPwvCFl/2uZposTNwgz 5baIQU8Z7VHR021Lc61Oms4UgBLZxGl+qppDIx87wo6aoZnKYxIzutbK/+DA+UsleP+4bEJklVw so2TZgEJGslX/qR1fNb+GYH8aEYDhsy5Gpxs5YuRljnylFjcyZkLyHK/upjX1zw== X-Google-Smtp-Source: AGHT+IG7/dc62nnEkODKkDFjpjftdI9gNf5NvEVk1eA/5v9zXXjcbJVj1cg1bibwNEL1hSD/5mJ+wA== X-Received: by 2002:a05:600c:4748:b0:45b:98d4:5eb7 with SMTP id 5b1f17b1804b1-45f211f8799mr46842565e9.18.1757706848078; Fri, 12 Sep 2025 12:54:08 -0700 (PDT) Received: from yanesskka.. (node-188-187-35-212.domolink.tula.net. [212.35.187.188]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45e017bfd14sm74650375e9.21.2025.09.12.12.54.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 12 Sep 2025 12:54:07 -0700 (PDT) From: Yana Bashlykova To: "David S. Miller" Cc: Yana Bashlykova , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Shuah Khan , netdev@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, lvc-project@linuxtesting.org Subject: [PATCH 6.1 11/15] selftests: net: genetlink: add /proc/net/netlink test Date: Fri, 12 Sep 2025 22:53:34 +0300 Message-Id: <20250912195339.20635-12-yana2bsh@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250912195339.20635-1-yana2bsh@gmail.com> References: <20250912195339.20635-1-yana2bsh@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add test case to verify proper handling of Netlink sockets in procfs: - Tests /proc/net/netlink file accessibility - Validates socket count changes on creation/deletion - Uses kernel's netlink_seq_ops mechanism Checks that socket entries are correctly added/removed from procfs. Signed-off-by: Yana Bashlykova --- tools/testing/selftests/net/genetlink.c | 74 +++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/tools/testing/selftests/net/genetlink.c b/tools/testing/selfte= sts/net/genetlink.c index 5be9ca68accd..f8231a302c36 100644 --- a/tools/testing/selftests/net/genetlink.c +++ b/tools/testing/selftests/net/genetlink.c @@ -81,6 +81,25 @@ =20 #define LARGE_GENL_FAMILY_NAME "LARGE_GENL" =20 +struct nl_sock *socket_alloc_and_conn(void) +{ + struct nl_sock *socket; + + socket =3D nl_socket_alloc(); + if (!socket) { + fprintf(stderr, "Failed to allocate socket\n"); + return NULL; + } + + if (genl_connect(socket)) { + fprintf(stderr, + "Failed to connect to generic netlink through socket\n"); + nl_socket_free(socket); + return NULL; + } + return socket; +} + /* * Test cases */ @@ -143,6 +162,61 @@ TEST(capture_start) printf("Starting Netlink tests...\n"); } =20 +/** + * TEST(open_netlink_file) - Verifies correct reading of Netlink socket in= formation + * + * Tests the /proc/net/netlink interface by: + * 1. Creating a test Netlink socket + * 2. Reading the proc file before and after socket creation + * 3. Verifying the socket count changes as expected + * + * The test checks that: + * - /proc/net/netlink is accessible + * - Entries are properly added/removed + * - Uses kernel's netlink_seq_ops mechanism + */ + +TEST(open_netlink_file) +{ + FILE *file; + char line[256]; + int cnt =3D 0; + + printf("Running Test: opening and reading /proc/net/netlink file...\n"); + + struct nl_sock *sock; + + sock =3D socket_alloc_and_conn(); + + file =3D fopen("/proc/net/netlink", "r"); + ASSERT_NE(NULL, file); + if (file =3D=3D NULL) { + perror("fopen"); + return; + } + + while (fgets(line, sizeof(line), file) !=3D NULL) + cnt++; + + nl_socket_free(sock); + + fclose(file); + + file =3D fopen("/proc/net/netlink", "r"); + ASSERT_NE(NULL, file); + if (file =3D=3D NULL) { + perror("fopen"); + return; + } + + while (fgets(line, sizeof(line), file) !=3D NULL) + cnt--; + + EXPECT_EQ(cnt, 1); + + fclose(file); +} + /** * TEST(capture_end) - Terminates Netlink traffic monitoring session * --=20 2.34.1 From nobody Thu Oct 2 18:21:35 2025 Received: from mail-wm1-f51.google.com (mail-wm1-f51.google.com [209.85.128.51]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AFE6B34DCF7 for ; Fri, 12 Sep 2025 19:54:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.51 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757706854; cv=none; b=dnyYVMeN/rRLfUfztCE59fZAAHUHCFtDTyhVfcOyqk8949vrHp7iSTxfRR7idOpRePElwObQKMr8M2CeHHR8jeXpH5i9HSoAnxa5yTiMIFAXI/alslLBb83wXD/rSZDhWmrKNfvG1rCS799OBKj79XgPdqUJnoZ2B9nu54vJk/8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757706854; c=relaxed/simple; bh=pJHnhqWiYo5cTWEwaTkSoKMKgT9nRFnFPrONnJs+rKc=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=iEyjXI7wJmCAnreDD3Gug36WFRnbMbAs2yetgWUqZ1d0LKWxIm/Tc40kx7+u7+bAscePwvk3gPqrxHX4Kt4zyi6qweZA+xOx1vy9Ra9rwe+ln72kZL25So3gOEp7nxTWopL9AkTxJkJtQ9TXLByBGb60ijnzCni2zT12IHdLRX4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=SJObfN5x; arc=none smtp.client-ip=209.85.128.51 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="SJObfN5x" Received: by mail-wm1-f51.google.com with SMTP id 5b1f17b1804b1-45de1084868so12227565e9.2 for ; Fri, 12 Sep 2025 12:54:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1757706850; x=1758311650; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=4xHrm3UhjY1E+duBeU+wutMGux/GWwKkhqrETHzmbNA=; b=SJObfN5xO2ypN+zFwaCUnHARdTguBmwU95Woh8dBTFmHHbvrEV8+mabV9F6LqOB1UT VCvxUHTPC87zuA+uMn6qn2G0KXpB7W/xohrrr6z6/0tAygWo97TR0Lzi1mLPX/Pocwll u7DOHzcuDbcWz2z6r+miHHzxpB3C8729Eu221REfZ5x1Hvuc5apgf+/w/KTGSJAdb/iR H00yA+xHeKBv9rNL0zFkLZ98w9UWcCibGTFBvdzFd5sQwGDgQXkb28NPPlZRNy2UFzGC BVrzeohCu42mNS0XNYzcMA4crqjDv+lOar3uLUIy5SU0G4PrvzL1R+H4X2+ZNLHxQOSV a7fw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1757706850; x=1758311650; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=4xHrm3UhjY1E+duBeU+wutMGux/GWwKkhqrETHzmbNA=; b=qVKQkxmLuFiipZKkF/G78THth7VRZqPhNnsSlMPIH1X8UYUrBWAJCQBoDMog0blNzV Og1bdKXQsU2faG2mnLEeXa5ahCgo++gWZaYQtf4A/3zSIFAw9tS/DqzKUuTBTZfIveD3 lPSGa3b24Ab/9z/iGZW8esYmBfAkiIf+aszPGVxY89+3SMzp4rIHumJb7VF9aTJPFNox 6op6IqG9DO2kx3RZ9CjnJDGUA0h8P3Uf8Ln+aI8y9fGNRW+1RVWSeYa+6gK4k+EK1KFO WgqwGrlTcSBT6ZeOtdrkphXGQLmu6Tg3hO3HtPT34fiEWYKmdTEXKDrWr46+M550qaks KouA== X-Forwarded-Encrypted: i=1; AJvYcCU6WnijBE1M6Pf15983lTOFDPyi+rAPDWOLz0J66bcjwZAUFVv+A4OuB2zI7hxq1vB9+gPGoEyAMRtuvrg=@vger.kernel.org X-Gm-Message-State: AOJu0YyLiPnRILkmTmUPdKXjNYiNbswOz+dLoZ6IjJvP2TqUQicOV6Hu mFXSgb0IsR3O2/Zt8Fr20hYIpLR5mBJrB93JmyleVt1xS346JKXJ1PSz X-Gm-Gg: ASbGncvjyeqfRC68yl/9a7hU/oIRr9YoIOM4EtosoQ11lekh5Kbn1AexEipWzxBEUqv fhieJz5l337UfHtFXa11+uAZZ8p5fupm9eg8iACeXXPxMnq7xtpKVsjT+9ufjfZM5LioExhsiui z+xPHsW0OSCw3zKDIvpCnUvugNsaUW8b956vUNrLaMQ4APcfrFT86gtaJiSejyLh40XwtTCsTwz 113h92AQga7L1umxHi0rG+O51cMvQ1JiCLem9HoGgL4KaMw0QTpKfpwcv2+tdgzv5+JMFrJi+/A rWxpBK0Ebi91zq4ICPxO6VbWknPnytdah0x6IU1yNpclcjXMWW5TJjXjCd3Tv74uT3svpshlME8 d71x+t3Wl9gVv7gNTxUUc9EJxRkCjRSHBoavJ+dUpGlp8mGyzBoakV6Tun+GyNQ== X-Google-Smtp-Source: AGHT+IEj7jZtshMFUnczbfQcwbELhSqa75oEUSkRUcNPLeWsst/HzcrhQTmsQxXD0MtH+3hn9mT7LQ== X-Received: by 2002:a05:600c:198f:b0:45d:db2a:ce37 with SMTP id 5b1f17b1804b1-45f24df556fmr27201995e9.0.1757706849638; Fri, 12 Sep 2025 12:54:09 -0700 (PDT) Received: from yanesskka.. (node-188-187-35-212.domolink.tula.net. [212.35.187.188]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45e017bfd14sm74650375e9.21.2025.09.12.12.54.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 12 Sep 2025 12:54:09 -0700 (PDT) From: Yana Bashlykova To: "David S. Miller" Cc: Yana Bashlykova , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Shuah Khan , netdev@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, lvc-project@linuxtesting.org Subject: [PATCH 6.1 12/15] selftests: net: genetlink: add Generic Netlink controller tests Date: Fri, 12 Sep 2025 22:53:35 +0300 Message-Id: <20250912195339.20635-13-yana2bsh@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250912195339.20635-1-yana2bsh@gmail.com> References: <20250912195339.20635-1-yana2bsh@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add comprehensive test coverage for nlctrl (Generic Netlink controller) Add my_genl_ctrl_resolve function for resolving family ID Signed-off-by: Yana Bashlykova --- tools/testing/selftests/net/genetlink.c | 925 ++++++++++++++++++++++++ 1 file changed, 925 insertions(+) diff --git a/tools/testing/selftests/net/genetlink.c b/tools/testing/selfte= sts/net/genetlink.c index f8231a302c36..0a05402caa20 100644 --- a/tools/testing/selftests/net/genetlink.c +++ b/tools/testing/selftests/net/genetlink.c @@ -81,6 +81,404 @@ =20 #define LARGE_GENL_FAMILY_NAME "LARGE_GENL" =20 +/** + * Callback data structures - used to pass data between test cases and mes= sage handlers + */ + +struct callback_data_ctrl { + int family_id; + char *family_name; + int op; + struct expected_policies *expected_policy; + int family_index; +}; + +static int elem; + +static int id_elem; + +struct ctrl_policy { + int id; + uint32_t field; + uint32_t type; + int value; +}; + +struct ctrl_policy expected_parallel_policy[] =3D { + { 1, CTRL_ATTR_OP_POLICY, CTRL_ATTR_POLICY_DO, 0 }, + { 2, CTRL_ATTR_OP_POLICY, CTRL_ATTR_POLICY_DUMP, 0 }, + { 3, CTRL_ATTR_OP_POLICY, CTRL_ATTR_POLICY_DO, 1 }, + { 4, CTRL_ATTR_OP_POLICY, CTRL_ATTR_POLICY_DO, 0 }, + { 5, CTRL_ATTR_POLICY, NL_POLICY_TYPE_ATTR_TYPE, 11 }, + { 6, CTRL_ATTR_POLICY, NL_POLICY_TYPE_ATTR_TYPE, 10 }, + { 7, CTRL_ATTR_POLICY, NL_POLICY_TYPE_ATTR_TYPE, 12 }, + { 8, CTRL_ATTR_POLICY, NL_POLICY_TYPE_ATTR_TYPE, 12 }, + { 9, CTRL_ATTR_POLICY, NL_POLICY_TYPE_ATTR_TYPE, 15 }, + { 9, CTRL_ATTR_POLICY, NL_POLICY_TYPE_ATTR_BITFIELD32_MASK, 0 }, + { 10, CTRL_ATTR_POLICY, NL_POLICY_TYPE_ATTR_TYPE, 8 }, + { 10, CTRL_ATTR_POLICY, NL_POLICY_TYPE_ATTR_MIN_VALUE_S, -100 }, + { 10, CTRL_ATTR_POLICY, NL_POLICY_TYPE_ATTR_MAX_VALUE_S, 100 }, + { 11, CTRL_ATTR_POLICY, NL_POLICY_TYPE_ATTR_TYPE, 14 }, + { 12, CTRL_ATTR_POLICY, NL_POLICY_TYPE_ATTR_TYPE, 13 }, + { 13, CTRL_ATTR_POLICY, NL_POLICY_TYPE_ATTR_TYPE, 1 }, + { 14, CTRL_ATTR_POLICY, NL_POLICY_TYPE_ATTR_TYPE, 1 }, + { 15, CTRL_ATTR_POLICY, NL_POLICY_TYPE_ATTR_TYPE, 11 }, +}; + +struct ctrl_policy expected_genl_cmd_get_value_policy[] =3D { + { 1, CTRL_ATTR_OP_POLICY, CTRL_ATTR_POLICY_DO, 0 }, + { 2, CTRL_ATTR_POLICY, NL_POLICY_TYPE_ATTR_TYPE, 11 }, + { 3, CTRL_ATTR_POLICY, NL_POLICY_TYPE_ATTR_TYPE, 4 }, + { 3, CTRL_ATTR_POLICY, NL_POLICY_TYPE_ATTR_MIN_VALUE_U, 0 }, + { 3, CTRL_ATTR_POLICY, NL_POLICY_TYPE_ATTR_MAX_VALUE_U, 100 }, + { 4, CTRL_ATTR_POLICY, NL_POLICY_TYPE_ATTR_TYPE, 11 }, + { 5, CTRL_ATTR_POLICY, NL_POLICY_TYPE_ATTR_TYPE, 13 }, +}; + +struct expected_policies { + struct ctrl_policy *policy; + int count; + int matched; +}; + +struct expected_policies parallel_policy =3D { + .policy =3D expected_parallel_policy, + .count =3D sizeof(expected_parallel_policy) / + sizeof(expected_parallel_policy[0]), + .matched =3D 0, +}; + +struct expected_policies genl_cmd_get_value_policy =3D { + .policy =3D expected_genl_cmd_get_value_policy, + .count =3D sizeof(expected_genl_cmd_get_value_policy) / + sizeof(expected_genl_cmd_get_value_policy[0]), + .matched =3D 0, +}; + +int validate_cb_ctrl(struct nl_msg *msg, void *arg) +{ + struct genlmsghdr *gnlh =3D nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *attrs[CTRL_ATTR_MAX + 1]; + int ret =3D 0; + int family_id =3D -40; + char *family_name =3D NULL; + + ret =3D genlmsg_parse(nlmsg_hdr(msg), 0, attrs, CTRL_ATTR_MAX, NULL); + if (ret < 0) { + printf("Failed to parse attributes: %d\n", ret); + return NL_STOP; + } + + struct callback_data_ctrl *data_ctrl =3D (struct callback_data_ctrl *)arg; + + switch (gnlh->cmd) { + case CTRL_CMD_NEWFAMILY: + if (attrs[CTRL_ATTR_FAMILY_ID]) { + if (data_ctrl->family_name) { + family_name =3D nla_get_string( + attrs[CTRL_ATTR_FAMILY_NAME]); + if (!strcmp(family_name, + data_ctrl->family_name)) { + family_id =3D nla_get_u16( + attrs[CTRL_ATTR_FAMILY_ID]); + data_ctrl->family_id =3D family_id; + } + } + } + if (attrs[CTRL_ATTR_FAMILY_NAME]) { + if (data_ctrl->family_id) { + if (!data_ctrl->family_name) { + family_name =3D nla_get_string( + attrs[CTRL_ATTR_FAMILY_NAME]); + data_ctrl->family_name =3D family_name; + } + } + } + data_ctrl->family_index++; + return NL_OK; + + case CTRL_CMD_GETPOLICY: + struct ctrl_policy *exp =3D + &data_ctrl->expected_policy->policy[elem]; + if (attrs[CTRL_ATTR_FAMILY_ID]) { + family_id =3D nla_get_u16(attrs[CTRL_ATTR_FAMILY_ID]); + data_ctrl->family_id =3D family_id; + } + + if (attrs[CTRL_ATTR_OP_POLICY]) { + struct nlattr *nla; + int rem; + + nla_for_each_nested(nla, attrs[CTRL_ATTR_OP_POLICY], + rem) { + struct nlattr *tb[CTRL_ATTR_POLICY_MAX + 1] =3D { + NULL + }; + + int err =3D nla_parse_nested( + tb, CTRL_ATTR_POLICY_MAX, nla, NULL); + if (err < 0) { + printf("Failed to parse nested policy attributes: %d\n", + err); + continue; + } + + if (tb[CTRL_ATTR_POLICY_DO]) { + uint32_t do_id =3D nla_get_u32( + tb[CTRL_ATTR_POLICY_DO]); + if (exp->field =3D=3D CTRL_ATTR_OP_POLICY && + exp->type =3D=3D CTRL_ATTR_POLICY_DO && + exp->value =3D=3D do_id) { + data_ctrl->expected_policy + ->matched++; + elem++; + if (elem !=3D id_elem) { + exp =3D &data_ctrl + ->expected_policy + ->policy[elem]; + } + } + } + + if (tb[CTRL_ATTR_POLICY_DUMP]) { + uint32_t dump_id =3D nla_get_u32( + tb[CTRL_ATTR_POLICY_DUMP]); + if (exp->field =3D=3D CTRL_ATTR_OP_POLICY && + exp->type =3D=3D + CTRL_ATTR_POLICY_DUMP && + exp->value =3D=3D dump_id) { + data_ctrl->expected_policy + ->matched++; + elem++; + if (elem !=3D id_elem) { + exp =3D &data_ctrl + ->expected_policy + ->policy[elem]; + } + } + } + } + id_elem++; + } + + if (attrs[CTRL_ATTR_POLICY]) { + struct nlattr *policy_attr; + int rem; + + nla_for_each_nested(policy_attr, + attrs[CTRL_ATTR_POLICY], rem) { + struct nlattr *tb[NL_POLICY_TYPE_ATTR_MAX + + 1] =3D { NULL }; + + int err =3D nla_parse_nested( + tb, NL_POLICY_TYPE_ATTR_MAX, + nla_data(policy_attr), NULL); + if (err < 0) { + printf("Failed to parse nested policy attributes: %d\n", + err); + continue; + } + + if (tb[NL_POLICY_TYPE_ATTR_TYPE]) { + uint32_t value1 =3D nla_get_u32( + tb[NL_POLICY_TYPE_ATTR_TYPE]); + if (exp->field =3D=3D CTRL_ATTR_POLICY && + exp->type =3D=3D + NL_POLICY_TYPE_ATTR_TYPE && + exp->value =3D=3D value1) { + data_ctrl->expected_policy + ->matched++; + elem++; + if (elem !=3D id_elem) { + exp =3D &data_ctrl + ->expected_policy + ->policy[elem]; + } + } + } + + if (tb[NL_POLICY_TYPE_ATTR_MIN_VALUE_S]) { + int64_t value2 =3D nla_get_s64( + tb[NL_POLICY_TYPE_ATTR_MIN_VALUE_S]); + if (exp->field =3D=3D CTRL_ATTR_POLICY && + exp->type =3D=3D + NL_POLICY_TYPE_ATTR_MIN_VALUE_S && + exp->value =3D=3D value2) { + data_ctrl->expected_policy + ->matched++; + elem++; + if (elem !=3D id_elem) { + exp =3D &data_ctrl + ->expected_policy + ->policy[elem]; + } + } + } + + if (tb[NL_POLICY_TYPE_ATTR_MAX_VALUE_S]) { + int64_t value3 =3D nla_get_s64( + tb[NL_POLICY_TYPE_ATTR_MAX_VALUE_S]); + if (exp->field =3D=3D CTRL_ATTR_POLICY && + exp->type =3D=3D + NL_POLICY_TYPE_ATTR_MAX_VALUE_S && + exp->value =3D=3D value3) { + data_ctrl->expected_policy + ->matched++; + elem++; + if (elem !=3D id_elem) { + exp =3D &data_ctrl + ->expected_policy + ->policy[elem]; + } + } + } + + if (tb[NL_POLICY_TYPE_ATTR_MIN_VALUE_U]) { + uint64_t value4 =3D nla_get_u64( + tb[NL_POLICY_TYPE_ATTR_MIN_VALUE_U]); + if (exp->field =3D=3D CTRL_ATTR_POLICY && + exp->type =3D=3D + NL_POLICY_TYPE_ATTR_MIN_VALUE_U && + exp->value =3D=3D value4) { + data_ctrl->expected_policy + ->matched++; + elem++; + if (elem !=3D id_elem) { + exp =3D &data_ctrl + ->expected_policy + ->policy[elem]; + } + } + } + + if (tb[NL_POLICY_TYPE_ATTR_MAX_VALUE_U]) { + uint64_t value5 =3D nla_get_u64( + tb[NL_POLICY_TYPE_ATTR_MAX_VALUE_U]); + if (exp->field =3D=3D CTRL_ATTR_POLICY && + exp->type =3D=3D + NL_POLICY_TYPE_ATTR_MAX_VALUE_U && + exp->value =3D=3D value5) { + data_ctrl->expected_policy + ->matched++; + elem++; + } + } + if (tb[NL_POLICY_TYPE_ATTR_MIN_LENGTH]) { + uint32_t value6 =3D nla_get_u32( + tb[NL_POLICY_TYPE_ATTR_MIN_LENGTH]); + if (exp->field =3D=3D CTRL_ATTR_POLICY && + exp->type =3D=3D + NL_POLICY_TYPE_ATTR_MIN_LENGTH && + exp->value =3D=3D value6) { + data_ctrl->expected_policy + ->matched++; + elem++; + if (elem !=3D id_elem) { + exp =3D &data_ctrl + ->expected_policy + ->policy[elem]; + } + } + } + + if (tb[NL_POLICY_TYPE_ATTR_MAX_LENGTH]) { + uint32_t value7 =3D nla_get_u32( + tb[NL_POLICY_TYPE_ATTR_MAX_LENGTH]); + if (exp->field =3D=3D CTRL_ATTR_POLICY && + exp->type =3D=3D + NL_POLICY_TYPE_ATTR_MAX_LENGTH && + exp->value =3D=3D value7) { + data_ctrl->expected_policy + ->matched++; + elem++; + if (elem !=3D id_elem) { + exp =3D &data_ctrl + ->expected_policy + ->policy[elem]; + } + } + } + if (tb[NL_POLICY_TYPE_ATTR_POLICY_IDX]) { + uint32_t value8 =3D nla_get_u32( + tb[NL_POLICY_TYPE_ATTR_POLICY_IDX]); + if (exp->field =3D=3D CTRL_ATTR_POLICY && + exp->type =3D=3D + NL_POLICY_TYPE_ATTR_POLICY_IDX && + exp->value =3D=3D value8) { + data_ctrl->expected_policy + ->matched++; + elem++; + if (elem !=3D id_elem) { + exp =3D &data_ctrl + ->expected_policy + ->policy[elem]; + } + } + } + + if (tb[NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE]) { + uint32_t value9 =3D nla_get_u32( + tb[NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE]); + if (exp->field =3D=3D CTRL_ATTR_POLICY && + exp->type =3D=3D + NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE && + exp->value =3D=3D value9) { + data_ctrl->expected_policy + ->matched++; + elem++; + if (elem !=3D id_elem) { + exp =3D &data_ctrl + ->expected_policy + ->policy[elem]; + } + } + } + if (tb[NL_POLICY_TYPE_ATTR_BITFIELD32_MASK]) { + uint32_t value10 =3D nla_get_u32( + tb[NL_POLICY_TYPE_ATTR_BITFIELD32_MASK]); + if (exp->field =3D=3D CTRL_ATTR_POLICY && + exp->type =3D=3D + NL_POLICY_TYPE_ATTR_BITFIELD32_MASK && + exp->value =3D=3D value10) { + data_ctrl->expected_policy + ->matched++; + elem++; + if (elem !=3D id_elem) { + exp =3D &data_ctrl + ->expected_policy + ->policy[elem]; + } + } + } + + if (tb[NL_POLICY_TYPE_ATTR_PAD]) { + uint64_t value11 =3D nla_get_u64( + tb[NL_POLICY_TYPE_ATTR_PAD]); + if (exp->field =3D=3D CTRL_ATTR_POLICY && + exp->type =3D=3D + NL_POLICY_TYPE_ATTR_PAD && + exp->value =3D=3D value11) { + data_ctrl->expected_policy + ->matched++; + elem++; + if (elem !=3D id_elem) { + exp =3D &data_ctrl + ->expected_policy + ->policy[elem]; + } + } + } + } + id_elem++; + } + return NL_OK; + default: + printf("Unknown command: %u\n", gnlh->cmd); + break; + } + return NL_OK; +} + struct nl_sock *socket_alloc_and_conn(void) { struct nl_sock *socket; @@ -100,6 +498,100 @@ struct nl_sock *socket_alloc_and_conn(void) return socket; } =20 +int my_genl_ctrl_resolve(char *family_name) +{ + struct nl_sock *ctrl_sock; + int genl_ctrl_family_id; + struct nl_msg *msg; + struct genlmsghdr *user_hdr; + struct nl_cb *cb_ctrl; + int err =3D -100; + struct callback_data_ctrl cb_ctrl_data; + + cb_ctrl_data.family_name =3D family_name; + + ctrl_sock =3D socket_alloc_and_conn(); + if (!ctrl_sock) { + fprintf(stderr, "socket for genl_ctrl is NULL\n"); + return -ENOMEM; + } + + genl_ctrl_family_id =3D genl_ctrl_resolve(ctrl_sock, GENL_CTRL); + if (genl_ctrl_family_id < 0) { + fprintf(stderr, + "Failed to resolve family id for genl_ctrl: %d\n", + genl_ctrl_family_id); + err =3D genl_ctrl_family_id; + return err; + } + + msg =3D nlmsg_alloc(); + if (!msg) { + fprintf(stderr, "Failed to allocate message\n"); + nl_socket_free(ctrl_sock); + return -ENOMEM; + } + + user_hdr =3D genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, + genl_ctrl_family_id, 0, + NLM_F_REQUEST | NLM_F_DUMP, CTRL_CMD_GETFAMILY, + 0); + if (!user_hdr) { + fprintf(stderr, "Failed to genlmsg_put\n"); + nlmsg_free(msg); + nl_socket_free(ctrl_sock); + return -ENOMEM; + } + + if (nla_put_string(msg, CTRL_ATTR_FAMILY_NAME, family_name) < 0) { + fprintf(stderr, + "Failed to add CTRL_ATTR_FAMILY_NAME attribute: %s\n", + strerror(errno)); + nlmsg_free(msg); + nl_socket_free(ctrl_sock); + return -EMSGSIZE; + } + + cb_ctrl =3D nl_cb_alloc(NL_CB_DEFAULT); + if (!cb_ctrl) { + fprintf(stderr, "Failed to allocate callback\n"); + nlmsg_free(msg); + nl_socket_free(ctrl_sock); + return -ENOMEM; + } + + err =3D nl_cb_set(cb_ctrl, NL_CB_VALID, NL_CB_CUSTOM, validate_cb_ctrl, + &cb_ctrl_data); + if (err < 0) { + printf("Error setting callback\n"); + goto error; + } + + err =3D nl_send_auto(ctrl_sock, msg); + if (err < 0) { + fprintf(stderr, "Failed to send message: %s\n", + nl_geterror(err)); + goto error; + } + + err =3D nl_recvmsgs(ctrl_sock, cb_ctrl); + if (err < 0) { + fprintf(stderr, "Failed to receive message: %s\n", + nl_geterror(err)); + goto error; + } + + nlmsg_free(msg); + nl_cb_put(cb_ctrl); + nl_socket_free(ctrl_sock); + return cb_ctrl_data.family_id; +error: + nlmsg_free(msg); + nl_cb_put(cb_ctrl); + nl_socket_free(ctrl_sock); + return err; +} + /* * Test cases */ @@ -217,6 +709,439 @@ TEST(open_netlink_file) fclose(file); } =20 +/** + * TEST(genl_ctrl_one_family) - Tests resolution of single Generic Netlink= family + * + * Validates that: + * 1. Controller correctly resolves family ID for given family name + * 2. Family ID obtained through direct query matches cached resolution + * 3. Callback correctly processes controller response + * + * Test flow: + * 1. Creates control socket + * 2. Sends GETFAMILY request for target family + * 3. Validates response through callback + * 4. Compares with direct resolution result + */ + +TEST(genl_ctrl_one_family) +{ + struct nl_sock *ctrl_sock; + int genl_ctrl_family_id; + int family_id; + struct nl_msg *msg; + struct genlmsghdr *user_hdr; + struct nl_cb *cb_ctrl; + int err =3D 0; + struct callback_data_ctrl cb_ctrl_data; + + cb_ctrl_data.family_id =3D -30; + cb_ctrl_data.family_name =3D NULL; + cb_ctrl_data.op =3D -100; + + printf("Running Test: getting family via genl_ctrl...\n"); + + ctrl_sock =3D socket_alloc_and_conn(); + EXPECT_NE(NULL, ctrl_sock); + if (!ctrl_sock) { + fprintf(stderr, "socket for genl_ctrl is NULL\n"); + return; + } + + genl_ctrl_family_id =3D genl_ctrl_resolve(ctrl_sock, GENL_CTRL); + EXPECT_GT(genl_ctrl_family_id, 0); + if (genl_ctrl_family_id < 0) { + fprintf(stderr, + "Failed to resolve family id for genl_ctrl: %d\n", + genl_ctrl_family_id); + err =3D genl_ctrl_family_id; + return; + } + + msg =3D nlmsg_alloc(); + EXPECT_NE(NULL, msg); + if (!msg) { + fprintf(stderr, "Failed to allocate message\n"); + nl_socket_free(ctrl_sock); + return; + } + + user_hdr =3D genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, + genl_ctrl_family_id, 0, NLM_F_REQUEST, + CTRL_CMD_GETFAMILY, 0); + EXPECT_NE(NULL, user_hdr); + if (!user_hdr) { + fprintf(stderr, "Failed to genlmsg_put\n"); + nlmsg_free(msg); + nl_socket_free(ctrl_sock); + return; + } + + if (nla_put_string(msg, CTRL_ATTR_FAMILY_NAME, + PARALLEL_GENL_FAMILY_NAME) < 0) { + fprintf(stderr, + "Failed to add CTRL_ATTR_FAMILY_NAME attribute: %s\n", + strerror(errno)); + nlmsg_free(msg); + nl_socket_free(ctrl_sock); + ASSERT_EQ(0, 1); + return; + } + cb_ctrl_data.family_name =3D PARALLEL_GENL_FAMILY_NAME; + + cb_ctrl =3D nl_cb_alloc(NL_CB_DEFAULT); + EXPECT_NE(NULL, cb_ctrl); + if (!cb_ctrl) { + fprintf(stderr, "Failed to allocate callback\n"); + nlmsg_free(msg); + nl_socket_free(ctrl_sock); + return; + } + + err =3D nl_cb_set(cb_ctrl, NL_CB_VALID, NL_CB_CUSTOM, validate_cb_ctrl, + &cb_ctrl_data); + EXPECT_EQ(err, 0); + if (err < 0) { + printf("Error setting callback\n"); + goto error; + } + + err =3D nl_send_auto(ctrl_sock, msg); + EXPECT_GE(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to send message: %s\n", + nl_geterror(err)); + goto error; + } + + err =3D nl_recvmsgs(ctrl_sock, cb_ctrl); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to receive message: %s\n", + nl_geterror(err)); + goto error; + } + my_genl_ctrl_resolve(PARALLEL_GENL_FAMILY_NAME); + family_id =3D genl_ctrl_resolve(socket_alloc_and_conn(), + PARALLEL_GENL_FAMILY_NAME); + EXPECT_GT(cb_ctrl_data.family_id, 0); + EXPECT_GT(family_id, 0); + EXPECT_EQ(cb_ctrl_data.family_id, family_id); + +error: + nlmsg_free(msg); + nl_cb_put(cb_ctrl); + nl_socket_free(ctrl_sock); +} + +/** + * TEST(genl_ctrl_family) - Tests dumping all registered Generic Netlink f= amilies + * + * Verifies that: + * 1. Controller correctly responds to family dump request + * 2. No errors occur during dump operation + * + * Test flow: + * 1. Creates control socket and resolves genl_ctrl family + * 2. Sends GETFAMILY dump request with NLM_F_DUMP flag + * 3. Checks for operation success + */ + +TEST(genl_ctrl_family) +{ + struct nl_sock *ctrl_sock; + int genl_ctrl_family_id; + struct nl_msg *msg; + struct genlmsghdr *user_hdr; + struct nl_cb *cb_ctrl; + int err =3D 0; + struct callback_data_ctrl cb_ctrl_data; + + cb_ctrl_data.family_id =3D -30; + cb_ctrl_data.family_name =3D NULL; + cb_ctrl_data.op =3D -100; + cb_ctrl_data.family_index =3D 0; + + printf("Running Test: getting families via genl_ctrl...\n"); + + ctrl_sock =3D socket_alloc_and_conn(); + EXPECT_NE(NULL, ctrl_sock); + if (!ctrl_sock) { + fprintf(stderr, "socket for genl_ctrl is NULL\n"); + return; + } + + genl_ctrl_family_id =3D genl_ctrl_resolve(ctrl_sock, GENL_CTRL); + EXPECT_GT(genl_ctrl_family_id, 0); + if (genl_ctrl_family_id < 0) { + fprintf(stderr, + "Failed to resolve family id for genl_ctrl: %d\n", + genl_ctrl_family_id); + err =3D genl_ctrl_family_id; + return; + } + + msg =3D nlmsg_alloc(); + EXPECT_NE(NULL, msg); + if (!msg) { + fprintf(stderr, "Failed to allocate message\n"); + nl_socket_free(ctrl_sock); + return; + } + + user_hdr =3D genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, + genl_ctrl_family_id, 0, NLM_F_DUMP, + CTRL_CMD_GETFAMILY, 0); + EXPECT_NE(NULL, user_hdr); + if (!user_hdr) { + fprintf(stderr, "Failed to genlmsg_put\n"); + nlmsg_free(msg); + nl_socket_free(ctrl_sock); + return; + } + + cb_ctrl =3D nl_cb_alloc(NL_CB_DEFAULT); + EXPECT_NE(NULL, cb_ctrl); + if (!cb_ctrl) { + fprintf(stderr, "Failed to allocate callback\n"); + nlmsg_free(msg); + nl_socket_free(ctrl_sock); + return; + } + + err =3D nl_cb_set(cb_ctrl, NL_CB_VALID, NL_CB_CUSTOM, validate_cb_ctrl, + &cb_ctrl_data); + EXPECT_EQ(err, 0); + if (err < 0) { + printf("Error setting callback\n"); + goto error; + } + + err =3D nl_send_auto(ctrl_sock, msg); + EXPECT_GE(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to send message: %s\n", + nl_geterror(err)); + goto error; + } + + err =3D nl_recvmsgs(ctrl_sock, cb_ctrl); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to receive message: %s\n", + nl_geterror(err)); + goto error; + } + EXPECT_GE(cb_ctrl_data.family_index, 4); + +error: + nlmsg_free(msg); + nl_cb_put(cb_ctrl); + nl_socket_free(ctrl_sock); +} + +/** + * TEST(genl_ctrl_policy) - Validates Generic Netlink policy retrieval mec= hanism + * + * Tests that: + * 1. Policy information can be retrieved by family ID and name + * 2. Operation-specific policies can be retrieved + * 3. Retrieved policies match expected structures + * + * Test sequence: + * 1. Retrieves general policy for PARALLEL_GENL family + * 2. Retrieves operation-specific policy for MY_GENL_CMD_GET_VALUE + * 3. Validates policy contents through callback + */ + +TEST(genl_ctrl_policy) +{ + struct nl_sock *ctrl_sock; + int genl_ctrl_family_id; + struct nl_msg *msg; + struct genlmsghdr *user_hdr; + struct nl_cb *cb_ctrl; + int err =3D 0; + struct callback_data_ctrl cb_ctrl_data; + + cb_ctrl_data.family_id =3D -30; + cb_ctrl_data.family_name =3D NULL; + cb_ctrl_data.op =3D -100; + cb_ctrl_data.expected_policy =3D ¶llel_policy; + cb_ctrl_data.expected_policy->matched =3D 0; + + printf("Running Test: getting policy via genl_ctrl...\n"); + + ctrl_sock =3D socket_alloc_and_conn(); + EXPECT_NE(NULL, ctrl_sock); + if (!ctrl_sock) { + fprintf(stderr, + "sockets for genl_ctrl and parallel_genl are NULL\n"); + return; + } + + genl_ctrl_family_id =3D genl_ctrl_resolve(ctrl_sock, GENL_CTRL); + EXPECT_GT(genl_ctrl_family_id, 0); + if (genl_ctrl_family_id < 0) { + fprintf(stderr, + "Failed to resolve family id for genl_ctrl: %d\n", + genl_ctrl_family_id); + nl_socket_free(ctrl_sock); + return; + } + + printf("Start first message with family id and family name\n"); + msg =3D nlmsg_alloc(); + EXPECT_NE(NULL, msg); + if (!msg) { + fprintf(stderr, "Failed to allocate message\n"); + nl_socket_free(ctrl_sock); + return; + } + + user_hdr =3D genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, + genl_ctrl_family_id, 0, NLM_F_DUMP, + CTRL_CMD_GETPOLICY, 0); + EXPECT_NE(NULL, user_hdr); + if (!user_hdr) { + fprintf(stderr, "Failed to genlmsg_put\n"); + nlmsg_free(msg); + nl_socket_free(ctrl_sock); + return; + } + + if (nla_put_u16(msg, CTRL_ATTR_FAMILY_ID, + genl_ctrl_resolve(ctrl_sock, + PARALLEL_GENL_FAMILY_NAME)) < 0) { + fprintf(stderr, + "Failed to add CTRL_ATTR_FAMILY_ID attribute: %s\n", + strerror(errno)); + nlmsg_free(msg); + nl_socket_free(ctrl_sock); + ASSERT_EQ(0, 1); + return; + } + if (nla_put_string(msg, CTRL_ATTR_FAMILY_NAME, + PARALLEL_GENL_FAMILY_NAME) < 0) { + fprintf(stderr, + "Failed to add CTRL_ATTR_FAMILY_NAME attribute: %s\n", + strerror(errno)); + nlmsg_free(msg); + nl_socket_free(ctrl_sock); + ASSERT_EQ(0, 1); + return; + } + + cb_ctrl =3D nl_cb_alloc(NL_CB_DEFAULT); + EXPECT_NE(NULL, cb_ctrl); + if (!cb_ctrl) { + fprintf(stderr, "Failed to allocate callback\n"); + nlmsg_free(msg); + nl_socket_free(ctrl_sock); + return; + } + + err =3D nl_cb_set(cb_ctrl, NL_CB_VALID, NL_CB_CUSTOM, validate_cb_ctrl, + &cb_ctrl_data); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Error setting callback: %s\n", + nl_geterror(err)); + goto error; + } + + err =3D nl_send_auto(ctrl_sock, msg); + EXPECT_GE(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to send message: %s\n", + nl_geterror(err)); + goto error; + } + + err =3D nl_recvmsgs(ctrl_sock, cb_ctrl); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to receive message: %s\n", + nl_geterror(err)); + goto error; + } + EXPECT_EQ(cb_ctrl_data.expected_policy->matched, + cb_ctrl_data.expected_policy->count); + + printf("[OK] [1/2]\n"); + + cb_ctrl_data.expected_policy =3D &genl_cmd_get_value_policy; + cb_ctrl_data.expected_policy->matched =3D 0; + elem =3D 0; + id_elem =3D 0; + + nlmsg_free(msg); + + printf("Start second message with family name and ctrl_attr_op\n"); + msg =3D nlmsg_alloc(); + EXPECT_NE(NULL, msg); + if (!msg) { + fprintf(stderr, "Failed to allocate message\n"); + nl_socket_free(ctrl_sock); + nl_cb_put(cb_ctrl); + return; + } + + user_hdr =3D genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, + genl_ctrl_family_id, 0, NLM_F_DUMP, + CTRL_CMD_GETPOLICY, 0); + EXPECT_NE(NULL, user_hdr); + if (!user_hdr) { + fprintf(stderr, "Failed to genlmsg_put\n"); + goto error; + } + + if (nla_put_string(msg, CTRL_ATTR_FAMILY_NAME, MY_GENL_FAMILY_NAME) < + 0) { + fprintf(stderr, + "Failed to add CTRL_ATTR_FAMILY_NAME attribute: %s\n", + strerror(errno)); + EXPECT_EQ(0, 1); + goto error; + } + + if (nla_put_u32(msg, CTRL_ATTR_OP, MY_GENL_CMD_GET_VALUE) < 0) { + fprintf(stderr, "Failed to add CTRL_ATTR_OP attribute: %s\n", + strerror(errno)); + EXPECT_EQ(0, 1); + goto error; + } + + err =3D nl_send_auto(ctrl_sock, msg); + EXPECT_GE(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to send message: %s\n", + nl_geterror(err)); + goto error; + } + + err =3D nl_recvmsgs(ctrl_sock, cb_ctrl); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to receive message: %s\n", + nl_geterror(err)); + goto error; + } + + EXPECT_EQ(cb_ctrl_data.expected_policy->matched, + cb_ctrl_data.expected_policy->count); + printf("[OK] [2/2]\n"); + + cb_ctrl_data.expected_policy->matched =3D 0; + elem =3D 0; + id_elem =3D 0; + +error: + nlmsg_free(msg); + nl_cb_put(cb_ctrl); + nl_socket_free(ctrl_sock); +} + /** * TEST(capture_end) - Terminates Netlink traffic monitoring session * --=20 2.34.1 From nobody Thu Oct 2 18:21:35 2025 Received: from mail-wm1-f45.google.com (mail-wm1-f45.google.com [209.85.128.45]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CE3FB350D49 for ; Fri, 12 Sep 2025 19:54:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.45 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757706854; cv=none; b=QXgpg4i/9R4evSKbE5aFs5qNu8rWN3199pElGbNgtCKQ2vOF5dTs4YoDNb3OYdHpS6G3qT0d5Wj2bKuAKXXf7BPGBznLcv6sB5bCtobkZd9w2cSoZ/S1odHXyPlNIVf4LhLBU9hHT/Vhy8FAQUc5eStXNulxB2GrkW6lgiu+nwg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757706854; c=relaxed/simple; bh=wyOfA9Z4qZjfSNCnN1Zoeu2Ob0/D/ATgwmgGwmRhB+k=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=nwnGzbaMdiIOC7bFaYDtTIXEAXuDP9ySaxDYmf/eRTKKiKUtXy/z0CkcMOG/f4uX6vJBnzGSYVsTqyadZVJFtYtLA53zNkJpv5Jek0O1GzK20oue8PEF79szjkDIJ/eSKHojnsmlJ0IsYdsZAkK1c35gcaxKaOB57i3kNyUrJXs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=mv8bvXwn; arc=none smtp.client-ip=209.85.128.45 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="mv8bvXwn" Received: by mail-wm1-f45.google.com with SMTP id 5b1f17b1804b1-45dfb8e986aso23917675e9.0 for ; Fri, 12 Sep 2025 12:54:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1757706851; x=1758311651; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=FL67JfuuY9SGdztk1CnmGmCEi73VTYHhsmgmXTv98L4=; b=mv8bvXwnZbyDXMRxWeCJ6EOm6yfmLYsAFxTw1/nSFFIJJOoMOt8QL01FLf0lkQCp/1 bocDdq1cWziNX3nbLYu8uF41JaasPlg28rnnxI/cT8whJg/dG7RUmheUjpf1XWCXo0+R Mwny2WT6MHWWf3hKVbCKj3xpgSpmrKMPuTrYYqEA8BNQKbeIP8KXL5ECZ2k7k9z2PtpM BollAa46Kx4aUnkbrJ8Q1l8YNtI0Kwe6xyBmsx7AZrvjmiicXERzpkevFZnhcrXogfYF y7mn+7eJxgo2P+71/VkIlW5kZ8TgLHP+ycAKNo6qpAtopJDuVazvReGXQO8xgX4h7Q3E e5AQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1757706851; x=1758311651; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=FL67JfuuY9SGdztk1CnmGmCEi73VTYHhsmgmXTv98L4=; b=KOt4KkPk77nKYPnN01HqZQsl3E28huVTeRFO0FDqEwoysEkVDnrJU4Tnk8+NW531dp vCQF3hsdgnbtBxMlH3KKUE9nKyHHOlVcM5iV8DRDGEaegkEYCsfRlj2N4GNr9gnpKMbl tEmqBqbcsRs4F+w4WwUX8aZhKEcQVn5KBY2pfSrgQQQzy+5Rq1YCBL2shJWpFH95DsvC P4+KDB2XAKHU43FLp4fnq5w1Sd4mv9iMd55/gFly92gD6Y6aPCK8gYJoOSbgjDot3qTj f3FfrRSNfMqqSjxBAN9STLjxPcJkCiU4pi110jiI4NgAX3nyTBrKP6PovxsJVlLSvcyZ HHdw== X-Forwarded-Encrypted: i=1; AJvYcCVdEbzDTmXGHK/ymf5Ub1I0NXkv43aQ07ePiqRiMm/41D59CHQiN3ghNlPySuAiNw0KyBIuEVvOJ54JJEU=@vger.kernel.org X-Gm-Message-State: AOJu0YyoK9MNGEWyQ4cU1wXBGVuDQco0DLW7LSgSfe6IwxKJxYCRcJKz Cw1JL/BzDictl/Fn4jRR0lbD3HneOSLy9KFVHsjiB1R1vW1sswW84q7Z X-Gm-Gg: ASbGncsvWpCJGB+5IFo9Sv0Lwx0z+Pn2uAbJ3bImgpG9kbWXRnfIAlDUqOl5fsKppVe vRq6WAbVu/F5JabfqNHTnLhej8IktaOIhnDKQ1581wZ17wOtVVMwF7AxiWappgqTNaoPAPEE+GA grVIdCNbCzwqwCnGtEhNmd3iaXxfnKJOE1y+gh7ubsNuf/fVUEh0R4jpgdhqmRKpb7sYd9e/AEb Vm+l8Yysu+N2bchCMpVhzNPgz1NCaE/Dur66qWm3id3AqEMe94RwTPFuEcZyQ0mFJHdGspAYpTs JIeSKlMsw2B/OR04ssVuy2a64IWwi1G050hrVtK1NQlx2XfGPvWD3XCeRH342iyC+GizhljhFJJ KQ/L++aoX0tM4S/GYiQDGhGGBunJdQ40gsDCjdkf5R/yPFntK8WsA2rM8Zy6ypXqz7eynU5Er X-Google-Smtp-Source: AGHT+IHnxAVngHZQRsePAFq7iynBLmIa8Fg7O2Z7VTvuVafjtGYamzNuY+ON6/+Ls16YAqNHgZJRXg== X-Received: by 2002:a05:600c:350d:b0:45b:9912:9f1e with SMTP id 5b1f17b1804b1-45f211c9c3bmr39664915e9.3.1757706851085; Fri, 12 Sep 2025 12:54:11 -0700 (PDT) Received: from yanesskka.. (node-188-187-35-212.domolink.tula.net. [212.35.187.188]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45e017bfd14sm74650375e9.21.2025.09.12.12.54.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 12 Sep 2025 12:54:10 -0700 (PDT) From: Yana Bashlykova To: "David S. Miller" Cc: Yana Bashlykova , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Shuah Khan , netdev@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, lvc-project@linuxtesting.org Subject: [PATCH 6.1 13/15] selftests: net: genetlink: add large family ID resolution test Date: Fri, 12 Sep 2025 22:53:36 +0300 Message-Id: <20250912195339.20635-14-yana2bsh@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250912195339.20635-1-yana2bsh@gmail.com> References: <20250912195339.20635-1-yana2bsh@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add test case for resolving family IDs of large Generic Netlink families (those with 199+ multicast groups): 1. Tests that standard genl_ctrl_resolve() may fail due to: - Response size exceeding single message limit - Implementation expecting single response 2. Verifies custom my_genl_ctrl_resolve() works by: - Using dump mechanism to collect all responses - Properly handling multi-message replies - Correctly identifying target family The test validates that large families can be reliably resolved despite kernel message size limitations. Signed-off-by: Yana Bashlykova --- tools/testing/selftests/net/genetlink.c | 37 +++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/tools/testing/selftests/net/genetlink.c b/tools/testing/selfte= sts/net/genetlink.c index 0a05402caa20..361840aae918 100644 --- a/tools/testing/selftests/net/genetlink.c +++ b/tools/testing/selftests/net/genetlink.c @@ -1142,6 +1142,43 @@ TEST(genl_ctrl_policy) nl_socket_free(ctrl_sock); } =20 +/** + * TEST(resolve_large_family_id) - Tests resolution of family ID for + * LARGE_GENL Generic Netlink family + * + * Validates special handling required for families with many multicast gr= oups (199+): + * 1. Standard genl_ctrl_resolve() fails due to message size limitations + * 2. Custom my_genl_ctrl_resolve() succeeds by using dump mechanism + * + * Background: + * - Kernel successfully registers large families + * - Standard resolution fails because: + * * Response doesn't fit in single message + * * genl_ctrl_resolve() expects single response + * - Custom solution works by: + * * Using dump request to get all messages + * * Searching for target family in callback + * + * Verification: + * 1. Custom resolver returns valid ID (> 0) + * 2. Standard resolver either fails or succeeds (platform-dependent) + */ + +TEST(resolve_large_family_id) +{ + int family_id; + int no_family_id; + + /* Test custom resolver */ + family_id =3D my_genl_ctrl_resolve(LARGE_GENL_FAMILY_NAME); + EXPECT_TRUE(family_id > 0); + + /* Test standard resolver (may fail) */ + no_family_id =3D genl_ctrl_resolve(socket_alloc_and_conn(), + LARGE_GENL_FAMILY_NAME); + EXPECT_TRUE(no_family_id > 0); +} + /** * TEST(capture_end) - Terminates Netlink traffic monitoring session * --=20 2.34.1 From nobody Thu Oct 2 18:21:35 2025 Received: from mail-wr1-f43.google.com (mail-wr1-f43.google.com [209.85.221.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 289C43568EF for ; Fri, 12 Sep 2025 19:54:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.43 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757706861; cv=none; b=mdKEYYEI/mftl4sCOYZRfGzGD3IdwjISMP2RRaTTli/EdOZQbs2hiV+CcvQi5jsKRiToahWhJa8k/VffK+ghD/Eqriosh1ZZOMdT5CVcNwOr/MFVrpEq4ueY5HlJPurhEZv3f/ZStA0lMVOLZLckgyDcV10BLu1nIQO/UKRwfC8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757706861; c=relaxed/simple; bh=r/SEkcwOHujwUwYsIlfjuR0ak0ppQOmzsVDL4iJn7is=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version:Content-Type; b=RHf1UGQEnhjZc34fLL+/DosX1C7ENkIrGTyJgoR+y3hdb8UoDfICofh9dBU8thOWdKS1dHhfa/aIFgOWpso7iBAX+OfRsamM6Cf9ZJ+iI3AbojQdLQsnfhpr0s0bhe7VqiH6sCTrzCvoe4Aw6N1AV0dlJ0y3Ludqbja2FAzdUgA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=nDiwD/or; arc=none smtp.client-ip=209.85.221.43 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="nDiwD/or" Received: by mail-wr1-f43.google.com with SMTP id ffacd0b85a97d-3db9641b725so1961473f8f.2 for ; Fri, 12 Sep 2025 12:54:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1757706853; x=1758311653; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=sgRQHdcc8YPG0tplcC5WYWa2ScMOYVslMYtlHBH3Ays=; b=nDiwD/or9rPbKEaxVJsJ15UMDBC32wWJK/qKSy8HKVaUWPR4RABzhvPAMt2O0eRrs7 fw+yc/fk1cXa3v1yzcp9OaDDt5RT6PQPX/AlmEiHbz5dJAxYasb0LTUTDxv+Xg31c8BK hR9mBvL4pwuevTHdLUkqh5mZfBhSLLfD5VLV15q+Pa1sCxDdAIOQPShqxwi5asvTeBAV lV78baDjWGjvc8+m5jjVMnifWMG+ukhU8hKXXDOWoZrlcJpi+5p0WUWSxMi9IytAGQH5 Ubpnknd5EM/sjr+8HZTE9PIupAUwIJvVkP/YIgldvpnjhfIt0u3jmOyheIDaqF2HYSAr xvAg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1757706853; x=1758311653; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=sgRQHdcc8YPG0tplcC5WYWa2ScMOYVslMYtlHBH3Ays=; b=tC5laDmwGH01kQ8MKAQ+Uo1YxUJQOJFVKrccjtKuqcuMGGpFC7ydggAp1jnh9n+RuJ dQyVYjDfyCiqJL6hhQbvXSPzaf27DS7Oz7f0k4yKf9VKb/g4p4wx594w7xecyc8RhG7D nVtVVYSgCDJJfCyyG04+vycU3TTOEJSMVHV9BJxAwg7SmGrXkDVYMS2qPSAVNBXe3KNe RhZ3zzC0TO8oTlOazD0VaRrFDNbSlKvDRUH7sZupmBoxLUs0zsGh05Pu2G+ul0Fd2CU8 hpKJnd1Quf5DLPdR52UXTgnHl9WfWF0JsViSpJNr91pRWMRa3WQLQYJms/lPrkb2RPHp s5qA== X-Forwarded-Encrypted: i=1; AJvYcCXOVbXaBCRRX2JddySNQ11PS9Ie4qUUUUlXo1rr8Z6O0IN83Phed7nMM3D7nba6+g3zGQiq3z2XiW5nURA=@vger.kernel.org X-Gm-Message-State: AOJu0YxU5OnDEOGohlt0I8do4Sg0MYqveZRGL+irqgCXmpMqDU7u6pBN ax/iQs4xrRv0nwnA59ZwLEt61G50ch+DyqkLdPu57FxEwSHO6/59NRqW X-Gm-Gg: ASbGncshfMeL6UouHvnWnJx30BoiWZJBwHyod0qD+rXmpZfeyELY36ggx3k8Ln7rtph UEPw/0pXMEqs6SDfUVWWfpS/3ijBOMdgJ9BVH4zR6lIiJgcF7qqjqMSpXQFs3MXuwA7AuoK7Nnj OAGt4ruyYvsF1Q7QpMPRbC1DfHjwvhXfyEOuUZwl0C6mR/DoKQkva72T9O1y9FpQ01eZbzwOU7m Bj0J8G1fHFU6dEmAo+Nv5gkXwgLCG0pGqCADCeHV3zB++7bkreHhI7DdoR4TCRCFlHDGEfAPAjz JSAP9E1YdI2cBtUaMrZ42Hd3DEKIoZDXi8cpwliTcH92lhOzDs84nC7VuQW2ekcuJA63UAZaYIS dJZ0GDeTuCaGJGUGPm4V4AxdvwCL9fJiSp1IQ1lT7tIu17OKURmH8q4bjuk8Z7CdArYdBkpXs X-Google-Smtp-Source: AGHT+IEBp3n9waN+QLfSeGkJ6Cl6QVfabWEq+lZhDZ0/Oyrgosuby6+FX48Fveezpj1GFz6tmkC1Ag== X-Received: by 2002:a05:6000:3111:b0:3d7:d444:da19 with SMTP id ffacd0b85a97d-3e765a55a96mr3809148f8f.55.1757706852893; Fri, 12 Sep 2025 12:54:12 -0700 (PDT) Received: from yanesskka.. (node-188-187-35-212.domolink.tula.net. [212.35.187.188]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45e017bfd14sm74650375e9.21.2025.09.12.12.54.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 12 Sep 2025 12:54:12 -0700 (PDT) From: Yana Bashlykova To: "David S. Miller" Cc: Yana Bashlykova , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Shuah Khan , netdev@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, lvc-project@linuxtesting.org Subject: [PATCH 6.1 14/15] selftests: net: genetlink: add Netlink and Generic Netlink test suite Date: Fri, 12 Sep 2025 22:53:37 +0300 Message-Id: <20250912195339.20635-15-yana2bsh@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250912195339.20635-1-yana2bsh@gmail.com> References: <20250912195339.20635-1-yana2bsh@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable This commit introduces a comprehensive test suite for Netlink and Generic N= etlink functionality. The tests cover: - Basic socket operations and protocol validation - Controller family resolution and policy checks - Multicast group communication - Error handling and edge cases - Socket option testing (EXT_ACK, NO_ENOBUFS, etc.) - Stress testing and race conditions The test suite uses kselftest harness and includes both positive and negati= ve test cases to validate kernel behavior under various conditions. Signed-off-by: Yana Bashlykova --- tools/testing/selftests/net/genetlink.c | 3881 +++++++++++++++++++++++ 1 file changed, 3881 insertions(+) diff --git a/tools/testing/selftests/net/genetlink.c b/tools/testing/selfte= sts/net/genetlink.c index 361840aae918..a166f2c474b4 100644 --- a/tools/testing/selftests/net/genetlink.c +++ b/tools/testing/selftests/net/genetlink.c @@ -81,10 +81,34 @@ =20 #define LARGE_GENL_FAMILY_NAME "LARGE_GENL" =20 +#define SOME_RANDOM_CMD 99 + /** * Callback data structures - used to pass data between test cases and mes= sage handlers */ =20 +struct callback_data { + int int_value; + char *message; + char *some_info; +}; + +struct callback_data_parallel_dump { + char *name; + char *desc; +}; + +struct callback_data_parallel_dump data_check[] =3D { + { "TEST_GENL", "one" }, + { "PARALLEL_GENL", "two" }, + { "THIRD_GENL", "three" }, + { "LARGE_GENL", "four" }, +}; + +#define DATA_SIZE (sizeof(data_check) / sizeof(data_check[0])) + +static int elems; + struct callback_data_ctrl { int family_id; char *family_name; @@ -93,6 +117,221 @@ struct callback_data_ctrl { int family_index; }; =20 +struct callback_data_third { + char *message; + int flag; +}; + +int validate_cb_parallel(struct nl_msg *msg, void *arg) +{ + struct genlmsghdr *gnlh =3D nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *attrs[PARALLEL_GENL_ATTR_MAX + 1]; + int ret =3D 0; + char *message =3D NULL; + + ret =3D genlmsg_parse(nlmsg_hdr(msg), 0, attrs, PARALLEL_GENL_ATTR_MAX, + NULL); + + if (ret < 0) { + printf("Failed to parse attributes: %d\n", ret); + return NL_STOP; + } + + struct callback_data *data =3D (struct callback_data *)arg; + + switch (gnlh->cmd) { + case PARALLEL_GENL_CMD_SEND: + if (attrs[PARALLEL_GENL_ATTR_DATA]) { + message =3D + nla_get_string(attrs[PARALLEL_GENL_ATTR_DATA]); + data->message =3D strdup(message); + if (data->message =3D=3D NULL) { + perror("strdup failed"); + return NL_SKIP; + } + } else { + printf("Attribute not found.\n"); + return NL_SKIP; + } + return NL_OK; + case PARALLEL_GENL_CMD_GET_VALUE: + if (attrs[PARALLEL_GENL_ATTR_DATA]) { + message =3D + nla_get_string(attrs[PARALLEL_GENL_ATTR_DATA]); + data->message =3D strdup(message); + if (data->message =3D=3D NULL) { + perror("strdup failed"); + return NL_SKIP; + } + } + return NL_OK; + } + return NL_OK; +} + +int validate_cb_parallel_dump(struct nl_msg *msg, void *arg) +{ + struct genlmsghdr *gnlh =3D nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *attrs[PARALLEL_GENL_ATTR_MAX + 1]; + int ret =3D 0; + char *name; + char *desc; + + ret =3D genlmsg_parse(nlmsg_hdr(msg), 0, attrs, PARALLEL_GENL_ATTR_MAX, + NULL); + + if (ret < 0) { + printf("Failed to parse attributes: %d\n", ret); + return NL_STOP; + } + + struct callback_data_parallel_dump *data =3D + (struct callback_data_parallel_dump *)arg; + switch (gnlh->cmd) { + case PARALLEL_GENL_CMD_DUMP_INFO: + if (attrs[PARALLEL_GENL_ATTR_NAME]) { + name =3D nla_get_string(attrs[PARALLEL_GENL_ATTR_NAME]); + data->name =3D strdup(name); + if (data->name =3D=3D NULL) { + perror("strdup failed"); + free(data); + return NL_SKIP; + } + + if (strcmp(data->name, data_check[elems].name)) + printf("[FAILED]\n"); + } + if (attrs[PARALLEL_GENL_ATTR_DESC]) { + desc =3D nla_get_string(attrs[PARALLEL_GENL_ATTR_DESC]); + data->desc =3D strdup(desc); + if (data->desc =3D=3D NULL) { + perror("strdup failed"); + return NL_SKIP; + } + if (strcmp(data->desc, data_check[elems].desc)) + printf("[FAILED]\n"); + } + elems++; + return NL_OK; + } + return NL_OK; +} + +int validate_cb_third(struct nl_msg *msg, void *arg) +{ + struct genlmsghdr *gnlh =3D nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *attrs[PARALLEL_GENL_ATTR_MAX + 1]; + int ret =3D 0; + int flag =3D -1; + char *message =3D NULL; + + ret =3D genlmsg_parse(nlmsg_hdr(msg), 0, attrs, PARALLEL_GENL_ATTR_MAX, + NULL); + + if (ret < 0) { + printf("Failed to parse attributes: %d\n", ret); + return NL_STOP; + } + + struct callback_data_third *data =3D (struct callback_data_third *)arg; + + switch (gnlh->cmd) { + case THIRD_GENL_CMD_ECHO: + if (attrs[THIRD_GENL_ATTR_DATA]) { + message =3D nla_get_string(attrs[THIRD_GENL_ATTR_DATA]); + data->message =3D strdup(message); + if (data->message =3D=3D NULL) { + perror("strdup failed"); + return NL_SKIP; + } + } + if (attrs[THIRD_GENL_ATTR_FLAG]) { + flag =3D nla_get_flag(attrs[THIRD_GENL_ATTR_FLAG]); + data->flag =3D flag; + } + return NL_OK; + } + return NL_OK; +} + +int validate_cb(struct nl_msg *msg, void *arg) +{ + struct genlmsghdr *gnlh =3D nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *attrs[MY_GENL_ATTR_MAX + 1]; + int ret =3D 0; + int int_value =3D 30; + + ret =3D genlmsg_parse(nlmsg_hdr(msg), 0, attrs, MY_GENL_ATTR_MAX, NULL); + + if (ret < 0) { + printf("Failed to parse attributes: %d\n", ret); + return NL_STOP; + } + + struct callback_data *data =3D (struct callback_data *)arg; + + switch (gnlh->cmd) { + case MY_GENL_CMD_GET_VALUE: + if (attrs[MY_GENL_ATTR_VALUE]) { + if (nla_len(attrs[MY_GENL_ATTR_VALUE]) >=3D sizeof(int)) { + int_value =3D + nla_get_u32(attrs[MY_GENL_ATTR_VALUE]); + data->int_value =3D int_value; + } else { + fprintf(stderr, + "MY_GENL_ATTR_VALUE has incorrect size"); + return NL_STOP; + } + } + return NL_OK; + + case MY_GENL_CMD_SET_VALUE: + if (attrs[MY_GENL_ATTR_VALUE]) { + if (nla_len(attrs[MY_GENL_ATTR_VALUE]) >=3D sizeof(int)) { + int_value =3D + nla_get_u32(attrs[MY_GENL_ATTR_VALUE]); + data->int_value =3D int_value; + } else { + fprintf(stderr, + "MY_GENL_ATTR_VALUE has incorrect size"); + return NL_STOP; + } + } + return NL_OK; + + case MY_GENL_CMD_ECHO: + if (attrs[MY_GENL_ATTR_DATA]) { + char *message =3D + nla_get_string(attrs[MY_GENL_ATTR_DATA]); + data->message =3D strdup(message); + if (data->message =3D=3D NULL) { + perror("strdup failed"); + return NL_SKIP; + } + } else { + printf("Attribute not found.\n"); + return NL_SKIP; + } + return NL_OK; + + case MY_GENL_SMALL_CMD_GET: + if (attrs[MY_GENL_ATTR_DATA]) { + char *message =3D + nla_get_string(attrs[MY_GENL_ATTR_DATA]); + data->message =3D strdup(message); + if (data->message =3D=3D NULL) { + perror("strdup failed"); + return NL_SKIP; + } + } + return NL_OK; + default: + printf("Unknown command: %u\n", gnlh->cmd); + break; + } + return NL_OK; +} + static int elem; =20 static int id_elem; @@ -479,6 +718,91 @@ int validate_cb_ctrl(struct nl_msg *msg, void *arg) return NL_OK; } =20 +#define BUFFER_SIZE 256 + +int read_string_from_sysfs(const char *path, char *buffer, size_t buffer_s= ize) +{ + int fd =3D open(path, O_RDONLY); + + if (fd < 0) { + fprintf(stderr, "Error opening %s for reading sysfs: %s\n", + path, strerror(errno)); + return -errno; + } + + ssize_t len =3D read(fd, buffer, buffer_size - 1); + + if (len < 0) { + fprintf(stderr, "Error reading to %s: %s\n", path, + strerror(errno)); + close(fd); + return -errno; + } + + buffer[len] =3D '\0'; + close(fd); + return 0; +} + +int read_int_from_sysfs(const char *path, int *value) +{ + char buffer[BUFFER_SIZE]; + int ret; + + ret =3D read_string_from_sysfs(path, buffer, sizeof(buffer)); + + if (ret !=3D 0) + return ret; + + char *endptr; + long val =3D strtol(buffer, &endptr, 10); + + if (endptr =3D=3D buffer) { + fprintf(stderr, "Conversion error: %s\n", strerror(errno)); + return -errno; + } + + *value =3D (int)val; + return 0; +} + +int write_string_to_sysfs(const char *path, const char *value) +{ + int fd =3D open(path, O_WRONLY); + + if (fd < 0) { + fprintf(stderr, "Error opening %s for writing sysfs: %s\n", + path, strerror(errno)); + return -errno; + } + + ssize_t len =3D write(fd, value, strlen(value)); + + if (len < 0) { + fprintf(stderr, "Error writing to %s: %s\n", path, + strerror(errno)); + close(fd); + return -errno; + } + + close(fd); + return 0; +} + +int write_int_to_sysfs(const char *path, int value) +{ + char buffer[32]; + + int ret =3D snprintf(buffer, sizeof(buffer), "%d", value); + + if (ret < 0 || ret >=3D sizeof(buffer)) { + fprintf(stderr, "Conversion error: %s\n", strerror(errno)); + return -errno; + } + + return write_string_to_sysfs(path, buffer); +} + struct nl_sock *socket_alloc_and_conn(void) { struct nl_sock *socket; @@ -1179,6 +1503,3563 @@ TEST(resolve_large_family_id) EXPECT_TRUE(no_family_id > 0); } =20 +/** + * TEST(genl_small_cmd_get_value) - Tests small command in Generic Netlink= family + * + * Validates: + * 1. Family resolution and socket setup + * 2. Message formatting and transmission + * 3. Response validation + * 4. Sysfs integration check + * + * Test Flow: + * 1. Resolves target Generic Netlink family + * 2. Prepares request with MY_GENL_SMALL_CMD_GET + * 3. Validates response through callback + * 4. Compares result with sysfs reference data + * 5. Cleans up test artifacts + * + * Special Handling: + * - Requires root for sysfs operations + * - Uses custom validation callback + * - Resets sysfs state after test + */ + +TEST(genl_small_cmd_get_value) +{ + struct nl_sock *sock; + int family_id; + struct nl_msg *msg; + struct genlmsghdr *user_hdr; + struct nl_cb *cb; + int err =3D 0; + struct callback_data cb_data; + + cb_data.int_value =3D -30; + cb_data.message =3D NULL; + + printf("Running Test: getting value using small cmd...\n"); + + // Only root can write to sysfs (needs for testing) + if (geteuid()) { + SKIP(return, "test requires root"); + return; + } + + sock =3D socket_alloc_and_conn(); + EXPECT_NE(NULL, sock); + if (!sock) { + fprintf(stderr, "socket is NULL\n"); + return; + } + + family_id =3D genl_ctrl_resolve(sock, MY_GENL_FAMILY_NAME); + EXPECT_GT(family_id, 0); + if (family_id < 0) { + fprintf(stderr, "Failed to resolve family id: %d\n", family_id); + nl_socket_free(sock); + err =3D family_id; + return; + } + + msg =3D nlmsg_alloc(); + EXPECT_NE(NULL, msg); + if (!msg) { + fprintf(stderr, "Failed to allocate message\n"); + nl_socket_free(sock); + return; + } + + user_hdr =3D genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family_id, 0, + NLM_F_REQUEST, MY_GENL_SMALL_CMD_GET, 0); + EXPECT_NE(NULL, user_hdr); + if (!user_hdr) { + fprintf(stderr, "Failed to genlmsg_put\n"); + nlmsg_free(msg); + nl_socket_free(sock); + return; + } + + cb =3D nl_cb_alloc(NL_CB_DEFAULT); + EXPECT_NE(NULL, cb); + if (!cb) { + fprintf(stderr, "Failed to allocate callback\n"); + nlmsg_free(msg); + nl_socket_free(sock); + return; + } + + char *str =3D malloc(BUFFER_SIZE); + + err =3D nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, validate_cb, &cb_data); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Error setting callback: %s\n", + nl_geterror(err)); + goto error; + } + + err =3D nl_send_auto(sock, msg); + EXPECT_GE(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to send message: %s\n", + nl_geterror(err)); + goto error; + } + + err =3D nl_recvmsgs(sock, cb); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to receive message: %s\n", + nl_geterror(err)); + goto error; + } + + err =3D read_string_from_sysfs(PATH_GENL_TEST_MES, str, BUFFER_SIZE); + EXPECT_EQ(err, 0); + if (err) { + fprintf(stderr, "Failed to read from sysfs: %s\n", + strerror(err)); + goto error; + } + + EXPECT_STREQ(str, cb_data.message); + + err =3D write_string_to_sysfs(PATH_GENL_TEST_MES, "default"); + EXPECT_EQ(err, 0); + if (err) { + fprintf(stderr, "Failed to write to sysfs: %s\n", + strerror(err)); + goto error; + } + +error: + free(str); + nlmsg_free(msg); + nl_cb_put(cb); + nl_socket_free(sock); +} + +/** + * TEST(genl_parallel) - Tests message exchange with PARALLEL_GENL Generic= Netlink family + * + * Validates end-to-end communication with PARALLEL_GENL family: + * 1. Establishes connection to PARALLEL_GENL family + * 2. Sends PARALLEL_GENL_CMD_SEND command + * 3. Checks results with sysfs reference data + * + * Test Flow: + * 1. Resolves PARALLEL_GENL family ID + * 2. Prepares and sends command message + * 3. Receives and validates response + * 4. Compares with sysfs reference data + * 5. Resets test environment + * + * Requirements: + * - Root privileges (for sysfs access) + * - Loaded parallel_genl kernel module + * - Properly configured sysfs interface + * + * Error Handling: + * - Validates all intermediate steps + * - Cleans up resources on failure + * - Resets sysfs state after test + */ + +TEST(genl_parallel) +{ + struct nl_sock *sock; + int family_id; + struct nl_msg *msg; + struct genlmsghdr *user_hdr; + struct nl_cb *cb; + int err =3D 0; + struct callback_data cb_data; + + cb_data.int_value =3D -30; + cb_data.message =3D NULL; + + printf("Running Test: sending message to parallel_genl...\n"); + + // Only root can write to sysfs (needs for testing) + if (geteuid()) { + SKIP(return, "test requires root"); + return; + } + + sock =3D socket_alloc_and_conn(); + EXPECT_NE(NULL, sock); + if (!sock) { + fprintf(stderr, "socket is NULL\n"); + return; + } + + family_id =3D genl_ctrl_resolve(sock, PARALLEL_GENL_FAMILY_NAME); + EXPECT_GT(family_id, 0); + if (family_id < 0) { + fprintf(stderr, "Failed to resolve family id: %d\n", family_id); + nl_socket_free(sock); + err =3D family_id; + return; + } + + msg =3D nlmsg_alloc(); + EXPECT_NE(NULL, msg); + if (!msg) { + fprintf(stderr, "Failed to allocate message\n"); + nl_socket_free(sock); + return; + } + + user_hdr =3D genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family_id, 0, + NLM_F_REQUEST, PARALLEL_GENL_CMD_SEND, 0); + EXPECT_NE(NULL, user_hdr); + if (!user_hdr) { + fprintf(stderr, "Failed to genlmsg_put\n"); + nlmsg_free(msg); + nl_socket_free(sock); + return; + } + + cb =3D nl_cb_alloc(NL_CB_DEFAULT); + EXPECT_NE(NULL, cb); + if (!cb) { + fprintf(stderr, "Failed to allocate callback\n"); + nlmsg_free(msg); + nl_socket_free(sock); + return; + } + + char *str =3D malloc(BUFFER_SIZE); + + err =3D nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, validate_cb_parallel, + &cb_data); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Error setting callback: %s\n", + nl_geterror(err)); + goto error; + } + + err =3D nl_send_auto(sock, msg); + EXPECT_GE(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to send message: %s\n", + nl_geterror(err)); + goto error; + } + + err =3D nl_recvmsgs(sock, cb); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to receive message: %s\n", + nl_geterror(err)); + goto error; + } + + err =3D read_string_from_sysfs(PATH_PARALLEL_GENL_MES, str, BUFFER_SIZE); + EXPECT_EQ(err, 0); + if (err) { + fprintf(stderr, "Failed to read from sysfs: %s\n", + strerror(err)); + goto error; + } + + EXPECT_STREQ(str, cb_data.message); + + err =3D write_string_to_sysfs(PATH_PARALLEL_GENL_MES, "default"); + EXPECT_EQ(err, 0); + if (err) { + fprintf(stderr, "Failed to write to sysfs: %s\n", + strerror(err)); + goto error; + } + +error: + free(str); + nlmsg_free(msg); + nl_cb_put(cb); + nl_socket_free(sock); +} + +/** + * TEST(genl_parallel_dump) - Tests parallel dump operation in Generic Net= link + * + * Validates the parallel dump functionality of the PARALLEL_GENL family b= y: + * 1. Sending a dump request (NLM_F_DUMP flag) with PARALLEL_GENL_CMD_DUMP= _INFO command + * 2. Processing multiple response messages through callback validation + * 3. Verifying correct handling of parallel data streams + * + * Key Features Tested: + * - Multi-message dump handling capability + * - Parallel data stream processing + * - Callback validation of dump contents + * - Resource management during extended operations + * + * Test Flow: + * 1. Resolve PARALLEL_GENL family ID + * 2. Prepare dump request message: + * - Sets NLM_F_DUMP flag + * - Uses PARALLEL_GENL_CMD_DUMP_INFO command + * 3. Configure callback (validate_cb_parallel_dump) for message processing + * 4. Execute send/receive operations + * 5. Validate results through callback + * + * Error Handling: + * - Verifies all intermediate steps + * - Proper resource cleanup on failure + * - Callback determines final test status + */ + +TEST(genl_parallel_dump) +{ + struct nl_sock *sock; + int family_id; + struct nl_msg *msg; + struct genlmsghdr *user_hdr; + struct nl_cb *cb; + int err =3D 0; + + struct callback_data_parallel_dump cb_data; + + printf("Running Test: doing parallel dump with genl_parallel_dump...\n"); + sock =3D socket_alloc_and_conn(); + EXPECT_NE(NULL, sock); + if (!sock) { + fprintf(stderr, "socket is NULL\n"); + return; + } + + family_id =3D genl_ctrl_resolve(sock, PARALLEL_GENL_FAMILY_NAME); + EXPECT_GT(family_id, 0); + if (family_id < 0) { + fprintf(stderr, "Failed to resolve family id: %d\n", family_id); + nl_socket_free(sock); + err =3D family_id; + return; + } + + msg =3D nlmsg_alloc(); + EXPECT_NE(NULL, msg); + if (!msg) { + fprintf(stderr, "Failed to allocate message\n"); + nl_socket_free(sock); + return; + } + + user_hdr =3D genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family_id, 0, + NLM_F_DUMP, PARALLEL_GENL_CMD_DUMP_INFO, 0); + EXPECT_NE(NULL, user_hdr); + if (!user_hdr) { + fprintf(stderr, "Failed to genlmsg_put\n"); + nlmsg_free(msg); + nl_socket_free(sock); + return; + } + + cb =3D nl_cb_alloc(NL_CB_DEFAULT); + EXPECT_NE(NULL, cb); + if (!cb) { + fprintf(stderr, "Failed to allocate callback\n"); + nlmsg_free(msg); + nl_socket_free(sock); + return; + } + + char *str =3D malloc(BUFFER_SIZE); + + err =3D nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, + validate_cb_parallel_dump, &cb_data); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Error setting callback: %s\n", + nl_geterror(err)); + goto error; + } + + err =3D nl_send_auto(sock, msg); + EXPECT_GE(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to send message: %s\n", + nl_geterror(err)); + goto error; + } + + err =3D nl_recvmsgs(sock, cb); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to receive message: %s\n", + nl_geterror(err)); + goto error; + } + + // callback function determines whether the test is successful + + EXPECT_EQ(elems, DATA_SIZE); + elems =3D 0; + +error: + free(str); + nlmsg_free(msg); + nl_cb_put(cb); + nl_socket_free(sock); +} + +static struct nl_msg *genl_generate_messages(int family_id, int nonblock) +{ + struct nl_msg *msg; + struct genlmsghdr *user_hdr; + char *data; + int err; + + msg =3D nlmsg_alloc(); + if (!msg) { + fprintf(stderr, "Failed to allocate message\n"); + return NULL; + } + + user_hdr =3D genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family_id, 0, + NLM_F_REQUEST, PARALLEL_GENL_CMD_SEND, 0); + if (!user_hdr) { + fprintf(stderr, "Failed to genlmsg_put\n"); + nlmsg_free(msg); + return NULL; + } + + if (nonblock) { + if (nla_put_flag(msg, PARALLEL_GENL_ATTR_FLAG_NONBLOCK) < 0) { + fprintf(stderr, + "Failed to add PARALLEL_GENL_ATTR_FLAG_NONBLOCK flag attribute: %s\n", + strerror(errno)); + nlmsg_free(msg); + return NULL; + } + } else { + if (nla_put_flag(msg, PARALLEL_GENL_ATTR_FLAG_BLOCK) < 0) { + fprintf(stderr, + "Failed to add PARALLEL_GENL_ATTR_FLAG_BLOCK flag attribute: %s\n", + strerror(errno)); + nlmsg_free(msg); + return NULL; + } + } + + int data_size =3D 4068; + + data =3D malloc(data_size); + if (!data) { + fprintf(stderr, "Failed to allocate data buffer\n"); + nlmsg_free(msg); + return NULL; + } + memset(data, 1, data_size); + + err =3D nla_put(msg, PARALLEL_GENL_ATTR_BINARY, data_size, data); + if (err < 0) { + fprintf(stderr, + "Failed to add PARALLEL_GENL_ATTR_BINARY attribute: %s\n", + strerror(errno)); + free(data); + nlmsg_free(msg); + return NULL; + } + + return msg; +} + +/** + * TEST(incorrect_genl_parallel_with_flag_nonblock_sock) - Tests buffer ov= erflow in + * non-blocking Generic Netlink socket + * + * Validates kernel behavior under buffer overflow conditions by: + * 1. Creating a non-blocking socket with reduced buffer size (5000 bytes) + * 2. Rapidly sending multiple messages (20x) without waiting for responses + * 3. Verifying proper error handling when buffer capacity is exceeded + * + * Expected Behavior: + * - First receive attempt should fail with NLE_NOMEM (ENOBUFS) + * - Subsequent receives should return NLE_AGAIN (EAGAIN) + * - Number of successfully received messages should be less than sent (ke= rnel drops packets) + * + * Test Methodology: + * 1. Configure non-blocking socket with small buffer + * 2. Flood the socket with back-to-back messages + * 3. Verify error sequence: + * a) Initial ENOBUFS when buffer is full + * b) Subsequent EAGAIN for empty buffer + * 4. Confirm packet loss (recv_count < send_count) + * + * Technical Notes: + * - Requires root for socket configuration + * - Uses custom message generator (genl_generate_messages) + * - Tests kernel's congestion control mechanisms + * - Validates Netlink's non-blocking error handling + */ + +TEST(incorrect_genl_parallel_with_flag_nonblock_sock) +{ + struct nl_sock *sock; + int family_id; + struct nl_msg *msg; + struct nl_cb *cb; + int err =3D 0; + int send_c; + int recv_c; + struct callback_data cb_data; + + cb_data.int_value =3D -30; + cb_data.message =3D NULL; + + printf("Running Test: trying to overflow buffer of nonblock socket...\n"); + + // Only root can write to sysfs (needs for testing) + if (geteuid()) { + SKIP(return, "test requires root"); + return; + } + + sock =3D socket_alloc_and_conn(); + EXPECT_NE(NULL, sock); + if (!sock) { + fprintf(stderr, "socket is NULL\n"); + return; + } + + family_id =3D genl_ctrl_resolve(sock, PARALLEL_GENL_FAMILY_NAME); + EXPECT_GT(family_id, 0); + if (family_id < 0) { + fprintf(stderr, "Failed to resolve family id: %d\n", family_id); + nl_socket_free(sock); + err =3D family_id; + return; + } + + err =3D nl_socket_set_buffer_size(sock, 5000, 5000); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to change socket buffer size: %s\n", + nl_geterror(err)); + nl_socket_free(sock); + return; + } + + err =3D nl_socket_set_nonblocking(sock); + EXPECT_EQ(err, 0); + + cb =3D nl_cb_alloc(NL_CB_DEFAULT); + EXPECT_NE(NULL, cb); + if (!cb) { + fprintf(stderr, "Failed to allocate callback\n"); + nl_socket_free(sock); + return; + } + + err =3D nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, validate_cb_parallel, + &cb_data); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Error setting callback: %s\n", + nl_geterror(err)); + nl_socket_free(sock); + return; + } + + send_c =3D 20; + recv_c =3D 0; + for (int i =3D 0; i < send_c; i++) { + msg =3D genl_generate_messages(family_id, 1); + EXPECT_NE(NULL, msg); + if (!msg) { + fprintf(stderr, "Failed to create message\n"); + goto error; + } + err =3D nl_send_auto(sock, msg); + EXPECT_GE(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to send message: %s\n", + nl_geterror(err)); + goto error; + } + nlmsg_free(msg); + } + + // the buffer is full + err =3D nl_recvmsgs(sock, cb); + EXPECT_EQ(err, -NLE_NOMEM); + EXPECT_EQ(errno, ENOBUFS); + + for (int i =3D 1; i < send_c; i++) { + err =3D nl_recvmsgs(sock, cb); + if (err < 0) { + EXPECT_EQ(err, -NLE_AGAIN); + EXPECT_EQ(errno, EAGAIN); + } + if (err =3D=3D 0) + recv_c++; + } + EXPECT_LT(recv_c, send_c); + +error: + nl_cb_put(cb); + nl_socket_free(sock); +} + +/** + * TEST(incorrect_genl_parallel_with_flag_block_sock) - Tests buffer overf= low behavior in + * blocking Generic Netlink socket + * + * Validates kernel packet handling under buffer overflow conditions with = blocking sockets: + * 1. Configures socket with small buffer (1000 bytes) and 1-second timeout + * 2. Sends burst of messages (8x) to trigger overflow + * 3. Verifies correct error sequence and packet loss + * + * Expected Behavior: + * - Initial receive returns NLE_NOMEM (ENOBUFS) when buffer is full + * - Subsequent receives get partial messages (recv_count < send_count) + * - Final receive returns NLE_AGAIN (EAGAIN) when queue is empty + * + * Test Methodology: + * 1. Reduce socket buffer size to force quick overflow + * 2. Set conservative timeout (1s) for blocked receives + * 3. Send message burst without waiting for responses + * 4. Verify: + * a) Initial ENOBUFS error + * b) Partial message delivery + * c) Terminal EAGAIN condition + * + * Technical Notes: + * - Demonstrates kernel's congestion control with blocking sockets + * - Shows Netlink's reliability limits under overload + * - Uses SO_RCVTIMEO to prevent indefinite blocking + * - Requires root for socket configuration + */ + +TEST(incorrect_genl_parallel_with_flag_block_sock) +{ + struct nl_sock *sock; + int family_id; + struct nl_msg *msg; + struct nl_cb *cb; + int err =3D 0; + struct callback_data cb_data; + + cb_data.int_value =3D -30; + cb_data.message =3D NULL; + + struct timeval tv =3D { 1, 0 }; + + int send_c; + int recv_c; + + printf("Running Test: trying to overflow buffer of block socket...\n"); + + // Only root can write to sysfs (needs for testing) + if (geteuid()) { + SKIP(return, "test requires root"); + return; + } + + sock =3D socket_alloc_and_conn(); + EXPECT_NE(NULL, sock); + if (!sock) { + fprintf(stderr, "socket is NULL\n"); + return; + } + + family_id =3D genl_ctrl_resolve(sock, PARALLEL_GENL_FAMILY_NAME); + EXPECT_GT(family_id, 0); + if (family_id < 0) { + fprintf(stderr, "Failed to resolve family id: %d\n", family_id); + nl_socket_free(sock); + err =3D family_id; + return; + } + + err =3D nl_socket_set_buffer_size(sock, 1000, 1000); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to change socket buffer size: %s\n", + nl_geterror(err)); + nl_socket_free(sock); + return; + } + + err =3D setsockopt(nl_socket_get_fd(sock), SOL_SOCKET, SO_RCVTIMEO, &tv, + sizeof(tv)); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to set timeout for block socket\n"); + nl_socket_free(sock); + return; + } + + cb =3D nl_cb_alloc(NL_CB_DEFAULT); + EXPECT_NE(NULL, cb); + if (!cb) { + fprintf(stderr, "Failed to allocate callback\n"); + nl_socket_free(sock); + return; + } + + err =3D nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, validate_cb_parallel, + &cb_data); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Error setting callback: %s\n", + nl_geterror(err)); + nl_socket_free(sock); + return; + } + + send_c =3D 8; + for (int i =3D 0; i < send_c; i++) { + msg =3D genl_generate_messages(family_id, 0); + EXPECT_NE(NULL, msg); + if (!msg) { + fprintf(stderr, "Failed to create message\n"); + goto error; + } + err =3D nl_send_auto(sock, msg); + EXPECT_GE(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to send message: %s\n", + nl_geterror(err)); + goto error; + } + nlmsg_free(msg); + } + + recv_c =3D 0; + + // the buffer is full + err =3D nl_recvmsgs(sock, cb); + EXPECT_EQ(err, -NLE_NOMEM); + EXPECT_EQ(errno, ENOBUFS); + + for (int i =3D 1; i < send_c; i++) { + err =3D nl_recvmsgs(sock, cb); + if (err =3D=3D 0) + recv_c++; + + if (err < 0) { + EXPECT_EQ(err, -NLE_AGAIN); + EXPECT_EQ(errno, EAGAIN); + } + } + + EXPECT_TRUE(err =3D=3D -NLE_AGAIN && errno =3D=3D EAGAIN); + EXPECT_LT(recv_c, send_c); + +error: + nl_cb_put(cb); + nl_socket_free(sock); +} + +/** + * TEST(genl_test_get_value) - Tests basic communication with TEST_GENL fa= mily + * + * Validates end-to-end message exchange including: + * 1. Family and multicast group resolution + * 2. Message formatting and transmission + * 3. Response validation through callback + * 4. Sysfs integration verification + * + * Test Flow: + * 1. Establish connection to TEST_GENL + * 2. Resolve multicast group MY_MCGRP_GENL + * 3. Prepare GET_VALUE request message: + * - Sets MY_GENL_CMD_GET_VALUE command + * - Includes path attribute (PATH_GENL_TEST_NUM) + * 4. Send request and validate response + * 5. Compare result with sysfs reference data + * 6. Reset test environment + * + * Special Handling: + * - Requires root privileges (sysfs access) + * - Uses custom validation callback + * - Verifies both Netlink and sysfs interfaces + * - Automatic cleanup of test artifacts + */ + +TEST(genl_test_get_value) +{ + struct nl_sock *nl_sock; + int family_id; + int mcgrp_id; + struct nl_msg *msg; + struct nl_cb *cb; + int err =3D 0; + int int_value =3D -10; + struct genlmsghdr *user_hdr; + struct callback_data cb_data; + + cb_data.int_value =3D 20; + cb_data.message =3D NULL; + + printf("Running Test: getting value from sysfs via Netlink message...\n"); + + // Only root can write to sysfs (needs for testing) + if (geteuid()) { + SKIP(return, "test requires root"); + return; + } + + nl_sock =3D socket_alloc_and_conn(); + EXPECT_NE(NULL, nl_sock); + if (!nl_sock) + return; + + family_id =3D genl_ctrl_resolve(nl_sock, MY_GENL_FAMILY_NAME); + EXPECT_GT(family_id, 0); + if (family_id < 0) { + nl_socket_free(nl_sock); + err =3D family_id; + return; + } + + mcgrp_id =3D genl_ctrl_resolve_grp(nl_sock, MY_GENL_FAMILY_NAME, + MY_MCGRP_NAME); + EXPECT_GE(mcgrp_id, 0); + if (mcgrp_id < 0) { + nl_socket_free(nl_sock); + err =3D mcgrp_id; + return; + } + + err =3D nl_socket_add_membership(nl_sock, mcgrp_id); + EXPECT_EQ(err, 0); + if (err < 0) { + nl_socket_free(nl_sock); + return; + } + + msg =3D nlmsg_alloc(); + EXPECT_NE(NULL, msg); + if (!msg) { + nl_socket_free(nl_sock); + return; + } + + user_hdr =3D genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family_id, 0, + NLM_F_REQUEST, MY_GENL_CMD_GET_VALUE, 0); + EXPECT_NE(NULL, user_hdr); + if (!user_hdr) { + nlmsg_free(msg); + nl_socket_free(nl_sock); + return; + } + + if (nla_put_string(msg, MY_GENL_ATTR_PATH, PATH_GENL_TEST_NUM) < 0) { + nlmsg_free(msg); + nl_socket_free(nl_sock); + ASSERT_EQ(0, 1); + return; + } + + cb =3D nl_cb_alloc(NL_CB_DEFAULT); + EXPECT_NE(NULL, cb); + if (!cb) { + fprintf(stderr, "Failed to allocate callback\n"); + nlmsg_free(msg); + nl_socket_free(nl_sock); + return; + } + + err =3D nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, validate_cb, &cb_data); + EXPECT_EQ(err, 0); + if (err < 0) + goto error; + + err =3D nl_send_auto(nl_sock, msg); + EXPECT_GE(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to send message: %s\n", + nl_geterror(err)); + nlmsg_free(msg); + nl_cb_put(cb); + return; + } + + err =3D nl_recvmsgs(nl_sock, cb); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to receive message: %s\n", + nl_geterror(err)); + nlmsg_free(msg); + nl_cb_put(cb); + return; + } + + err =3D read_int_from_sysfs(PATH_GENL_TEST_NUM, &int_value); + EXPECT_EQ(err, 0); + if (err) { + fprintf(stderr, "Failed to read from sysfs: %s\n", + strerror(err)); + goto error; + } + + EXPECT_EQ(int_value, cb_data.int_value); + + err =3D write_int_to_sysfs(PATH_GENL_TEST_NUM, -20); + EXPECT_EQ(err, 0); + if (err) { + fprintf(stderr, "Failed to write to sysfs: %s\n", + strerror(err)); + goto error; + } + +error: + nlmsg_free(msg); + nl_cb_put(cb); + nl_socket_free(nl_sock); +} + +/** + * TEST(genl_test_echo) - Tests multicast echo functionality in TEST_GENL = family + * + * Validates the echo request/reply mechanism through multicast groups by: + * 1. Configuring socket with CAP_ACK capability + * 2. Sending echo request (NLM_F_ECHO flag) with MY_GENL_CMD_ECHO command + * 3. Receiving and validating multicast response + * 4. Verifying message content against sysfs reference + * + * Protocol Details: + * - Uses NETLINK_CAP_ACK for reliable multicast delivery + * - Leverages multicast group (MY_MCGRP_GENL) for replies + * - Validates both Netlink and sysfs message content + * + * Test Flow: + * 1. Establish Netlink connection + * 2. Enable CAP_ACK socket option + * 3. Resolve family and multicast group IDs + * 4. Join multicast group + * 5. Prepare and send echo request + * 6. Receive and validate multicast reply + * 7. Compare with sysfs reference data + * 8. Reset test environment + * + * Requirements: + * - Root privileges (for sysfs and socket configuration) + * - Properly configured multicast group in kernel + * - Validated echo handler in kernel module + */ + +TEST(genl_test_echo) +{ + struct nl_sock *sock; + int family_id; + int mcgrp_id; + struct nl_msg *msg; + struct genlmsghdr *user_hdr; + struct nl_cb *cb; + int err =3D 0; + int sock_fd; + int cap_ack =3D 1; + int optval; + socklen_t optlen =3D sizeof(optval); + struct callback_data cb_data; + + cb_data.int_value =3D -30; + cb_data.message =3D NULL; + + printf("Running Test: getting message that was sent to mcast groups...\n"= ); + + // Only root can write to sysfs (needs for testing) + if (geteuid()) { + SKIP(return, "test requires root"); + return; + } + + sock =3D socket_alloc_and_conn(); + EXPECT_NE(NULL, sock); + if (!sock) + return; + + sock_fd =3D nl_socket_get_fd(sock); + EXPECT_GE(sock_fd, 0); + if (sock_fd < 0) { + nl_socket_free(sock); + err =3D sock_fd; + return; + } + + err =3D setsockopt(sock_fd, SOL_NETLINK, NETLINK_CAP_ACK, &cap_ack, + sizeof(cap_ack)); + EXPECT_EQ(err, 0); + if (err < 0) { + nl_socket_free(sock); + return; + } + + err =3D getsockopt(sock_fd, SOL_NETLINK, NETLINK_CAP_ACK, &optval, + &optlen); + EXPECT_EQ(err, 0); + if (err < 0) { + nl_socket_free(sock); + return; + } + + family_id =3D genl_ctrl_resolve(sock, MY_GENL_FAMILY_NAME); + EXPECT_GT(family_id, 0); + if (family_id < 0) { + nl_socket_free(sock); + err =3D family_id; + return; + } + + mcgrp_id =3D + genl_ctrl_resolve_grp(sock, MY_GENL_FAMILY_NAME, MY_MCGRP_NAME); + EXPECT_GE(mcgrp_id, 0); + if (mcgrp_id < 0) { + err =3D mcgrp_id; + fprintf(stderr, "Failed to resolve multicast group: %s\n", + nl_geterror(err)); + nl_socket_free(sock); + return; + } + + err =3D nl_socket_add_membership(sock, mcgrp_id); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to add membership: %s\n", + nl_geterror(err)); + nl_socket_free(sock); + return; + } + + msg =3D nlmsg_alloc(); + EXPECT_NE(NULL, msg); + if (!msg) { + nl_socket_free(sock); + return; + } + + user_hdr =3D genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family_id, 0, + NLM_F_ECHO, MY_GENL_CMD_ECHO, 0); + EXPECT_NE(NULL, user_hdr); + if (!user_hdr) { + nlmsg_free(msg); + nl_socket_free(sock); + return; + } + + cb =3D nl_cb_alloc(NL_CB_DEFAULT); + EXPECT_NE(NULL, cb); + if (!cb) { + fprintf(stderr, "Failed to allocate callback\n"); + nlmsg_free(msg); + nl_socket_free(sock); + return; + } + + char *str =3D malloc(BUFFER_SIZE); + + err =3D nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, validate_cb, &cb_data); + EXPECT_EQ(err, 0); + if (err < 0) + goto error; + + err =3D nl_send_auto(sock, msg); + EXPECT_GE(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to send message: %s\n", + nl_geterror(err)); + free(str); + nlmsg_free(msg); + nl_cb_put(cb); + return; + } + + err =3D nl_recvmsgs(sock, cb); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to receive message: %s\n", + nl_geterror(err)); + free(str); + nlmsg_free(msg); + nl_cb_put(cb); + return; + } + + err =3D read_string_from_sysfs(PATH_GENL_TEST_MES, str, BUFFER_SIZE); + EXPECT_EQ(err, 0); + if (err) { + fprintf(stderr, "Failed to read from sysfs: %s\n", + strerror(err)); + goto error; + } + + EXPECT_STREQ(str, cb_data.message); + + err =3D write_string_to_sysfs(PATH_GENL_TEST_MES, "default"); + EXPECT_EQ(err, 0); + if (err) { + fprintf(stderr, "Failed to write to sysfs: %s\n", + strerror(err)); + goto error; + } + +error: + free(str); + nlmsg_free(msg); + nl_cb_put(cb); + nl_socket_free(sock); +} + +/** + * TEST(genl_test_set_value) - Tests value setting functionality in TEST_G= ENL family + * + * Validates the complete SET_VALUE operation workflow: + * 1. Configures socket with STRICT_CHK option for robust message validati= on + * 2. Sends properly formatted SET_VALUE command with: + * - Target path (PATH_GENL_TEST_NUM) + * - Integer value to set (1) + * 3. Verifies correct processing through: + * - Netlink response validation + * - Sysfs value verification + * + * Key Features Tested: + * - Strict checking option (NETLINK_GET_STRICT_CHK) + * - Multicast group communication + * - Attribute packing and unpacking + * - End-to-end sysfs integration + * + * Test Flow: + * 1. Initialize Netlink connection with strict checking + * 2. Resolve family and multicast group IDs + * 3. Prepare SET_VALUE request with path and value attributes + * 4. Send request and validate response + * 5. Verify sysfs value was updated correctly + * 6. Reset test environment + * + * Special Handling: + * - Requires root privileges (sysfs modification) + * - Uses custom validation callback + * - Automatic cleanup of test artifacts + */ + +TEST(genl_test_set_value) +{ + struct nl_sock *nl_sock; + int family_id; + int mcgrp_id; + struct nl_msg *msg; + struct nl_cb *cb; + int err =3D 0; + int int_value; + int sock_fd; + int up =3D 1; + struct genlmsghdr *user_hdr; + int optval; + + socklen_t optlen =3D sizeof(optval); + + struct callback_data cb_data; + + cb_data.int_value =3D 74; + cb_data.message =3D NULL; + + printf("Running Test: sending correct value for sysfs to genl_test...\n"); + + // Only root can write to sysfs (needs for testing) + if (geteuid()) { + SKIP(return, "test requires root"); + return; + } + + nl_sock =3D socket_alloc_and_conn(); + EXPECT_NE(NULL, nl_sock); + if (!nl_sock) + return; + + sock_fd =3D nl_socket_get_fd(nl_sock); + EXPECT_GE(sock_fd, 0); + if (sock_fd < 0) { + err =3D sock_fd; + nl_socket_free(nl_sock); + return; + } + + err =3D setsockopt(sock_fd, SOL_NETLINK, NETLINK_GET_STRICT_CHK, &up, + sizeof(up)); + EXPECT_EQ(err, 0); + if (err < 0) { + nl_socket_free(nl_sock); + return; + } + + err =3D getsockopt(sock_fd, SOL_NETLINK, NETLINK_GET_STRICT_CHK, &optval, + &optlen); + EXPECT_EQ(err, 0); + if (err < 0) { + nl_socket_free(nl_sock); + return; + } + + family_id =3D genl_ctrl_resolve(nl_sock, MY_GENL_FAMILY_NAME); + EXPECT_GT(family_id, 0); + if (family_id < 0) { + nl_socket_free(nl_sock); + err =3D family_id; + return; + } + + mcgrp_id =3D genl_ctrl_resolve_grp(nl_sock, MY_GENL_FAMILY_NAME, + MY_MCGRP_NAME); + EXPECT_GE(mcgrp_id, 0); + if (mcgrp_id < 0) { + nl_socket_free(nl_sock); + err =3D mcgrp_id; + return; + } + + err =3D nl_socket_add_membership(nl_sock, mcgrp_id); + EXPECT_EQ(err, 0); + if (err < 0) { + nl_socket_free(nl_sock); + return; + } + + msg =3D nlmsg_alloc(); + EXPECT_NE(NULL, msg); + if (!msg) { + nl_socket_free(nl_sock); + return; + } + + user_hdr =3D genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family_id, 0, + NLM_F_REQUEST, MY_GENL_CMD_SET_VALUE, 0); + EXPECT_NE(NULL, user_hdr); + if (!user_hdr) { + nlmsg_free(msg); + nl_socket_free(nl_sock); + return; + } + + if (nla_put_string(msg, MY_GENL_ATTR_PATH, PATH_GENL_TEST_NUM) < 0) { + nlmsg_free(msg); + nl_socket_free(nl_sock); + ASSERT_EQ(0, 1); + return; + } + + if (nla_put_u32(msg, MY_GENL_ATTR_VALUE, 1) < 0) { + nlmsg_free(msg); + nl_socket_free(nl_sock); + ASSERT_EQ(0, 1); + return; + } + + cb =3D nl_cb_alloc(NL_CB_DEFAULT); + EXPECT_NE(NULL, cb); + if (!cb) { + fprintf(stderr, "Failed to allocate callback\n"); + nlmsg_free(msg); + nl_socket_free(nl_sock); + return; + } + + err =3D nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, validate_cb, &cb_data); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Error setting callback: %s\n", + nl_geterror(err)); + goto error; + } + + err =3D nl_send_auto(nl_sock, msg); + EXPECT_GE(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to send message: %s\n", + nl_geterror(err)); + nlmsg_free(msg); + nl_cb_put(cb); + return; + } + + err =3D nl_recvmsgs(nl_sock, cb); + EXPECT_TRUE(err =3D=3D 0 || err =3D=3D -NLE_PERM); + if (err < 0) { + if (geteuid() !=3D 0) + EXPECT_EQ(err, -NLE_PERM); + + EXPECT_EQ(err, 0); + fprintf(stderr, "Failed to receive message: %s\n", + nl_geterror(err)); + nlmsg_free(msg); + nl_cb_put(cb); + return; + } + + err =3D read_int_from_sysfs(PATH_GENL_TEST_NUM, &int_value); + EXPECT_EQ(err, 0); + if (err) { + fprintf(stderr, "Failed to read from sysfs: %s\n", + strerror(err)); + goto error; + } + + EXPECT_EQ(int_value, cb_data.int_value); + + err =3D write_int_to_sysfs(PATH_GENL_TEST_NUM, -20); + EXPECT_EQ(err, 0); + if (err) { + fprintf(stderr, "Failed to write to sysfs: %s\n", + strerror(err)); + goto error; + } + +error: + nlmsg_free(msg); + nl_cb_put(cb); + nl_socket_free(nl_sock); +} + +/** + * TEST(incorrect_genl_test_set_value) - Tests error handling in TEST_GENL= family + * + * Validates proper error reporting for invalid SET_VALUE operations by: + * 1. Enabling extended ACK (NETLINK_EXT_ACK) for detailed error messages + * 2. Configuring broadcast error reporting (NETLINK_BROADCAST_ERROR) + * 3. Sending intentionally incorrect value (34) to trigger error + * 4. Verifying kernel returns appropriate error codes: + * - NLE_INVAL for root (invalid value) + * - NLE_PERM for non-root (permission denied) + * + * Key Features Tested: + * - Extended ACK error reporting mechanism + * - Broadcast error propagation + * - Kernel validation of input values + * - Permission checking + * + * Test Flow: + * 1. Configure socket with EXT_ACK and BROADCAST_ERROR options + * 2. Resolve family and multicast group IDs + * 3. Prepare SET_VALUE request with invalid value (34) + * 4. Send request and verify error response + * 5. Validate error code matches expectations + * + * Special Handling: + * - Different expected errors for root/non-root + * - Uses kernel's extended ACK reporting + * - Tests both value validation and permission checks + */ + +TEST(incorrect_genl_test_set_value) +{ + struct nl_sock *nl_sock; + int family_id; + int mcgrp_id; + struct nl_msg *msg; + struct nl_cb *cb; + int err; + int sock_fd; + int ext_ack =3D 1; + int broadcast_error =3D 1; + struct genlmsghdr *user_hdr; + + int optval; + + socklen_t optlen =3D sizeof(optval); + + struct callback_data cb_data; + + cb_data.int_value =3D 74; + cb_data.message =3D NULL; + + printf("Running Test: sending incorrect value for sysfs to genl_test...\n= "); + + nl_sock =3D socket_alloc_and_conn(); + EXPECT_NE(NULL, nl_sock); + if (!nl_sock) { + printf("socket for my_genl is NULL\n"); + return; + } + + sock_fd =3D nl_socket_get_fd(nl_sock); + EXPECT_GE(sock_fd, 0); + if (sock_fd < 0) { + fprintf(stderr, "Failed to get socket file descriptor\n"); + err =3D sock_fd; + nl_socket_free(nl_sock); + return; + } + + err =3D setsockopt(sock_fd, SOL_NETLINK, NETLINK_EXT_ACK, &ext_ack, + sizeof(ext_ack)); + EXPECT_EQ(err, 0); + if (err < 0) { + nl_socket_free(nl_sock); + return; + } + + err =3D getsockopt(sock_fd, SOL_NETLINK, NETLINK_EXT_ACK, &optval, + &optlen); + EXPECT_EQ(err, 0); + if (err < 0) { + nl_socket_free(nl_sock); + return; + } + + EXPECT_EQ(optval, 1); + + err =3D setsockopt(sock_fd, SOL_NETLINK, NETLINK_BROADCAST_ERROR, + &broadcast_error, sizeof(broadcast_error)); + EXPECT_EQ(err, 0); + if (err < 0) { + nl_socket_free(nl_sock); + return; + } + + err =3D getsockopt(sock_fd, SOL_NETLINK, NETLINK_BROADCAST_ERROR, &optval, + &optlen); + EXPECT_EQ(err, 0); + if (err < 0) { + nl_socket_free(nl_sock); + return; + } + + EXPECT_EQ(optval, 1); + + family_id =3D genl_ctrl_resolve(nl_sock, MY_GENL_FAMILY_NAME); + EXPECT_GT(family_id, 0); + if (family_id < 0) { + err =3D family_id; + fprintf(stderr, "Failed to resolve family id: %s\n", + nl_geterror(err)); + nl_socket_free(nl_sock); + return; + } + + mcgrp_id =3D genl_ctrl_resolve_grp(nl_sock, MY_GENL_FAMILY_NAME, + MY_MCGRP_NAME); + EXPECT_GE(mcgrp_id, 0); + if (mcgrp_id < 0) { + err =3D mcgrp_id; + fprintf(stderr, "Failed to resolve multicast group: %s\n", + nl_geterror(err)); + nl_socket_free(nl_sock); + return; + } + + err =3D nl_socket_add_membership(nl_sock, mcgrp_id); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to add membership: %s\n", + nl_geterror(err)); + nl_socket_free(nl_sock); + return; + } + + msg =3D nlmsg_alloc(); + EXPECT_NE(NULL, msg); + if (!msg) { + fprintf(stderr, "Failed to allocate message\n"); + nl_socket_free(nl_sock); + return; + } + + user_hdr =3D genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family_id, 0, + NLM_F_REQUEST, MY_GENL_CMD_SET_VALUE, 0); + EXPECT_NE(NULL, user_hdr); + if (!user_hdr) { + fprintf(stderr, "Failed to genlmsg_put\n"); + nlmsg_free(msg); + nl_socket_free(nl_sock); + return; + } + + if (nla_put_string(msg, MY_GENL_ATTR_PATH, PATH_GENL_TEST_NUM) < 0) { + fprintf(stderr, + "Failed to add MY_GENL_ATTR_PATH attribute: %s\n", + strerror(errno)); + nlmsg_free(msg); + nl_socket_free(nl_sock); + ASSERT_EQ(0, 1); + return; + } + + if (nla_put_u32(msg, MY_GENL_ATTR_VALUE, 34) < 0) { + fprintf(stderr, + "Failed to add MY_GENL_ATTR_VALUE attribute: %s\n", + strerror(errno)); + nlmsg_free(msg); + nl_socket_free(nl_sock); + ASSERT_EQ(0, 1); + return; + } + + cb =3D nl_cb_alloc(NL_CB_DEFAULT); + EXPECT_NE(NULL, cb); + if (!cb) { + fprintf(stderr, "Failed to allocate callback\n"); + nlmsg_free(msg); + nl_socket_free(nl_sock); + return; + } + + err =3D nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, validate_cb, &cb_data); + EXPECT_EQ(err, 0); + if (err < 0) { + printf("Error setting callback\n"); + goto error; + } + + err =3D nl_send_auto(nl_sock, msg); + EXPECT_GE(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to send message: %s\n", + nl_geterror(err)); + goto error; + } + + // nl_recvmsgs gets error code from error ACK from kernel + err =3D nl_recvmsgs(nl_sock, cb); + EXPECT_TRUE(err =3D=3D -NLE_PERM || err =3D=3D -NLE_INVAL); + if (err < 0) { + if (geteuid() !=3D 0) + EXPECT_EQ(err, -NLE_PERM); + + if (geteuid() =3D=3D 0) + EXPECT_EQ(err, -NLE_INVAL); + } + EXPECT_LT(err, 0); + +error: + nlmsg_free(msg); + nl_cb_put(cb); + nl_socket_free(nl_sock); +} + +/** + * TEST(incorrect_family) - Tests handling of non-existent Generic Netlink= family + * + * Validates proper error reporting when attempting to resolve: + * 1. A deliberately non-existent Generic Netlink family + * 2. Expected error code (NLE_OBJ_NOTFOUND) + * + * Key Features Tested: + * - Controller behavior for unknown family names + * - Correct error code propagation + * - Graceful handling of resolution failures + * + * Test Methodology: + * 1. Creates standard Netlink socket + * 2. Attempts to resolve "SOME_RANDOM_NAME" family + * 3. Verifies: + * - Return value is negative (error) + * - Specific error code is NLE_OBJ_NOTFOUND + * - Clean resource deallocation + * + * Negative Testing: + * - Demonstrates proper error handling for invalid inputs + * - Verifies kernel API contract for unknown families + */ + +TEST(incorrect_family) +{ + struct nl_sock *sock; + int family_id; + + printf("Running Test: trying to find id of incorrect Netlink family...\n"= ); + + sock =3D socket_alloc_and_conn(); + EXPECT_NE(NULL, sock); + if (!sock) { + fprintf(stderr, "socket is NULL\n"); + return; + } + + family_id =3D genl_ctrl_resolve(sock, "SOME_RANDOM_NAME"); + EXPECT_EQ(family_id, -NLE_OBJ_NOTFOUND); + + nl_socket_free(sock); +} + +/** + * TEST(incorrect_family_id) - Tests error handling for invalid family ID + * + * Validates proper error reporting when sending messages to: + * 1. A deliberately incorrect family ID (valid ID + 1) + * 2. With otherwise valid command (MY_GENL_SMALL_CMD_GET) + * + * Expected Behavior: + * - Kernel should return NLE_OPNOTSUPP ("Operation not supported") + * - Demonstrates proper error propagation through Netlink stack + * + * Test Methodology: + * 1. Resolves valid family ID for reference + * 2. Creates message with intentionally invalid family ID (+1) + * 3. Verifies: + * - Message transmission succeeds + * - Kernel responds with NLE_OPNOTSUPP + * - Resources are properly cleaned up + * + * Negative Testing: + * - Confirms kernel validates family IDs + * - Tests error handling for invalid destinations + * - Verifies API contract for unsupported operations + */ + +TEST(incorrect_family_id) +{ + struct nl_sock *sock; + int family_id; + struct nl_msg *msg; + struct genlmsghdr *user_hdr; + struct nl_cb *cb; + int err; + struct callback_data cb_data; + + cb_data.int_value =3D -30; + cb_data.message =3D NULL; + + printf("Running Test: trying to send a message to incorrect id of Netlink= family (=3D=3D nonexistent cmd)...\n"); + + sock =3D socket_alloc_and_conn(); + EXPECT_NE(NULL, sock); + if (!sock) { + fprintf(stderr, "socket is NULL\n"); + return; + } + + family_id =3D genl_ctrl_resolve(sock, MY_GENL_FAMILY_NAME); + EXPECT_GT(family_id, 0); + if (family_id < 0) { + err =3D family_id; + fprintf(stderr, "Failed to resolve family id: %s\n", + nl_geterror(err)); + nl_socket_free(sock); + return; + } + + msg =3D nlmsg_alloc(); + EXPECT_NE(NULL, msg); + if (!msg) { + fprintf(stderr, "Failed to allocate message\n"); + nl_socket_free(sock); + return; + } + + // put incorrect id for Netlink message + user_hdr =3D genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family_id + 1, 0, + NLM_F_REQUEST, MY_GENL_SMALL_CMD_GET, 0); + EXPECT_NE(NULL, user_hdr); + if (!user_hdr) { + fprintf(stderr, "Failed to genlmsg_put\n"); + nlmsg_free(msg); + nl_socket_free(sock); + return; + } + + cb =3D nl_cb_alloc(NL_CB_DEFAULT); + EXPECT_NE(NULL, cb); + if (!cb) { + fprintf(stderr, "Failed to allocate callback\n"); + nlmsg_free(msg); + nl_socket_free(sock); + return; + } + + err =3D nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, validate_cb, &cb_data); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Error setting callback: %s\n", + nl_geterror(err)); + goto error; + } + + err =3D nl_send_auto(sock, msg); + EXPECT_GE(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to send message: %s\n", + nl_geterror(err)); + goto error; + } + + err =3D nl_recvmsgs(sock, cb); + EXPECT_EQ(err, -NLE_OPNOTSUPP); + +error: + nlmsg_free(msg); + nl_cb_put(cb); + nl_socket_free(sock); +} + +/** + * TEST(incorrect_cmd) - Tests error handling for invalid Generic Netlink = commands + * + * Validates proper error reporting when: + * 1. Sending a message with deliberately invalid command (SOME_RANDOM_CMD) + * 2. Using otherwise correct family ID and message format + * + * Expected Behavior: + * - Kernel should return NLE_OPNOTSUPP ("Operation not supported") + * - Demonstrates command validation in Generic Netlink subsystem + * + * Test Methodology: + * 1. Resolves valid family ID + * 2. Creates message with invalid command number + * 3. Verifies: + * - Message transmission succeeds (invalid command is syntactically va= lid) + * - Kernel responds with NLE_OPNOTSUPP + * - Resources are properly cleaned up + * + * Negative Testing: + * - Confirms kernel validates command numbers + * - Tests error handling for unsupported operations + * - Verifies API contract for invalid commands + */ + +TEST(incorrect_cmd) +{ + struct nl_sock *sock; + int family_id; + struct nl_msg *msg; + struct genlmsghdr *user_hdr; + struct nl_cb *cb; + int err; + struct callback_data cb_data; + + cb_data.int_value =3D -30; + cb_data.message =3D NULL; + + printf("Running Test: trying to send incorrect =3D=3D non-existent cmd...= \n"); + + sock =3D socket_alloc_and_conn(); + EXPECT_NE(NULL, sock); + if (!sock) { + fprintf(stderr, "socket is NULL\n"); + return; + } + + family_id =3D genl_ctrl_resolve(sock, MY_GENL_FAMILY_NAME); + EXPECT_GT(family_id, 0); + if (family_id < 0) { + err =3D family_id; + fprintf(stderr, "Failed to resolve family id: %s\n", + nl_geterror(err)); + nl_socket_free(sock); + return; + } + + msg =3D nlmsg_alloc(); + EXPECT_NE(NULL, msg); + if (!msg) { + fprintf(stderr, "Failed to allocate message\n"); + nl_socket_free(sock); + return; + } + + user_hdr =3D genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family_id, 0, + NLM_F_REQUEST, SOME_RANDOM_CMD, 0); + EXPECT_NE(NULL, user_hdr); + if (!user_hdr) { + fprintf(stderr, "Failed to genlmsg_put\n"); + nlmsg_free(msg); + nl_socket_free(sock); + return; + } + + cb =3D nl_cb_alloc(NL_CB_DEFAULT); + EXPECT_NE(NULL, cb); + if (!cb) { + fprintf(stderr, "Failed to allocate callback\n"); + nlmsg_free(msg); + nl_socket_free(sock); + return; + } + + err =3D nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, validate_cb, &cb_data); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Error setting callback: %s\n", + nl_geterror(err)); + goto error; + } + + err =3D nl_send_auto(sock, msg); + EXPECT_GE(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to send message: %s\n", + nl_geterror(err)); + goto error; + } + + err =3D nl_recvmsgs(sock, cb); + EXPECT_EQ(err, -NLE_OPNOTSUPP); + +error: + nlmsg_free(msg); + nl_cb_put(cb); + nl_socket_free(sock); +} + +/** + * TEST(incorrect_ctrl_family_name) - Tests error handling for invalid fam= ily names + * in controller requests + * + * Validates that the Generic Netlink controller: + * 1. Properly rejects requests with non-existent family names + * 2. Returns appropriate error code (NLE_INVAL) + * 3. Maintains system stability when receiving invalid parameters + * + * Test Methodology: + * 1. Creates valid connection to genl_ctrl + * 2. Prepares GETFAMILY request with invalid family name + * 3. Verifies: + * - Controller rejects request with NLE_INVAL + * - Error is properly propagated to userspace + * - Resources are correctly cleaned up + * + * Expected Behavior: + * - Kernel should return NLE_INVAL ("Invalid input data or parameter") + * - Controller should maintain stable operation + * - No memory leaks or resource issues + * + * Negative Testing: + * - Confirms input validation in Generic Netlink controller + * - Tests error handling for non-existent entities + * - Verifies API contract for invalid parameters + */ + +TEST(incorrect_ctrl_family_name) +{ + struct nl_sock *ctrl_sock; + int genl_ctrl_family_id; + struct nl_msg *msg; + struct genlmsghdr *user_hdr; + struct nl_cb *cb_ctrl; + int err; + struct callback_data_ctrl cb_ctrl_data; + + cb_ctrl_data.family_id =3D -30; + cb_ctrl_data.family_name =3D NULL; + cb_ctrl_data.op =3D -100; + + printf("Running Test: sending invalid family name to genl_ctrl...\n"); + + ctrl_sock =3D socket_alloc_and_conn(); + EXPECT_NE(NULL, ctrl_sock); + if (!ctrl_sock) { + fprintf(stderr, "socket for genl_ctrl is NULL\n"); + return; + } + + genl_ctrl_family_id =3D genl_ctrl_resolve(ctrl_sock, GENL_CTRL); + EXPECT_GT(genl_ctrl_family_id, 0); + if (genl_ctrl_family_id < 0) { + err =3D genl_ctrl_family_id; + fprintf(stderr, + "Failed to resolve family id for genl_ctrl: %s\n", + nl_geterror(err)); + nl_socket_free(ctrl_sock); + return; + } + + msg =3D nlmsg_alloc(); + EXPECT_NE(NULL, msg); + if (!msg) { + fprintf(stderr, "Failed to allocate message\n"); + nl_socket_free(ctrl_sock); + return; + } + + user_hdr =3D genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, + genl_ctrl_family_id, 0, NLM_F_REQUEST, + CTRL_CMD_GETFAMILY, 0); + EXPECT_NE(NULL, user_hdr); + if (!user_hdr) { + fprintf(stderr, "Failed to genlmsg_put\n"); + nlmsg_free(msg); + nl_socket_free(ctrl_sock); + return; + } + + if (nla_put_string(msg, CTRL_ATTR_FAMILY_NAME, "SOME_RANDOM_NAME") < + 0) { + fprintf(stderr, + "Failed to add incorrect CTRL_ATTR_FAMILY_NAME attribute: %s\n", + strerror(errno)); + nlmsg_free(msg); + nl_socket_free(ctrl_sock); + ASSERT_EQ(0, 1); + return; + } + + cb_ctrl =3D nl_cb_alloc(NL_CB_DEFAULT); + EXPECT_NE(NULL, cb_ctrl); + if (!cb_ctrl) { + fprintf(stderr, "Failed to allocate callback\n"); + nlmsg_free(msg); + nl_socket_free(ctrl_sock); + return; + } + + err =3D nl_cb_set(cb_ctrl, NL_CB_VALID, NL_CB_CUSTOM, validate_cb_ctrl, + &cb_ctrl_data); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Error setting callback: %s\n", + nl_geterror(err)); + goto error; + } + + err =3D nl_send_auto(ctrl_sock, msg); + EXPECT_GE(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to send message: %s\n", + nl_geterror(err)); + goto error; + } + + err =3D nl_recvmsgs(ctrl_sock, cb_ctrl); + EXPECT_EQ(err, -NLE_INVAL); + +error: + nlmsg_free(msg); + nl_cb_put(cb_ctrl); + nl_socket_free(ctrl_sock); +} + +/** + * TEST(incorrect_genl_parallel_with_flag_nonblock_sock_enobufs) - Tests + * NETLINK_NO_ENOBUFS socket option behavior + * + * Validates the interaction of buffer overflow handling with NETLINK_NO_E= NOBUFS by: + * 1. Configuring socket with NETLINK_NO_ENOBUFS option + * 2. Artificially creating buffer overflow conditions + * 3. Verifying the absence of ENOBUFS errors + * 4. Confirming packet loss occurs during overflow + * + * Key Features Tested: + * - NETLINK_NO_ENOBUFS socket option functionality + * - Non-blocking socket behavior under congestion + * - Kernel packet dropping policy + * - Error code propagation + * + * Test Methodology: + * 1. Configure socket with: + * - Small buffer size (2000 bytes) + * - Non-blocking mode + * - NETLINK_NO_ENOBUFS option + * 2. Flood the socket with back-to-back messages (15x) + * 3. Verify: + * - No ENOBUFS errors occur + * - Only EAGAIN is reported when buffer is empty + * - Packet loss occurs (recv_count < send_count) + * + * Expected Behavior: + * - Kernel should suppress ENOBUFS errors when NETLINK_NO_ENOBUFS is set + * - Messages should be silently dropped when buffer is full + * - Application should only see EAGAIN for empty buffer + */ + +TEST(incorrect_genl_parallel_with_flag_nonblock_sock_enobufs) +{ + struct nl_sock *sock; + int family_id; + struct nl_msg *msg; + struct nl_cb *cb; + int err =3D 0; + int send_c; + int recv_c; + + int no_enobufs_val =3D 1; + int sock_fd; + + int optval; + + socklen_t optlen =3D sizeof(optval); + + struct callback_data cb_data; + + cb_data.int_value =3D -30; + cb_data.message =3D NULL; + + printf("Running Test: trying to overflow buffer of nonblock socket with N= ETLINK_NO_ENOBUFS socket option...\n"); + + // Only root can write to sysfs (needs for testing) + if (geteuid()) { + SKIP(return, "test requires root"); + return; + } + + sock =3D socket_alloc_and_conn(); + EXPECT_NE(NULL, sock); + if (!sock) { + fprintf(stderr, "socket is NULL\n"); + return; + } + + sock_fd =3D nl_socket_get_fd(sock); + EXPECT_GE(sock_fd, 0); + if (sock_fd < 0) { + err =3D sock_fd; + fprintf(stderr, "Failed to get socket file descriptor: %s\n", + nl_geterror(err)); + nl_socket_free(sock); + return; + } + + err =3D setsockopt(sock_fd, SOL_NETLINK, NETLINK_NO_ENOBUFS, + &no_enobufs_val, sizeof(no_enobufs_val)); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to set NETLINK_NO_ENOBUFS: %s\n", + strerror(errno)); + nl_socket_free(sock); + return; + } + + err =3D getsockopt(sock_fd, SOL_NETLINK, NETLINK_NO_ENOBUFS, &optval, + &optlen); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to get NETLINK_NO_ENOBUFS: %s\n", + strerror(errno)); + nl_socket_free(sock); + return; + } + + EXPECT_EQ(optval, 1); + + family_id =3D genl_ctrl_resolve(sock, PARALLEL_GENL_FAMILY_NAME); + EXPECT_GT(family_id, 0); + if (family_id < 0) { + fprintf(stderr, "Failed to resolve family id: %d\n", family_id); + nl_socket_free(sock); + return; + } + + err =3D nl_socket_set_buffer_size(sock, 2000, 2000); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to change socket buffer size: %s\n", + nl_geterror(err)); + nl_socket_free(sock); + return; + } + + err =3D nl_socket_set_nonblocking(sock); + EXPECT_EQ(err, 0); + + cb =3D nl_cb_alloc(NL_CB_DEFAULT); + EXPECT_NE(NULL, cb); + if (!cb) { + fprintf(stderr, "Failed to allocate callback\n"); + nl_socket_free(sock); + return; + } + + err =3D nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, validate_cb_parallel, + &cb_data); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Error setting callback: %s\n", + nl_geterror(err)); + nl_socket_free(sock); + return; + } + + send_c =3D 15; + recv_c =3D 0; + for (int i =3D 0; i < send_c; i++) { + msg =3D genl_generate_messages(family_id, 1); + EXPECT_NE(NULL, msg); + if (!msg) { + fprintf(stderr, "Failed to create message\n"); + goto error; + } + err =3D nl_send_auto(sock, msg); + EXPECT_GE(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to send message: %s\n", + nl_geterror(err)); + goto error; + } + nlmsg_free(msg); + } + + for (int i =3D 0; i < send_c; i++) { + err =3D nl_recvmsgs(sock, cb); + if (err < 0) { + EXPECT_EQ(err, -NLE_AGAIN); + EXPECT_EQ(errno, EAGAIN); + } + if (err =3D=3D 0) + recv_c++; + + EXPECT_NE(errno, ENOBUFS); + } + EXPECT_LT(recv_c, send_c); + +error: + nl_cb_put(cb); + nl_socket_free(sock); +} + +/** + * TEST(genl_test_get_value_sock_option) - Tests NETLINK_NO_ENOBUFS socket= option functionality + * + * Validates the complete workflow of setting and using the NETLINK_NO_ENO= BUFS socket option: + * 1. Sets and verifies NETLINK_NO_ENOBUFS socket option + * 2. Performs standard GET_VALUE operation + * 3. Verifies successful message exchange despite option being set + * + * Key Features Tested: + * - NETLINK_NO_ENOBUFS option setting and verification + * - Normal operation with the option enabled + * - Integration with existing GET_VALUE functionality + * - Sysfs value verification + * + * Test Flow: + * 1. Configure socket with NETLINK_NO_ENOBUFS option + * 2. Verify option was correctly set + * 3. Resolve family and multicast group IDs + * 4. Prepare and send GET_VALUE request + * 5. Validate response and sysfs value + * 6. Clean up test environment + * + * Special Considerations: + * - Requires root privileges for sysfs access + * - Tests both socket option functionality and normal operation + * - Maintains backward compatibility with existing behavior + */ + +TEST(genl_test_get_value_sock_option) +{ + struct nl_sock *nl_sock; + int family_id; + int mcgrp_id; + struct nl_msg *msg; + struct nl_cb *cb; + int err; + int int_value; + int no_enobufs_val =3D 1; + int sock_fd; + + int optval; + + socklen_t optlen =3D sizeof(optval); + + struct genlmsghdr *user_hdr; + + struct callback_data cb_data; + + printf("Running Test: sending a message with NETLINK_NO_ENOBUFS socket op= tion...\n"); + + // Only root can write to sysfs (needs for testing) + if (geteuid()) { + SKIP(return, "test requires root"); + return; + } + + nl_sock =3D socket_alloc_and_conn(); + EXPECT_NE(NULL, nl_sock); + if (!nl_sock) { + printf("socket for my_genl is NULL\n"); + return; + } + + sock_fd =3D nl_socket_get_fd(nl_sock); + EXPECT_GE(sock_fd, 0); + if (sock_fd < 0) { + err =3D sock_fd; + fprintf(stderr, "Failed to get socket file descriptor: %s\n", + nl_geterror(err)); + nl_socket_free(nl_sock); + return; + } + + err =3D setsockopt(sock_fd, SOL_NETLINK, NETLINK_NO_ENOBUFS, + &no_enobufs_val, sizeof(no_enobufs_val)); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to set NETLINK_NO_ENOBUFS: %s\n", + strerror(errno)); + err =3D -errno; + nl_socket_free(nl_sock); + return; + } + + err =3D getsockopt(sock_fd, SOL_NETLINK, NETLINK_NO_ENOBUFS, &optval, + &optlen); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to get NETLINK_NO_ENOBUFS: %s\n", + strerror(errno)); + err =3D -errno; + nl_socket_free(nl_sock); + return; + } + + EXPECT_EQ(optval, 1); + + family_id =3D genl_ctrl_resolve(nl_sock, MY_GENL_FAMILY_NAME); + EXPECT_GT(family_id, 0); + if (family_id < 0) { + err =3D family_id; + fprintf(stderr, "Failed to resolve family id: %s\n", + nl_geterror(err)); + nl_socket_free(nl_sock); + return; + } + + mcgrp_id =3D genl_ctrl_resolve_grp(nl_sock, MY_GENL_FAMILY_NAME, + MY_MCGRP_NAME); + EXPECT_GE(mcgrp_id, 0); + if (mcgrp_id < 0) { + err =3D mcgrp_id; + fprintf(stderr, "Failed to resolve multicast group: %s\n", + nl_geterror(err)); + nl_socket_free(nl_sock); + return; + } + + err =3D nl_socket_add_membership(nl_sock, mcgrp_id); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to add membership: %s\n", + nl_geterror(err)); + nl_socket_free(nl_sock); + return; + } + + msg =3D nlmsg_alloc(); + EXPECT_NE(NULL, msg); + if (!msg) { + fprintf(stderr, "Failed to allocate message\n"); + nl_socket_free(nl_sock); + return; + } + + user_hdr =3D genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family_id, 0, + NLM_F_REQUEST, MY_GENL_CMD_GET_VALUE, 0); + EXPECT_NE(NULL, user_hdr); + if (!user_hdr) { + fprintf(stderr, "Failed to genlmsg_put\n"); + nlmsg_free(msg); + nl_socket_free(nl_sock); + return; + } + + if (nla_put_string(msg, MY_GENL_ATTR_PATH, PATH_GENL_TEST_NUM) < 0) { + fprintf(stderr, + "Failed to add MY_GENL_ATTR_PATH attribute: %s\n", + strerror(errno)); + nlmsg_free(msg); + nl_socket_free(nl_sock); + ASSERT_EQ(0, 1); + return; + } + + cb =3D nl_cb_alloc(NL_CB_DEFAULT); + EXPECT_NE(NULL, cb); + if (!cb) { + fprintf(stderr, "Failed to allocate callback\n"); + nlmsg_free(msg); + nl_socket_free(nl_sock); + return; + } + + err =3D nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, validate_cb, &cb_data); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Error setting callback: %s\n", + nl_geterror(err)); + goto error; + } + + err =3D nl_send_auto(nl_sock, msg); + EXPECT_GE(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to send message: %s\n", + nl_geterror(err)); + goto error; + } + + err =3D nl_recvmsgs(nl_sock, cb); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to receive message: %s\n", + nl_geterror(err)); + goto error; + } + + err =3D read_int_from_sysfs(PATH_GENL_TEST_NUM, &int_value); + EXPECT_EQ(err, 0); + if (err) { + fprintf(stderr, "Failed to read from sysfs: %s\n", + strerror(err)); + goto error; + } + + EXPECT_EQ(int_value, cb_data.int_value); + + err =3D write_int_to_sysfs(PATH_GENL_TEST_NUM, -20); + EXPECT_EQ(err, 0); + if (err) { + fprintf(stderr, "Failed to write to sysfs: %s\n", + strerror(err)); + goto error; + } + +error: + nlmsg_free(msg); + nl_cb_put(cb); + nl_socket_free(nl_sock); +} + +/** + * TEST(incorrect_genl_test_ext_ack) - NETLINK_EXT_ACK error handling veri= fication + * + * Validates extended error acknowledgment mechanism by: + * 1. Testing successful setting of NETLINK_EXT_ACK socket option + * 2. Sending deliberately malformed Generic Netlink message: + * - Contains invalid path attribute (MY_GENL_ATTR_PATH=3D"some/random/= path") + * 3. Verifying kernel returns expected error (EINVAL/NLE_INVAL) + * 4. Checking proper delivery of extended error information via EXT_ACK + * + * Expected behavior: + * - NETLINK_EXT_ACK option should be successfully set (optval =3D=3D 1) + * - Kernel should reject malformed message with -NLE_INVAL error + * + * Implementation notes: + * - Uses synthetic invalid path to guarantee error generation + * - Tests complete workflow: option setup -> message send -> error handli= ng + * - Covers both basic error code and extended error information + */ + +TEST(incorrect_genl_test_ext_ack) +{ + struct nl_sock *nl_sock; + int family_id; + int mcgrp_id; + struct nl_msg *msg; + struct nl_cb *cb; + int err; + int up; + int sock_fd; + + int optval; + + socklen_t optlen =3D sizeof(optval); + + struct genlmsghdr *user_hdr; + struct callback_data cb_data; + + printf("Running Test: sending a message with NETLINK_EXT_ACK socket optio= n and incorrect path value...\n"); + + nl_sock =3D socket_alloc_and_conn(); + EXPECT_NE(NULL, nl_sock); + if (!nl_sock) { + fprintf(stderr, "socket for my_genl is NULL\n"); + return; + } + + sock_fd =3D nl_socket_get_fd(nl_sock); + EXPECT_GE(sock_fd, 0); + if (sock_fd < 0) { + err =3D sock_fd; + fprintf(stderr, "Failed to get socket file descriptor: %s\n", + nl_geterror(err)); + nl_socket_free(nl_sock); + return; + } + + up =3D 1; + err =3D setsockopt(sock_fd, SOL_NETLINK, NETLINK_EXT_ACK, &up, + sizeof(up)); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to set NETLINK_EXT_ACK: %s", + strerror(errno)); + err =3D -errno; + nl_socket_free(nl_sock); + return; + } + + err =3D getsockopt(sock_fd, SOL_NETLINK, NETLINK_EXT_ACK, &optval, + &optlen); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to get NETLINK_EXT_ACK: %s", + strerror(errno)); + err =3D -errno; + nl_socket_free(nl_sock); + return; + } + + EXPECT_EQ(optval, 1); + + family_id =3D genl_ctrl_resolve(nl_sock, MY_GENL_FAMILY_NAME); + EXPECT_GT(family_id, 0); + if (family_id < 0) { + err =3D family_id; + fprintf(stderr, "Failed to resolve family id: %s\n", + nl_geterror(err)); + nl_socket_free(nl_sock); + return; + } + + mcgrp_id =3D genl_ctrl_resolve_grp(nl_sock, MY_GENL_FAMILY_NAME, + MY_MCGRP_NAME); + EXPECT_GE(mcgrp_id, 0); + if (mcgrp_id < 0) { + err =3D mcgrp_id; + fprintf(stderr, "Failed to resolve multicast group: %s\n", + nl_geterror(err)); + nl_socket_free(nl_sock); + return; + } + + err =3D nl_socket_add_membership(nl_sock, mcgrp_id); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to add membership: %s\n", + nl_geterror(err)); + nl_socket_free(nl_sock); + return; + } + + msg =3D nlmsg_alloc(); + EXPECT_NE(NULL, msg); + if (!msg) { + fprintf(stderr, "Failed to allocate message\n"); + nl_socket_free(nl_sock); + return; + } + + user_hdr =3D genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family_id, 0, + NLM_F_REQUEST, MY_GENL_CMD_GET_VALUE, 0); + EXPECT_NE(NULL, user_hdr); + if (!user_hdr) { + fprintf(stderr, "Failed to genlmsg_put\n"); + nlmsg_free(msg); + nl_socket_free(nl_sock); + return; + } + + if (nla_put_string(msg, MY_GENL_ATTR_PATH, "some/random/path") < 0) { + fprintf(stderr, + "Failed to add MY_GENL_ATTR_PATH attribute: %s\n", + strerror(errno)); + nlmsg_free(msg); + nl_socket_free(nl_sock); + ASSERT_EQ(0, 1); + return; + } + + cb =3D nl_cb_alloc(NL_CB_DEFAULT); + EXPECT_NE(NULL, cb); + if (!cb) { + fprintf(stderr, "Failed to allocate callback\n"); + nlmsg_free(msg); + nl_socket_free(nl_sock); + return; + } + + err =3D nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, validate_cb, &cb_data); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Error setting callback: %s\n", + nl_geterror(err)); + goto error; + } + + err =3D nl_send_auto(nl_sock, msg); + EXPECT_GE(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to send message: %s\n", + nl_geterror(err)); + goto error; + } + + err =3D nl_recvmsgs(nl_sock, cb); + EXPECT_EQ(err, -NLE_INVAL); + +error: + nlmsg_free(msg); + nl_cb_put(cb); + nl_socket_free(nl_sock); +} + +/** + * TEST(genl_test_sock_listen_all_nsid) - Tests NETLINK_LISTEN_ALL_NSID so= cket option functionality + * + * Validates the behavior of NETLINK_LISTEN_ALL_NSID socket option by: + * 1. Setting the NETLINK_LISTEN_ALL_NSID option on a netlink socket + * 2. Verifying proper socket operation with this option enabled + * 3. Testing permission enforcement (root privileges required) + * 4. Performing end-to-end communication with the option set + * + * Test flow: + * - Creates netlink socket with increased buffer size + * - Sets NETLINK_LISTEN_ALL_NSID option + * - Configures Generic Netlink communication: + * - Resolves family and multicast group IDs + * - Sets up message and callback + * - Performs round-trip message exchange + * - Verifies sysfs interaction matches received data + * + * Special considerations: + * - Requires root privileges (checks and skips if not root) + * - No getsockopt available for NETLINK_LISTEN_ALL_NSID verification + * - Tests both successful operation and permission error cases + * - Includes sysfs value validation for complete functionality check + * + * Expected results: + * - Root user: Successful option setting and normal operation + * - Correct message handling through entire communication chain + * - Proper sysfs value synchronization with received data + * - Non-root: Graceful test skipping + */ + +TEST(genl_test_sock_listen_all_nsid) +{ + struct nl_sock *nl_sock; + int family_id; + int mcgrp_id; + struct nl_msg *msg; + struct nl_cb *cb; + int err; + int int_value; + int up; + int sock_fd; + + struct genlmsghdr *user_hdr; + struct callback_data cb_data; + + printf("Running Test: setting NETLINK_LISTEN_ALL_NSID option for socket..= .\n"); + + // Only root can listen to different Netlink namespaces + if (geteuid()) { + SKIP(return, "test requires root"); + return; + } + + nl_sock =3D socket_alloc_and_conn(); + EXPECT_NE(NULL, nl_sock); + if (!nl_sock) { + printf("socket for my_genl is NULL\n"); + return; + } + + err =3D nl_socket_set_buffer_size(nl_sock, 8000, 8000); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to change socket buffer size: %s\n", + strerror(err)); + nl_socket_free(nl_sock); + return; + } + + sock_fd =3D nl_socket_get_fd(nl_sock); + EXPECT_GE(sock_fd, 0); + if (sock_fd < 0) { + err =3D sock_fd; + fprintf(stderr, "Failed to get socket file descriptor: %s\n", + nl_geterror(err)); + nl_socket_free(nl_sock); + return; + } + + up =3D 1; + err =3D setsockopt(sock_fd, SOL_NETLINK, NETLINK_LISTEN_ALL_NSID, &up, + sizeof(up)); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to set NETLINK_LISTEN_ALL_NSID: %s\n", + strerror(err)); + nl_socket_free(nl_sock); + return; + } + + family_id =3D genl_ctrl_resolve(nl_sock, MY_GENL_FAMILY_NAME); + EXPECT_GT(family_id, 0); + if (family_id < 0) { + err =3D family_id; + fprintf(stderr, "Failed to resolve family id: %s\n", + nl_geterror(err)); + nl_socket_free(nl_sock); + return; + } + + mcgrp_id =3D genl_ctrl_resolve_grp(nl_sock, MY_GENL_FAMILY_NAME, + MY_MCGRP_NAME); + EXPECT_GE(mcgrp_id, 0); + if (mcgrp_id < 0) { + err =3D mcgrp_id; + fprintf(stderr, "Failed to resolve multicast group: %s\n", + nl_geterror(err)); + nl_socket_free(nl_sock); + return; + } + + err =3D nl_socket_add_membership(nl_sock, mcgrp_id); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to add membership: %s\n", + nl_geterror(err)); + nl_socket_free(nl_sock); + return; + } + + msg =3D nlmsg_alloc(); + EXPECT_NE(NULL, msg); + if (!msg) { + fprintf(stderr, "Failed to allocate message\n"); + nl_socket_free(nl_sock); + return; + } + + user_hdr =3D genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family_id, 0, + NLM_F_REQUEST, MY_GENL_CMD_GET_VALUE, 0); + EXPECT_NE(NULL, user_hdr); + if (!user_hdr) { + fprintf(stderr, "Failed to genlmsg_put\n"); + nlmsg_free(msg); + nl_socket_free(nl_sock); + return; + } + + if (nla_put_string(msg, MY_GENL_ATTR_PATH, PATH_GENL_TEST_NUM) < 0) { + fprintf(stderr, + "Failed to add MY_GENL_ATTR_PATH attribute: %s\n", + strerror(errno)); + nlmsg_free(msg); + nl_socket_free(nl_sock); + ASSERT_EQ(0, 1); + return; + } + + cb =3D nl_cb_alloc(NL_CB_DEFAULT); + EXPECT_NE(NULL, cb); + if (!cb) { + fprintf(stderr, "Failed to allocate callback\n"); + nlmsg_free(msg); + nl_socket_free(nl_sock); + return; + } + + err =3D nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, validate_cb, &cb_data); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Error setting callback: %s\n", + nl_geterror(err)); + goto error; + } + + err =3D nl_send_auto(nl_sock, msg); + EXPECT_GE(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to send message: %s\n", + nl_geterror(err)); + goto error; + } + + err =3D nl_recvmsgs(nl_sock, cb); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to receive message: %s\n", + nl_geterror(err)); + goto error; + } + + err =3D read_int_from_sysfs(PATH_GENL_TEST_NUM, &int_value); + EXPECT_EQ(err, 0); + if (err) { + fprintf(stderr, "Failed to read from sysfs: %s\n", + strerror(err)); + goto error; + } + + EXPECT_EQ(int_value, cb_data.int_value); + + err =3D write_int_to_sysfs(PATH_GENL_TEST_NUM, -20); + EXPECT_EQ(err, 0); + if (err) { + fprintf(stderr, "Failed to write to sysfs: %s\n", + strerror(err)); + goto error; + } + +error: + nlmsg_free(msg); + nl_cb_put(cb); + nl_socket_free(nl_sock); +} + +/** + * TEST(genl_third_echo) - Validates NLM_F_ECHO flag functionality in Gene= ric Netlink + * + * Tests the echo/reply mechanism by: + * 1. Creating a Netlink socket and resolving the third_genl family + * 2. Sending a message with NLM_F_ECHO flag set + * 3. Verifying proper echo reply handling through: + * - Callback validation (validate_cb_third) + * - Sysfs value comparison + * + * Test Flow: + * - Requires root privileges (for sysfs operations) + * - Allocates and configures Netlink socket and message + * - Sets up callback for reply validation + * - Sends echo request and waits for reply + * - Compares received message with sysfs content + * - Cleans up sysfs state after verification + * + * Key Validations: + * - Successful message round-trip with echo flag + * - Correct message content in callback vs sysfs + * - Proper resource cleanup in all code paths + * - Root permission enforcement + * + * Expected Behavior: + * - Message with NLM_F_ECHO should trigger reply from kernel + * - Callback should receive matching message content + * - Sysfs should reflect the same message content + * - Non-root users should be properly handled + */ + +TEST(genl_third_echo) +{ + struct nl_sock *sock; + int family_id; + struct nl_msg *msg; + struct genlmsghdr *user_hdr; + struct nl_cb *cb; + int err; + + struct callback_data_third cb_data; + + printf("Running Test: sending message to third_genl...\n"); + + // Only root can write to sysfs (needs for testing) + if (geteuid()) { + SKIP(return, "test requires root"); + return; + } + + sock =3D socket_alloc_and_conn(); + EXPECT_NE(NULL, sock); + if (!sock) { + fprintf(stderr, "socket is NULL\n"); + return; + } + + family_id =3D my_genl_ctrl_resolve(THIRD_GENL_FAMILY_NAME); + EXPECT_GT(family_id, 0); + if (family_id < 0) { + err =3D family_id; + fprintf(stderr, + "Failed to resolve family id for THIRD_GENL: %s\n", + nl_geterror(err)); + nl_socket_free(sock); + return; + } + + msg =3D nlmsg_alloc(); + EXPECT_NE(NULL, msg); + if (!msg) { + fprintf(stderr, "Failed to allocate message\n"); + nl_socket_free(sock); + return; + } + + user_hdr =3D genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family_id, 0, + NLM_F_ECHO, THIRD_GENL_CMD_ECHO, 0); + EXPECT_NE(NULL, user_hdr); + if (!user_hdr) { + fprintf(stderr, "Failed to genlmsg_put\n"); + nlmsg_free(msg); + nl_socket_free(sock); + return; + } + + cb =3D nl_cb_alloc(NL_CB_DEFAULT); + EXPECT_NE(NULL, cb); + if (!cb) { + fprintf(stderr, "Failed to allocate callback\n"); + nlmsg_free(msg); + nl_socket_free(sock); + return; + } + + char *str =3D malloc(BUFFER_SIZE); + + err =3D nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, validate_cb_third, + &cb_data); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Error setting callback: %s\n", + nl_geterror(err)); + goto error; + } + + err =3D nl_send_auto(sock, msg); + EXPECT_GE(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to send message: %s\n", + nl_geterror(err)); + goto error; + } + + err =3D nl_recvmsgs(sock, cb); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to receive message: %s\n", + nl_geterror(err)); + goto error; + } + + err =3D read_string_from_sysfs(PATH_THIRD_GENL_MES, str, BUFFER_SIZE); + EXPECT_EQ(err, 0); + if (err) { + fprintf(stderr, "Failed to read from sysfs: %s\n", + strerror(err)); + goto error; + } + + EXPECT_STREQ(str, cb_data.message); + + err =3D write_string_to_sysfs(PATH_THIRD_GENL_MES, "default"); + EXPECT_EQ(err, 0); + if (err) { + fprintf(stderr, "Failed to write to sysfs: %s\n", + strerror(err)); + goto error; + } + +error: + free(str); + nlmsg_free(msg); + nl_cb_put(cb); + nl_socket_free(sock); +} + +/** + * TEST(incorrect_genl_third_echo_flags) - Validates Netlink flag enforcem= ent + * + * Tests kernel's handling of invalid Netlink message flags by: + * 1. Sending a message with explicitly prohibited flag combination (NLM_F= _ECHO | NLM_F_ATOMIC) + * 2. Verifying proper error response (EINVAL/NLE_INVAL) + * + * Test Flow: + * 1. Creates and configures Netlink socket + * 2. Resolves THIRD_GENL family + * 3. Constructs message with invalid flags: + * - Uses valid NLM_F_ECHO + * - Adds invalid NLM_F_ATOMIC (prohibited for Generic Netlink) + * 4. Sets up validation callback + * 5. Sends message and verifies error response + * + * Key Validations: + * - Kernel rejects messages with invalid flag combinations + * - Correct error code (NLE_INVAL) is returned + * - Proper resource cleanup in all execution paths + * + * Expected Behavior: + * - Kernel should reject message with EINVAL/NLE_INVAL + * - No callback validation should occur (message fails before processing) + * - All allocated resources should be properly freed + * + * Note: + * - Only these flags are valid for Generic Netlink: + * NLM_F_REQUEST, NLM_F_ACK, NLM_F_ECHO, NLM_F_DUMP + * - NLM_F_ATOMIC is explicitly invalid for Generic Netlink + */ + +TEST(incorrect_genl_third_echo_flags) +{ + struct nl_sock *sock; + int family_id; + struct nl_msg *msg; + struct genlmsghdr *user_hdr; + struct nl_cb *cb; + int err; + + struct callback_data_third cb_data; + + printf("Running Test: sending message with incorrect flags to third_genl.= ..\n"); + + sock =3D socket_alloc_and_conn(); + EXPECT_NE(NULL, sock); + if (!sock) { + fprintf(stderr, "socket is NULL\n"); + return; + } + + family_id =3D genl_ctrl_resolve(sock, "THIRD_GENL"); + EXPECT_GT(family_id, 0); + if (family_id < 0) { + err =3D family_id; + fprintf(stderr, + "Failed to resolve family id for THIRD_GENL: %s\n", + nl_geterror(err)); + nl_socket_free(sock); + return; + } + + msg =3D nlmsg_alloc(); + EXPECT_NE(NULL, msg); + if (!msg) { + fprintf(stderr, "Failed to allocate message\n"); + nl_socket_free(sock); + return; + } + + user_hdr =3D genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family_id, 0, + NLM_F_ECHO | NLM_F_ATOMIC, THIRD_GENL_CMD_ECHO, + 0); + EXPECT_NE(NULL, user_hdr); + if (!user_hdr) { + fprintf(stderr, "Failed to genlmsg_put\n"); + nlmsg_free(msg); + nl_socket_free(sock); + return; + } + + cb =3D nl_cb_alloc(NL_CB_DEFAULT); + EXPECT_NE(NULL, cb); + if (!cb) { + fprintf(stderr, "Failed to allocate callback\n"); + nlmsg_free(msg); + nl_socket_free(sock); + return; + } + + err =3D nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, validate_cb_third, + &cb_data); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Error setting callback: %s\n", + nl_geterror(err)); + goto error; + } + + err =3D nl_send_auto(sock, msg); + EXPECT_GE(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to send message: %s\n", + nl_geterror(err)); + goto error; + } + + err =3D nl_recvmsgs(sock, cb); + EXPECT_EQ(err, -NLE_INVAL); + +error: + nlmsg_free(msg); + nl_cb_put(cb); + nl_socket_free(sock); +} + +/** + * TEST(new_socket_netlink_usersock) - Validates NETLINK_USERSOCK socket l= ifecycle + * + * Tests the creation and cleanup of NETLINK_USERSOCK sockets by: + * 1. Creating and connecting a NETLINK_USERSOCK socket + * 2. Verifying its presence in /proc/net/netlink + * 3. Checking proper cleanup after socket release + * + * Test Methodology: + * 1. Socket Allocation: + * - Creates socket using nl_socket_alloc() + * - Binds to NETLINK_USERSOCK protocol (2) + * + * 2. System Validation: + * - Parses /proc/net/netlink to count active sockets + * - Verifies exactly one new NETLINK_USERSOCK exists + * - Includes 2-second delay for kernel state synchronization + * - Re-checks /proc after socket release + * + * 3. Cleanup Verification: + * - Confirms socket count returns to baseline + * - Validates proper resource deallocation + * + * Key Validations: + * - Correct socket creation in kernel space + * - Accurate /proc filesystem reporting + * - Proper socket cleanup on free + * - Robust parsing of /proc/net/netlink format + * + * Expected Behavior: + * - Socket appears in /proc/net/netlink after creation + * - Socket disappears from /proc/net/netlink after release + * - Final count matches initial baseline + * - All file handles properly closed + * + * Note: + * - Uses 2-second delay to account for kernel cleanup latency + * - Handles potential /proc/net/netlink parsing errors gracefully + * - Validates both presence and absence of socket record + */ + +TEST(new_socket_netlink_usersock) +{ +#define NETLINK_USERSOCK 2 // Reserved for user mode socket protocols + int err; + + struct nl_sock *sock; + char *header; + + printf("Running Test: creating socket for user mode and checking it exist= ence in the system...\n"); + + sock =3D nl_socket_alloc(); + EXPECT_NE(NULL, sock); + if (!sock) { + fprintf(stderr, "Failed to allocate socket\n"); + return; + } + + err =3D nl_connect(sock, NETLINK_USERSOCK); + EXPECT_EQ(err, 0); + if (err) { + fprintf(stderr, + "Failed to connect to Netlink using NETLINK_USERSOCK: %s\n", + nl_geterror(err)); + nl_socket_free(sock); + return; + } + + FILE *file; + char line[256]; + char sk[20]; + int Eth, Pid; + unsigned int Groups, Rmem, Wmem, Dump, Locks, Drops, Inode; + + int count_user_socks =3D 0; + + file =3D fopen("/proc/net/netlink", "r"); + EXPECT_NE(NULL, file); + if (file =3D=3D NULL) { + perror("fopen"); + return; + } + + // Skip header + header =3D fgets(line, sizeof(line), file); + EXPECT_NE(NULL, header); + if (header =3D=3D NULL) { + fclose(file); + nl_socket_free(sock); + return; + } + + // Parse line + while (fgets(line, sizeof(line), file) !=3D NULL) { + if (!isxdigit( + line[0])) { // check if the first column is 16-number value + break; + } + if (sscanf(line, + "%19s %d %d %x %u %u %u %u %u %u", // limit sk len to 19 symbols + sk, &Eth, &Pid, &Groups, &Rmem, &Wmem, &Dump, &Locks, + &Drops, &Inode) =3D=3D 10) { + if (Eth =3D=3D NETLINK_USERSOCK) + count_user_socks +=3D 1; + + } else { + fprintf(stderr, "Failed to parse line: %s", line); + EXPECT_EQ(0, 1); + } + } + + fclose(file); + + nl_socket_free(sock); + + sleep(2); + + file =3D fopen("/proc/net/netlink", "r"); + EXPECT_NE(NULL, file); + if (file =3D=3D NULL) { + perror("fopen"); + return; + } + + header =3D fgets(line, sizeof(line), file); + EXPECT_NE(NULL, header); + if (header =3D=3D NULL) { + fclose(file); + return; + } + + while (fgets(line, sizeof(line), file) !=3D NULL) { + if (!isxdigit(line[0])) + break; + + if (sscanf(line, "%19s %d %d %x %u %u %u %u %u %u", sk, &Eth, + &Pid, &Groups, &Rmem, &Wmem, &Dump, &Locks, &Drops, + &Inode) =3D=3D 10) { + if (Eth =3D=3D NETLINK_USERSOCK) + count_user_socks -=3D 1; + + } else { + fprintf(stderr, "Failed to parse line: %s", line); + EXPECT_EQ(0, 1); + } + } + + fclose(file); + + EXPECT_TRUE(count_user_socks =3D=3D 1); +} + +/** + * TEST(incorrect_parallel_genl_reject_policy_set_value) - Validates rejec= t policy enforcement + * + * Tests the Generic Netlink reject policy by: + * 1. Sending a properly formatted message to a command with reject policy + * 2. Verifying the kernel rejects the message with EINVAL + * 3. Confirming all attributes are properly skipped + * + * Test Methodology: + * 1. Creates Generic Netlink socket and resolves parallel_genl family + * 2. Constructs message with: + * - Valid path attribute (PATH_PARALLEL_GENL_MES) + * - Test data ("value for reject") + * - SET_VALUE command (PARALLEL_GENL_CMD_SET_VALUE) + * 3. Configures validation callback + * 4. Sends message and verifies rejection + * + * Key Validations: + * - Kernel properly enforces reject policy + * - Correct error code (NLE_INVAL) is returned + * - Message attributes are ignored as expected + * - Resources are properly cleaned up + * + * Expected Behavior: + * - Kernel should reject message with EINVAL/NLE_INVAL + * - No callback validation should occur (message rejected by policy) + * - All allocated resources should be freed + * + * Special Considerations: + * - Tests edge case of valid message format but rejected by policy + * - Verifies proper attribute handling under reject policy + * - Validates correct error propagation to userspace + */ + +TEST(incorrect_parallel_genl_reject_policy_set_value) +{ + struct nl_sock *nl_sock; + int family_id; + struct nl_msg *msg; + struct nl_cb *cb; + int err =3D 0; + char *value; + struct genlmsghdr *user_hdr; + struct callback_data cb_data; + + printf("Running Test: sending correct value for sysfs to parallel_genl to= check reject policy...\n"); + + nl_sock =3D socket_alloc_and_conn(); + EXPECT_NE(NULL, nl_sock); + if (!nl_sock) + return; + + family_id =3D genl_ctrl_resolve(nl_sock, PARALLEL_GENL_FAMILY_NAME); + EXPECT_GT(family_id, 0); + if (family_id < 0) { + nl_socket_free(nl_sock); + err =3D family_id; + return; + } + + msg =3D nlmsg_alloc(); + EXPECT_NE(NULL, msg); + if (!msg) { + nl_socket_free(nl_sock); + return; + } + + user_hdr =3D genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family_id, 0, + NLM_F_REQUEST, PARALLEL_GENL_CMD_SET_VALUE, 0); + EXPECT_NE(NULL, user_hdr); + if (!user_hdr) { + nlmsg_free(msg); + nl_socket_free(nl_sock); + return; + } + + if (nla_put_string(msg, PARALLEL_GENL_ATTR_PATH, + PATH_PARALLEL_GENL_MES) < 0) { + nlmsg_free(msg); + nl_socket_free(nl_sock); + ASSERT_EQ(0, 1); + return; + } + + value =3D "value for reject"; + if (nla_put_string(msg, PARALLEL_GENL_ATTR_DATA, value) < 0) { + nlmsg_free(msg); + nl_socket_free(nl_sock); + ASSERT_EQ(0, 1); + return; + } + + cb =3D nl_cb_alloc(NL_CB_DEFAULT); + EXPECT_NE(NULL, cb); + if (!cb) { + fprintf(stderr, "Failed to allocate callback\n"); + nlmsg_free(msg); + nl_socket_free(nl_sock); + return; + } + + err =3D nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, validate_cb, &cb_data); + EXPECT_EQ(err, 0); + if (err < 0) { + fprintf(stderr, "Error setting callback: %s\n", + nl_geterror(err)); + goto error; + } + + err =3D nl_send_auto(nl_sock, msg); + EXPECT_GE(err, 0); + if (err < 0) { + fprintf(stderr, "Failed to send message: %s\n", + nl_geterror(err)); + goto error; + } + + err =3D nl_recvmsgs(nl_sock, cb); + EXPECT_EQ(err, -NLE_INVAL); + +error: + nlmsg_free(msg); + nl_cb_put(cb); + nl_socket_free(nl_sock); +} + +/** + * TEST(connect_sock) - Validates raw Netlink socket operations using syst= em calls + * + * Tests the complete lifecycle of a Netlink socket using low-level system= calls: + * 1. Creates a raw NETLINK_GENERIC socket + * 2. Binds to the socket with process-specific PID + * 3. Connects to the kernel (pid 0) + * 4. Properly closes the socket + * + * Test Methodology: + * 1. Initial Setup: + * - Uses libnl to resolve Generic Netlink family (for verification) + * - Releases libnl socket to test raw system calls + * + * 2. System Call Validation: + * - Creates socket with AF_NETLINK/SOCK_RAW + * - Binds to process PID (getpid()) + * - Connects to kernel (pid 0) + * - Verifies each operation succeeds + * + * 3. Cleanup: + * - Proper socket closure + * - Resource cleanup + * + * Key Validations: + * - Correct socket creation with NETLINK_GENERIC + * - Proper binding with AF_NETLINK + * - Successful connection to kernel + * - Error handling for all system calls + * - Resource cleanup + * + * Expected Behavior: + * - All system calls should succeed + * - Socket should be properly bound to process PID + * - Connection to kernel (pid 0) should establish + * - No resource leaks after close() + * + * Note: + * - Uses both libnl and raw system calls for comprehensive validation + * - Tests the fundamental Netlink socket operations + * - Verifies proper kernel/userspace communication setup + */ + +TEST(connect_sock) +{ + int sock_fd; + struct sockaddr_nl src_addr, dest_addr; + int family_id; + struct nl_sock *sock; + int err; + + printf("Running Test: using system calls to operate with Netlink socket..= .\n"); + + sock =3D socket_alloc_and_conn(); + EXPECT_NE(NULL, sock); + if (!sock) + return; + + family_id =3D genl_ctrl_resolve(sock, MY_GENL_FAMILY_NAME); + EXPECT_GT(family_id, 0); + if (family_id < 0) { + fprintf(stderr, + "Failed to resolve family id for TEST_GENL: %d\n", + family_id); + nl_socket_free(sock); + err =3D family_id; + return; + } + + nl_socket_free(sock); + + sock_fd =3D socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC); + EXPECT_GE(sock_fd, 0); + if (sock_fd < 0) { + perror("socket()"); + err =3D sock_fd; + return; + } + + memset(&src_addr, 0, sizeof(src_addr)); + src_addr.nl_family =3D AF_NETLINK; + src_addr.nl_pid =3D getpid(); + + err =3D bind(sock_fd, (struct sockaddr *)&src_addr, sizeof(src_addr)); + EXPECT_EQ(err, 0); + if (err < 0) { + perror("bind()"); + close(sock_fd); + return; + } + + memset(&dest_addr, 0, sizeof(dest_addr)); + dest_addr.nl_family =3D AF_NETLINK; + dest_addr.nl_pid =3D 0; + dest_addr.nl_groups =3D 0; + + err =3D connect(sock_fd, (struct sockaddr *)&dest_addr, + sizeof(dest_addr)); + EXPECT_EQ(err, 0); + if (err < 0) { + perror("connect()"); + close(sock_fd); + return; + } + + close(sock_fd); +} + +/** + * TEST(netfilter_unbind_grp) - Validates Netlink group membership bind/un= bind operations + * + * Tests the NETLINK_ADD_MEMBERSHIP and NETLINK_DROP_MEMBERSHIP socket opt= ions + * using NETLINK_NETFILTER protocol which implements bind/unbind callbacks. + * + * Test Methodology: + * 1. Creates NETLINK_NETFILTER socket (requires root privileges) + * 2. Exercises group membership operations: + * - Adds membership to NFNLGRP_NFTABLES (group 3) + * - Adds membership to NFNLGRP_NFTRACE (group 4) + * - Drops membership from group 3 + * - Re-adds membership to group 3 + * 3. Completes socket lifecycle: + * - Binds socket to process PID + * - Connects to kernel (pid 0) + * - Closes socket + * + * Key Validations: + * - Successful group membership operations + * - Proper bind/unbind callback execution + * - Socket option error handling + * - Root privilege enforcement + * - Socket cleanup + * + * Expected Behavior: + * - All membership operations should succeed (return 0) + * - Bind/connect operations should complete successfully + * - Non-root execution should skip test gracefully + * + * Protocol Selection Rationale: + * - NETLINK_NETFILTER specifically implements .bind/.unbind callbacks (in= netlink_kernel_cfg) + * - Other Netlink protocols may not support these operations + * - Provides concrete test case for callback functionality + * + * Note: + * - Requires root privileges for group operations + * - Tests both single and multiple group scenarios + * - Verifies re-adding previously dropped groups + */ + +TEST(netfilter_unbind_grp) +{ + int sock_fd; + struct sockaddr_nl src_addr, dest_addr; + int err; + int group_3, group_4; + + printf("Running Test: trying to unbind groups from releasing socket...\n"= ); + + // Only root can NETLINK_ADD_MEMBERSHIP and NETLINK_DROP_MEMBERSHIP + if (geteuid()) { + SKIP(return, "test requires root"); + return; + } + + sock_fd =3D socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER); + ASSERT_GE(sock_fd, 0); + + memset(&src_addr, 0, sizeof(src_addr)); + src_addr.nl_family =3D AF_NETLINK; + src_addr.nl_pid =3D getpid(); + + group_3 =3D NFNLGRP_NFTABLES; + group_4 =3D NFNLGRP_NFTRACE; + + err =3D setsockopt(sock_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &group_3, + sizeof(group_3)); + EXPECT_EQ(err, 0); + + err =3D setsockopt(sock_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &group_4, + sizeof(group_4)); + EXPECT_EQ(err, 0); + + err =3D setsockopt(sock_fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP, + &group_3, sizeof(group_3)); + EXPECT_EQ(err, 0); + + err =3D setsockopt(sock_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &group_3, + sizeof(group_3)); + EXPECT_EQ(err, 0); + + err =3D bind(sock_fd, (struct sockaddr *)&src_addr, sizeof(src_addr)); + EXPECT_EQ(err, 0); + if (err < 0) { + perror("bind()"); + close(sock_fd); + return; + } + + memset(&dest_addr, 0, sizeof(dest_addr)); + dest_addr.nl_family =3D AF_NETLINK; + dest_addr.nl_pid =3D 0; + + err =3D connect(sock_fd, (struct sockaddr *)&dest_addr, + sizeof(dest_addr)); + EXPECT_EQ(err, 0); + if (err < 0) { + perror("connect()"); + close(sock_fd); + return; + } + + close(sock_fd); +} + +#define ITERATIONS 5000 + +void socket_worker(int iterations) +{ + srand(time(NULL) ^ getpid()); + + for (int i =3D 0; i < iterations; i++) { + int fd =3D socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC); + + if (fd < 0) { + perror("socket"); + continue; + } + + struct sockaddr_nl addr =3D { + .nl_family =3D AF_NETLINK, + .nl_pid =3D getpid(), + .nl_groups =3D 0, + }; + + if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + perror("bind"); + close(fd); + continue; + } + + // Short random delay + struct timespec ts =3D { .tv_sec =3D 0, .tv_nsec =3D rand() % 1000 }; + + nanosleep(&ts, NULL); + + close(fd); + } +} + +/** + * TEST(netlink_grab_table_check_wait) - Stress tests Netlink table lockin= g mechanism + * + * Creates a race condition scenario to validate Netlink table grabbing be= havior by: + * 1. Spawning two concurrent processes + * 2. Each process performs rapid socket create/bind/close cycles + * 3. Introduces random micro-delays to increase race condition probability + * 4. Verifies system stability under contention + * + * Test Methodology: + * 1. Process Creation: + * - Forks two child processes + * - Each executes socket_worker(ITERATIONS) + * + * 2. Worker Behavior (per iteration): + * - Creates NETLINK_GENERIC socket + * - Binds to process PID + * - Adds random 0-1=CE=BCs delay + * - Closes socket + * - Repeats 5000 times (ITERATIONS) + * + * 3. Validation: + * - Parent waits for both children + * - Checks for deadlocks/crashes + * - Verifies proper resource cleanup + * + * Key Stress Points: + * - Concurrent table access attempts + * - Rapid socket lifecycle churn + * - Randomized timing variations + * - Kernel table locking contention + * + * Expected Behavior: + * - System should remain stable throughout + * - No deadlocks or resource leaks + * - Proper serialization of table access + * - Correct error handling under contention + * + * Race Condition Verification: + * - Tests kernel's ability to handle: + * - Simultaneous socket operations + * - Table grabbing contention + * - Resource cleanup under load + * + * Note: + * - Uses 5000 iterations for significant stress + * - Micro-delays increase race probability + * - Tests both success and failure paths + * - Verifies proper process cleanup + */ + +TEST(netlink_grab_table_check_wait) +{ + int status; + + printf("Running Test: making one process waiting a grab for a netlink tab= le...\n"); + + pid_t p1 =3D fork(); + + if (p1 =3D=3D 0) { + socket_worker(ITERATIONS); + exit(0); + } + + pid_t p2 =3D fork(); + + if (p2 =3D=3D 0) { + socket_worker(ITERATIONS); + exit(0); + } + + waitpid(p1, &status, 0); + EXPECT_EQ(WEXITSTATUS(status), 0); + + waitpid(p2, &status, 0); + EXPECT_EQ(WEXITSTATUS(status), 0); +} + /** * TEST(capture_end) - Terminates Netlink traffic monitoring session * --=20 2.34.1 From nobody Thu Oct 2 18:21:35 2025 Received: from mail-wr1-f43.google.com (mail-wr1-f43.google.com [209.85.221.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0FC5E35A2AF for ; Fri, 12 Sep 2025 19:54:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.43 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757706858; cv=none; b=UNrMySsjUU7ru0JGp2ZPHA8bCiAghSNoxOsE8RyDN/szFp0M3126gjPlHjPggdRMo55CySmGrlmDVTNiyU5AOHB9Wu1p+7MpFtY37Fvu1lck53hh9jVzBNBNlTk3lC7ww+aCgr1EvKbIsYwTbDyQf9y5zWxFMBaePh84MX7RGhI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757706858; c=relaxed/simple; bh=icbkvjvQJUFVCkaCJXhVHTgOSqoKQBetWKx3gQY2/kQ=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=ig4kase4jdaTMgLpCaCS/dBY3JmOH6nHlLe9CUw41u0XCmapo5PH4bYNP/77OyCdySKtjmccx+COQwjOEQrdP89ZDTKgZInEXNr4GnXj29e2h6xt81YHlVCP5qgFrgNWUj7gqBjZLNjB42bYBVGWzkbWzvVlhAgBFdJxsEgBsUc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=Nfp89k+a; arc=none smtp.client-ip=209.85.221.43 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Nfp89k+a" Received: by mail-wr1-f43.google.com with SMTP id ffacd0b85a97d-3dad6252eacso1016463f8f.1 for ; Fri, 12 Sep 2025 12:54:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1757706854; x=1758311654; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=Fb9o+yLyjF+OaI0yOxAbCTZnd+38YkRAXuvGtFeqK84=; b=Nfp89k+az3mXppfv9w5wgN+4jCy1oi6QTALBueEqIjMUhJNjUrajkNJwFZ+uOyKGYi C4L0hSz4pPnDNyg/wqofjGGh1SdSEIOZFrgpjTtu2z0pMGliR0lWfb4zCNeKnFw/V+Mo PEGR7w+Q7zN54Iw498IuN8UHuY6Go1clnf2PshtIkWHZeUrb8SlXQhLIY2ON5+E6o1p6 65V+NvUNgj78FCNpgtM2veRU3OKtgPKnSiEafjilUmakXuArzBf/G9Isc1C0T+mEUoLh h6FEcKTabTdiWAeVekhMJdzria00VWRuIY8nasVnLcfSdYp/Aw4qRjGKAiXkhkvWI/Lw Si+Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1757706854; x=1758311654; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Fb9o+yLyjF+OaI0yOxAbCTZnd+38YkRAXuvGtFeqK84=; b=ZG+EqW27L3YRo7Id7OJqPewOLOY5ydPYLsGOsGT9Fbs5y9dmSPDfEJ8dmxMwSDIcBv j3Dq7pG4D6RuqmZfDOOXf67N7C027RGEpltpPgX/U8HGtSHPxdsWpjM0IRP0fdy02Lu2 5V0jopWEs3M5tYKwkJ5FUg2w+dNOz9CvQI1VkW9eUNo1KqNJFpanQwaRSsZdjbUYtg9N 1dWhThn/171mxvQGM2X8WkpsEhz7A+kaRQv0jx2XaTXaSRTNmP0JxEMvPi+Hzhx7/LBV tEEMWvflpzDrVEhZ3m8VPRyRUlBwvCy6U7O5+cvandk5A1a8YoxAVzTu50jPQ6GLkIT+ uSbA== X-Forwarded-Encrypted: i=1; AJvYcCWHEAXpE6iUe42CArJC9rN1/wLoHAh0s/83WjAhCbMMflzrmvnfuAlz8UEHh98MittC7Fh55YZuW5rmiAg=@vger.kernel.org X-Gm-Message-State: AOJu0YwS0yUYeeOpdD9N3eMPPhsJVw7cecxqaeDR/YCR6eXtrqmTR4fq dj63EN+8DT51kIaoz3NfrVtzhBhlx+eh4cN+GKgBr/NSYAM5gpQeHXzM X-Gm-Gg: ASbGncvvcvnvGan0qZPiABwCdl4Vk74NVBhn8OrlCz8MpB5pq0Laclg+bPFw8cl2hOD 3xaLxlwzCDPcwyW2JB+TPlfdoMVUFtoTYU12QPScsORxzQAVtrGJhniE5T+btpDCLW+tk5Fq8NZ CwE0RpTfubuk7TiZpW3W0Nc48X/79xaDXl8InmF3VRacA+2rcH7+l+PmD3/BJfnlSBlF/ijIHF6 XV3QQn/DnptpVJ4h+IK3wSEi4hHJGz4qGAj1g+6Z2cGS5nxmctJcgJ38fYilX8X2zNm/atAzkZg 9LQBUi/H/sa/aej0sNcZuqNp6Nz2jaiBXtSl4hW9DEEUs5pql6aNpOxxjU8zYa1WvqWWgHtmYQG D3SulVkTQJHYhWw0m6y3P8TvJ6aMWtdMHg/eUiy+FykRKi3vJwJwWtKHHvPTHug== X-Google-Smtp-Source: AGHT+IGDemjaEgtgOCoyvvb4Rw0Ry/Drus7N9V4sjIQEOXHnP0EXYeoSrzatSrGttoH5W/PqCe+s8g== X-Received: by 2002:a05:6000:4023:b0:3c9:3f46:70eb with SMTP id ffacd0b85a97d-3e7659f3b84mr3972483f8f.52.1757706854322; Fri, 12 Sep 2025 12:54:14 -0700 (PDT) Received: from yanesskka.. (node-188-187-35-212.domolink.tula.net. [212.35.187.188]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45e017bfd14sm74650375e9.21.2025.09.12.12.54.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 12 Sep 2025 12:54:13 -0700 (PDT) From: Yana Bashlykova To: "David S. Miller" Cc: Yana Bashlykova , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Shuah Khan , netdev@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, lvc-project@linuxtesting.org Subject: [PATCH 6.1 15/15] selftests: net: genetlink: fix expectation for large family resolution Date: Fri, 12 Sep 2025 22:53:38 +0300 Message-Id: <20250912195339.20635-16-yana2bsh@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250912195339.20635-1-yana2bsh@gmail.com> References: <20250912195339.20635-1-yana2bsh@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Correctly expect standard genl_ctrl_resolve() to fail for large families with many multicast groups. While kernel handles large families correctly, libnl's resolution fails due to message fragmentation: - Responses exceed single message size (~32KB) - Kernel fragments across multiple messages - genl_ctrl_resolve() only processes first fragment - Returns ENOMSG instead of family ID Custom my_genl_ctrl_resolve() handles fragmentation correctly via dump mechanism. Change EXPECT_TRUE(no_family_id > 0) to EXPECT_TRUE(no_family_id= < 0) to match actual behavior. Signed-off-by: Yana Bashlykova --- tools/testing/selftests/net/genetlink.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/net/genetlink.c b/tools/testing/selfte= sts/net/genetlink.c index a166f2c474b4..8a394991fe32 100644 --- a/tools/testing/selftests/net/genetlink.c +++ b/tools/testing/selftests/net/genetlink.c @@ -437,6 +437,7 @@ int validate_cb_ctrl(struct nl_msg *msg, void *arg) return NL_OK; =20 case CTRL_CMD_GETPOLICY: + ; struct ctrl_policy *exp =3D &data_ctrl->expected_policy->policy[elem]; if (attrs[CTRL_ATTR_FAMILY_ID]) { @@ -1485,7 +1486,7 @@ TEST(genl_ctrl_policy) * * Verification: * 1. Custom resolver returns valid ID (> 0) - * 2. Standard resolver either fails or succeeds (platform-dependent) + * 2. Standard resolver fails */ =20 TEST(resolve_large_family_id) @@ -1500,7 +1501,7 @@ TEST(resolve_large_family_id) /* Test standard resolver (may fail) */ no_family_id =3D genl_ctrl_resolve(socket_alloc_and_conn(), LARGE_GENL_FAMILY_NAME); - EXPECT_TRUE(no_family_id > 0); + EXPECT_TRUE(no_family_id < 0); } =20 /** --=20 2.34.1