DPDK patches and discussions
 help / color / mirror / Atom feed
* [PATCH] app/crypto-perf: support TLS record
@ 2024-01-24  6:49 Akhil Goyal
  2024-03-01  5:20 ` Anoob Joseph
  0 siblings, 1 reply; 3+ messages in thread
From: Akhil Goyal @ 2024-01-24  6:49 UTC (permalink / raw)
  To: dev
  Cc: ciara.power, fanzhang.oss, kai.ji, pablo.de.lara.guarch,
	hemant.agrawal, matan, g.singh, ruifeng.wang, anoobj,
	radu.nicolau, Akhil Goyal

Added support for latency and throughput measurement of
TLS and DTLS security ops.

Signed-off-by: Akhil Goyal <gakhil@marvell.com>
---
 app/test-crypto-perf/cperf_ops.c             | 144 +++++++++++++++++++
 app/test-crypto-perf/cperf_options.h         |   5 +-
 app/test-crypto-perf/cperf_options_parsing.c |  60 +++++++-
 app/test-crypto-perf/cperf_test_latency.c    |   1 +
 app/test-crypto-perf/cperf_test_throughput.c |   1 +
 app/test-crypto-perf/cperf_test_vectors.c    |   4 +-
 app/test-crypto-perf/cperf_test_verify.c     |   1 +
 app/test-crypto-perf/main.c                  |   4 +-
 doc/guides/tools/cryptoperf.rst              |   6 +
 9 files changed, 216 insertions(+), 10 deletions(-)

diff --git a/app/test-crypto-perf/cperf_ops.c b/app/test-crypto-perf/cperf_ops.c
index 84945d1313..d3fd115bc0 100644
--- a/app/test-crypto-perf/cperf_ops.c
+++ b/app/test-crypto-perf/cperf_ops.c
@@ -175,6 +175,42 @@ cperf_set_ops_security_ipsec(struct rte_crypto_op **ops,
 	*tsc_start += tsc_end_temp - tsc_start_temp;
 }
 
+static void
+cperf_set_ops_security_tls(struct rte_crypto_op **ops,
+		uint32_t src_buf_offset __rte_unused,
+		uint32_t dst_buf_offset __rte_unused,
+		uint16_t nb_ops, void *sess,
+		const struct cperf_options *options,
+		const struct cperf_test_vector *test_vector,
+		uint16_t iv_offset __rte_unused, uint32_t *imix_idx,
+		uint64_t *tsc_start)
+{
+	const uint32_t test_buffer_size = options->test_buffer_size;
+	const uint32_t headroom_sz = options->headroom_sz;
+	const uint32_t segment_sz = options->segment_sz;
+	uint16_t i = 0;
+
+	RTE_SET_USED(imix_idx);
+	RTE_SET_USED(tsc_start);
+	RTE_SET_USED(test_vector);
+
+	for (i = 0; i < nb_ops; i++) {
+		struct rte_crypto_sym_op *sym_op = ops[i]->sym;
+		struct rte_mbuf *m = sym_op->m_src;
+
+		ops[i]->status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
+		ops[i]->param1.tls_record.content_type = 0x17;
+		rte_security_attach_session(ops[i], sess);
+		sym_op->m_src = (struct rte_mbuf *)((uint8_t *)ops[i] + src_buf_offset);
+
+		m->data_off = headroom_sz;
+		m->buf_len = segment_sz;
+		m->data_len = test_buffer_size;
+		m->pkt_len = test_buffer_size;
+
+		sym_op->m_dst = NULL;
+	}
+}
 #endif
 
 static void
@@ -755,6 +791,106 @@ create_ipsec_session(struct rte_mempool *sess_mp,
 	return (void *)rte_security_session_create(ctx, &sess_conf, sess_mp);
 }
 
+static void *
+create_tls_session(struct rte_mempool *sess_mp,
+		uint8_t dev_id,
+		const struct cperf_options *options,
+		const struct cperf_test_vector *test_vector,
+		uint16_t iv_offset)
+{
+	struct rte_crypto_sym_xform auth_xform = {0};
+	struct rte_crypto_sym_xform *crypto_xform;
+	struct rte_crypto_sym_xform xform = {0};
+
+	if (options->aead_algo != 0) {
+		/* Setup AEAD Parameters */
+		xform.type = RTE_CRYPTO_SYM_XFORM_AEAD;
+		xform.next = NULL;
+		xform.aead.algo = options->aead_algo;
+		xform.aead.op = options->aead_op;
+		xform.aead.iv.offset = iv_offset;
+		xform.aead.key.data = test_vector->aead_key.data;
+		xform.aead.key.length = test_vector->aead_key.length;
+		xform.aead.iv.length = test_vector->aead_iv.length;
+		xform.aead.digest_length = options->digest_sz;
+		xform.aead.aad_length = options->aead_aad_sz;
+		crypto_xform = &xform;
+	} else if (options->cipher_algo != 0 && options->auth_algo != 0) {
+		/* Setup Cipher Parameters */
+		xform.type = RTE_CRYPTO_SYM_XFORM_CIPHER;
+		xform.cipher.algo = options->cipher_algo;
+		xform.cipher.op = options->cipher_op;
+		xform.cipher.iv.offset = iv_offset;
+		xform.cipher.iv.length = test_vector->cipher_iv.length;
+		/* cipher different than null */
+		if (options->cipher_algo != RTE_CRYPTO_CIPHER_NULL) {
+			xform.cipher.key.data = test_vector->cipher_key.data;
+			xform.cipher.key.length = test_vector->cipher_key.length;
+		} else {
+			xform.cipher.key.data = NULL;
+			xform.cipher.key.length = 0;
+		}
+
+		/* Setup Auth Parameters */
+		auth_xform.type = RTE_CRYPTO_SYM_XFORM_AUTH;
+		auth_xform.auth.algo = options->auth_algo;
+		auth_xform.auth.op = options->auth_op;
+		auth_xform.auth.iv.offset = iv_offset + xform.cipher.iv.length;
+		/* auth different than null */
+		if (options->auth_algo != RTE_CRYPTO_AUTH_NULL) {
+			auth_xform.auth.digest_length = options->digest_sz;
+			auth_xform.auth.key.length = test_vector->auth_key.length;
+			auth_xform.auth.key.data = test_vector->auth_key.data;
+			auth_xform.auth.iv.length = test_vector->auth_iv.length;
+		} else {
+			auth_xform.auth.digest_length = 0;
+			auth_xform.auth.key.length = 0;
+			auth_xform.auth.key.data = NULL;
+			auth_xform.auth.iv.length = 0;
+		}
+
+		if (options->is_outbound) {
+			/* Currently supporting AUTH then Encrypt mode only for TLS. */
+			crypto_xform = &auth_xform;
+			auth_xform.next = &xform;
+			xform.next = NULL;
+		} else {
+			crypto_xform = &xform;
+			xform.next = &auth_xform;
+			auth_xform.next = NULL;
+		}
+	} else {
+		return NULL;
+	}
+
+	struct rte_security_tls_record_sess_options opts = {
+		.iv_gen_disable = 0,
+		.extra_padding_enable = 0,
+	};
+	struct rte_security_session_conf sess_conf = {
+		.action_type = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
+		.protocol = RTE_SECURITY_PROTOCOL_TLS_RECORD,
+		{.tls_record = {
+			.ver = RTE_SECURITY_VERSION_TLS_1_2,
+			.options = opts,
+		} },
+		.userdata = NULL,
+		.crypto_xform = crypto_xform,
+	};
+	if (options->tls_version)
+		sess_conf.tls_record.ver = options->tls_version;
+
+	if (options->is_outbound)
+		sess_conf.tls_record.type = RTE_SECURITY_TLS_SESS_TYPE_WRITE;
+	else
+		sess_conf.tls_record.type = RTE_SECURITY_TLS_SESS_TYPE_READ;
+
+	void *ctx = rte_cryptodev_get_sec_ctx(dev_id);
+
+	/* Create security session */
+	return (void *)rte_security_session_create(ctx, &sess_conf, sess_mp);
+}
+
 static void *
 cperf_create_session(struct rte_mempool *sess_mp,
 	uint8_t dev_id,
@@ -863,6 +999,11 @@ cperf_create_session(struct rte_mempool *sess_mp,
 				options, test_vector, iv_offset);
 	}
 
+	if (options->op_type == CPERF_TLS) {
+		return create_tls_session(sess_mp, dev_id,
+				options, test_vector, iv_offset);
+	}
+
 	if (options->op_type == CPERF_DOCSIS) {
 		enum rte_security_docsis_direction direction;
 
@@ -1089,6 +1230,9 @@ cperf_get_op_functions(const struct cperf_options *options,
 	case CPERF_IPSEC:
 		op_fns->populate_ops = cperf_set_ops_security_ipsec;
 		break;
+	case CPERF_TLS:
+		op_fns->populate_ops = cperf_set_ops_security_tls;
+		break;
 #endif
 	default:
 		return -1;
diff --git a/app/test-crypto-perf/cperf_options.h b/app/test-crypto-perf/cperf_options.h
index 6966e0b286..be36c70be1 100644
--- a/app/test-crypto-perf/cperf_options.h
+++ b/app/test-crypto-perf/cperf_options.h
@@ -55,6 +55,7 @@
 #define CPERF_PDCP_SES_HFN_EN	("pdcp-ses-hfn-en")
 #define PDCP_DEFAULT_HFN	0x1
 #define CPERF_DOCSIS_HDR_SZ	("docsis-hdr-sz")
+#define CPERF_TLS_VERSION	("tls-version")
 #endif
 
 #define CPERF_CSV		("csv-friendly")
@@ -83,7 +84,8 @@ enum cperf_op_type {
 	CPERF_PDCP,
 	CPERF_DOCSIS,
 	CPERF_IPSEC,
-	CPERF_ASYM_MODEX
+	CPERF_ASYM_MODEX,
+	CPERF_TLS,
 };
 
 extern const char *cperf_op_type_strs[];
@@ -134,6 +136,7 @@ struct cperf_options {
 	uint16_t pdcp_sdap;
 	enum rte_security_pdcp_domain pdcp_domain;
 	uint16_t docsis_hdr_sz;
+	enum rte_security_tls_version tls_version;
 #endif
 	char device_type[RTE_CRYPTODEV_NAME_MAX_LEN];
 	enum cperf_op_type op_type;
diff --git a/app/test-crypto-perf/cperf_options_parsing.c b/app/test-crypto-perf/cperf_options_parsing.c
index 75afedc7fd..cba6d6bc42 100644
--- a/app/test-crypto-perf/cperf_options_parsing.c
+++ b/app/test-crypto-perf/cperf_options_parsing.c
@@ -36,8 +36,8 @@ usage(char *progname)
 		" --segment-sz N: set the size of the segment to use\n"
 		" --desc-nb N: set number of descriptors for each crypto device\n"
 		" --devtype TYPE: set crypto device type to use\n"
-		" --optype cipher-only / auth-only / cipher-then-auth /\n"
-		"           auth-then-cipher / aead : set operation type\n"
+		" --optype cipher-only / auth-only / cipher-then-auth / auth-then-cipher /\n"
+		"        aead / pdcp / docsis / ipsec / modex / tls-record : set operation type\n"
 		" --sessionless: enable session-less crypto operations\n"
 		" --out-of-place: enable out-of-place crypto operations\n"
 		" --test-file NAME: set the test vector file path\n"
@@ -67,6 +67,7 @@ usage(char *progname)
 		" --pdcp-ses-hfn-en: enable session based fixed HFN\n"
 		" --enable-sdap: enable sdap\n"
 		" --docsis-hdr-sz: set DOCSIS header size\n"
+		" --tls-version VER: set TLS VERSION <TLS1.2/TLS1.3/DTLS1.2>\n"
 #endif
 		" -h: prints this help\n",
 		progname);
@@ -480,7 +481,11 @@ parse_op_type(struct cperf_options *opts, const char *arg)
 		{
 			cperf_op_type_strs[CPERF_ASYM_MODEX],
 			CPERF_ASYM_MODEX
-		}
+		},
+		{
+			cperf_op_type_strs[CPERF_TLS],
+			CPERF_TLS
+		},
 	};
 
 	int id = get_str_key_id_mapping(optype_namemap,
@@ -732,6 +737,45 @@ parse_pdcp_domain(struct cperf_options *opts, const char *arg)
 	return 0;
 }
 
+const char *cperf_tls_version_strs[] = {
+	[RTE_SECURITY_VERSION_TLS_1_2] = "TLS1.2",
+	[RTE_SECURITY_VERSION_TLS_1_3] = "TLS1.3",
+	[RTE_SECURITY_VERSION_DTLS_1_2] = "DTLS1.2"
+};
+
+static int
+parse_tls_version(struct cperf_options *opts, const char *arg)
+{
+	struct name_id_map tls_version_namemap[] = {
+		{
+			cperf_tls_version_strs
+			[RTE_SECURITY_VERSION_TLS_1_2],
+			RTE_SECURITY_VERSION_TLS_1_2
+		},
+		{
+			cperf_tls_version_strs
+			[RTE_SECURITY_VERSION_TLS_1_3],
+			RTE_SECURITY_VERSION_TLS_1_3
+		},
+		{
+			cperf_tls_version_strs
+			[RTE_SECURITY_VERSION_DTLS_1_2],
+			RTE_SECURITY_VERSION_DTLS_1_2
+		},
+	};
+
+	int id = get_str_key_id_mapping(tls_version_namemap,
+			RTE_DIM(tls_version_namemap), arg);
+	if (id < 0) {
+		RTE_LOG(ERR, USER1, "invalid TLS version specified\n");
+		return -1;
+	}
+
+	opts->tls_version = (enum rte_security_tls_version)id;
+
+	return 0;
+}
+
 static int
 parse_pdcp_ses_hfn_en(struct cperf_options *opts, const char *arg __rte_unused)
 {
@@ -893,6 +937,7 @@ static struct option lgopts[] = {
 	{ CPERF_PDCP_SES_HFN_EN, no_argument, 0, 0 },
 	{ CPERF_ENABLE_SDAP, no_argument, 0, 0 },
 	{ CPERF_DOCSIS_HDR_SZ, required_argument, 0, 0 },
+	{ CPERF_TLS_VERSION, required_argument, 0, 0 },
 #endif
 	{ CPERF_CSV, no_argument, 0, 0},
 
@@ -1010,6 +1055,7 @@ cperf_opts_parse_long(int opt_idx, struct cperf_options *opts)
 		{ CPERF_PDCP_SES_HFN_EN,	parse_pdcp_ses_hfn_en },
 		{ CPERF_ENABLE_SDAP,	parse_enable_sdap },
 		{ CPERF_DOCSIS_HDR_SZ,	parse_docsis_hdr_sz },
+		{ CPERF_TLS_VERSION,	parse_tls_version },
 #endif
 		{ CPERF_CSV,		parse_csv_friendly},
 		{ CPERF_PMDCC_DELAY_MS,	parse_pmd_cyclecount_delay_ms},
@@ -1190,12 +1236,12 @@ cperf_options_check(struct cperf_options *options)
 	if (options->segment_sz == 0) {
 		options->segment_sz = options->max_buffer_size +
 				options->digest_sz;
-		/* In IPsec operation, packet length will be increased
+		/* In IPsec and TLS operation, packet length will be increased
 		 * by some bytes depend upon the algorithm, so increasing
 		 * the segment size by headroom to cover most of
 		 * the scenarios.
 		 */
-		if (options->op_type == CPERF_IPSEC)
+		if (options->op_type == CPERF_IPSEC || options->op_type == CPERF_TLS)
 			options->segment_sz += RTE_PKTMBUF_HEADROOM;
 	}
 
@@ -1328,7 +1374,7 @@ cperf_options_check(struct cperf_options *options)
 			return -EINVAL;
 	}
 
-	if (options->op_type == CPERF_IPSEC) {
+	if (options->op_type == CPERF_IPSEC || options->op_type == CPERF_TLS) {
 		if (options->aead_algo) {
 			if (options->aead_op == RTE_CRYPTO_AEAD_OP_ENCRYPT)
 				options->is_outbound = 1;
@@ -1356,6 +1402,8 @@ cperf_options_dump(struct cperf_options *opts)
 	printf("#\n");
 	printf("# cperf test: %s\n", cperf_test_type_strs[opts->test]);
 	printf("#\n");
+	printf("# cperf operation type: %s\n", cperf_op_type_strs[opts->op_type]);
+	printf("#\n");
 	printf("# size of crypto op / mbuf pool: %u\n", opts->pool_sz);
 	printf("# total number of ops: %u\n", opts->total_ops);
 	if (opts->inc_buffer_size != 0) {
diff --git a/app/test-crypto-perf/cperf_test_latency.c b/app/test-crypto-perf/cperf_test_latency.c
index 484bc9eb4e..99b7d7c678 100644
--- a/app/test-crypto-perf/cperf_test_latency.c
+++ b/app/test-crypto-perf/cperf_test_latency.c
@@ -52,6 +52,7 @@ cperf_latency_test_free(struct cperf_latency_ctx *ctx)
 #ifdef RTE_LIB_SECURITY
 		else if (ctx->options->op_type == CPERF_PDCP ||
 			 ctx->options->op_type == CPERF_DOCSIS ||
+			 ctx->options->op_type == CPERF_TLS ||
 			 ctx->options->op_type == CPERF_IPSEC) {
 			void *sec_ctx = rte_cryptodev_get_sec_ctx(ctx->dev_id);
 			rte_security_session_destroy(sec_ctx, ctx->sess);
diff --git a/app/test-crypto-perf/cperf_test_throughput.c b/app/test-crypto-perf/cperf_test_throughput.c
index f8f8bd717f..e3d266d7a4 100644
--- a/app/test-crypto-perf/cperf_test_throughput.c
+++ b/app/test-crypto-perf/cperf_test_throughput.c
@@ -43,6 +43,7 @@ cperf_throughput_test_free(struct cperf_throughput_ctx *ctx)
 #ifdef RTE_LIB_SECURITY
 		else if (ctx->options->op_type == CPERF_PDCP ||
 			 ctx->options->op_type == CPERF_DOCSIS ||
+			 ctx->options->op_type == CPERF_TLS ||
 			 ctx->options->op_type == CPERF_IPSEC) {
 			void *sec_ctx = rte_cryptodev_get_sec_ctx(ctx->dev_id);
 
diff --git a/app/test-crypto-perf/cperf_test_vectors.c b/app/test-crypto-perf/cperf_test_vectors.c
index 5cd7a229b8..3c35eea460 100644
--- a/app/test-crypto-perf/cperf_test_vectors.c
+++ b/app/test-crypto-perf/cperf_test_vectors.c
@@ -660,7 +660,7 @@ cperf_test_vector_get_dummy(struct cperf_options *options)
 		t_vec->modex.elen = options->modex_data->exponent.len;
 	}
 
-	if (options->op_type ==	CPERF_PDCP ||
+	if (options->op_type ==	CPERF_PDCP || options->op_type == CPERF_TLS ||
 			options->op_type == CPERF_IPSEC) {
 		if (options->cipher_algo == RTE_CRYPTO_CIPHER_NULL) {
 			t_vec->cipher_key.length = 0;
@@ -795,7 +795,7 @@ cperf_test_vector_get_dummy(struct cperf_options *options)
 		t_vec->auth_iv.length = options->auth_iv_sz;
 	}
 
-	if (options->op_type == CPERF_AEAD ||
+	if (options->op_type == CPERF_AEAD || options->op_type == CPERF_TLS ||
 			options->op_type == CPERF_IPSEC) {
 		t_vec->aead_key.length = options->aead_key_sz;
 		t_vec->aead_key.data = aead_key;
diff --git a/app/test-crypto-perf/cperf_test_verify.c b/app/test-crypto-perf/cperf_test_verify.c
index a6c0ffe813..a57841dafb 100644
--- a/app/test-crypto-perf/cperf_test_verify.c
+++ b/app/test-crypto-perf/cperf_test_verify.c
@@ -47,6 +47,7 @@ cperf_verify_test_free(struct cperf_verify_ctx *ctx)
 #ifdef RTE_LIB_SECURITY
 		else if (ctx->options->op_type == CPERF_PDCP ||
 			 ctx->options->op_type == CPERF_DOCSIS ||
+			 ctx->options->op_type == CPERF_TLS ||
 			 ctx->options->op_type == CPERF_IPSEC) {
 			void *sec_ctx = rte_cryptodev_get_sec_ctx(ctx->dev_id);
 
diff --git a/app/test-crypto-perf/main.c b/app/test-crypto-perf/main.c
index 6a2e5762a3..40c0b4b54f 100644
--- a/app/test-crypto-perf/main.c
+++ b/app/test-crypto-perf/main.c
@@ -43,7 +43,8 @@ const char *cperf_op_type_strs[] = {
 	[CPERF_PDCP] = "pdcp",
 	[CPERF_DOCSIS] = "docsis",
 	[CPERF_IPSEC] = "ipsec",
-	[CPERF_ASYM_MODEX] = "modex"
+	[CPERF_ASYM_MODEX] = "modex",
+	[CPERF_TLS] = "tls-record"
 };
 
 const struct cperf_test cperf_testmap[] = {
@@ -236,6 +237,7 @@ cperf_initialize_cryptodev(struct cperf_options *opts, uint8_t *enabled_cdevs)
 		case CPERF_PDCP:
 		case CPERF_DOCSIS:
 		case CPERF_IPSEC:
+		case CPERF_TLS:
 			/* Fall through */
 		default:
 			conf.ff_disable |= RTE_CRYPTODEV_FF_ASYMMETRIC_CRYPTO;
diff --git a/doc/guides/tools/cryptoperf.rst b/doc/guides/tools/cryptoperf.rst
index f30784674d..facf412799 100644
--- a/doc/guides/tools/cryptoperf.rst
+++ b/doc/guides/tools/cryptoperf.rst
@@ -175,6 +175,8 @@ The following are the application command-line options:
            pdcp
            docsis
            modex
+           ipsec
+           tls-record
 
         For GCM/CCM algorithms you should use aead flag.
 
@@ -340,6 +342,10 @@ The following are the application command-line options:
         Set modex length for asymmetric crypto perf test.
         Supported lengths are 60, 128, 255, 448. Default length is 128.
 
+* ``--tls-version <TLS1.2/TLS1.3/DTLS1.2>``
+
+        Set TLS/DTLS protocol version for perf test (default is TLS1.2).
+
 Test Vector File
 ~~~~~~~~~~~~~~~~
 
-- 
2.25.1


^ permalink raw reply	[flat|nested] 3+ messages in thread

* RE: [PATCH] app/crypto-perf: support TLS record
  2024-01-24  6:49 [PATCH] app/crypto-perf: support TLS record Akhil Goyal
@ 2024-03-01  5:20 ` Anoob Joseph
  2024-03-01  6:18   ` Akhil Goyal
  0 siblings, 1 reply; 3+ messages in thread
From: Anoob Joseph @ 2024-03-01  5:20 UTC (permalink / raw)
  To: Akhil Goyal, dev
  Cc: ciara.power, fanzhang.oss, kai.ji, pablo.de.lara.guarch,
	hemant.agrawal, matan, g.singh, ruifeng.wang, radu.nicolau,
	Akhil Goyal

> 
> Added support for latency and throughput measurement of TLS and DTLS
> security ops.
> 
> Signed-off-by: Akhil Goyal <gakhil@marvell.com>

Acked-by: Anoob Joseph <anoobj@marvell.com>



^ permalink raw reply	[flat|nested] 3+ messages in thread

* RE: [PATCH] app/crypto-perf: support TLS record
  2024-03-01  5:20 ` Anoob Joseph
@ 2024-03-01  6:18   ` Akhil Goyal
  0 siblings, 0 replies; 3+ messages in thread
From: Akhil Goyal @ 2024-03-01  6:18 UTC (permalink / raw)
  To: Anoob Joseph, dev
  Cc: ciara.power, fanzhang.oss, kai.ji, pablo.de.lara.guarch,
	hemant.agrawal, matan, g.singh, ruifeng.wang, radu.nicolau

> Subject: RE: [PATCH] app/crypto-perf: support TLS record
> 
> >
> > Added support for latency and throughput measurement of TLS and DTLS
> > security ops.
> >
> > Signed-off-by: Akhil Goyal <gakhil@marvell.com>
> 
> Acked-by: Anoob Joseph <anoobj@marvell.com>
> 
Applied to dpdk-next-crypto

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2024-03-01  6:18 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-01-24  6:49 [PATCH] app/crypto-perf: support TLS record Akhil Goyal
2024-03-01  5:20 ` Anoob Joseph
2024-03-01  6:18   ` Akhil Goyal

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).