From nobody Thu Oct 2 19:38:18 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