xref: /dpdk/lib/port/rte_swx_port_fd.c (revision 72b452c5f2599f970f47fd17d3e8e5d60bfebe7a)
199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson  * Copyright(c) 2021 Intel Corporation
399a2dd95SBruce Richardson  */
499a2dd95SBruce Richardson #include <string.h>
599a2dd95SBruce Richardson #include <stdint.h>
6*72b452c5SDmitry Kozlyuk #include <stdlib.h>
799a2dd95SBruce Richardson #include <unistd.h>
899a2dd95SBruce Richardson 
999a2dd95SBruce Richardson #include <rte_mbuf.h>
1099a2dd95SBruce Richardson #include <rte_hexdump.h>
1199a2dd95SBruce Richardson 
1299a2dd95SBruce Richardson #include "rte_swx_port_fd.h"
1399a2dd95SBruce Richardson 
1499a2dd95SBruce Richardson #ifndef TRACE_LEVEL
1599a2dd95SBruce Richardson #define TRACE_LEVEL 0
1699a2dd95SBruce Richardson #endif
1799a2dd95SBruce Richardson 
1899a2dd95SBruce Richardson #if TRACE_LEVEL
1999a2dd95SBruce Richardson #define TRACE(...) printf(__VA_ARGS__)
2099a2dd95SBruce Richardson #else
2199a2dd95SBruce Richardson #define TRACE(...)
2299a2dd95SBruce Richardson #endif
2399a2dd95SBruce Richardson 
2499a2dd95SBruce Richardson /*
2599a2dd95SBruce Richardson  * FD Reader
2699a2dd95SBruce Richardson  */
2799a2dd95SBruce Richardson struct reader {
2899a2dd95SBruce Richardson 	struct {
2999a2dd95SBruce Richardson 		int fd;
3099a2dd95SBruce Richardson 		uint32_t mtu;
3199a2dd95SBruce Richardson 		uint32_t burst_size;
3299a2dd95SBruce Richardson 		struct rte_mempool *mempool;
3399a2dd95SBruce Richardson 	} params;
3499a2dd95SBruce Richardson 
3599a2dd95SBruce Richardson 	struct rte_swx_port_in_stats stats;
3699a2dd95SBruce Richardson 	struct rte_mbuf **pkts;
3799a2dd95SBruce Richardson 	uint32_t n_pkts;
3899a2dd95SBruce Richardson 	uint32_t pos;
3999a2dd95SBruce Richardson };
4099a2dd95SBruce Richardson 
4199a2dd95SBruce Richardson static void *
reader_create(void * args)4299a2dd95SBruce Richardson reader_create(void *args)
4399a2dd95SBruce Richardson {
4499a2dd95SBruce Richardson 	struct rte_swx_port_fd_reader_params *conf = args;
4599a2dd95SBruce Richardson 	struct reader *p;
4699a2dd95SBruce Richardson 
4799a2dd95SBruce Richardson 	/* Check input parameters. */
4899a2dd95SBruce Richardson 	if (!conf || conf->fd < 0 || conf->mtu == 0 || !conf->mempool)
4999a2dd95SBruce Richardson 		return NULL;
5099a2dd95SBruce Richardson 
5199a2dd95SBruce Richardson 	/* Memory allocation. */
5299a2dd95SBruce Richardson 	p = calloc(1, sizeof(struct reader));
5399a2dd95SBruce Richardson 	if (!p)
5499a2dd95SBruce Richardson 		return NULL;
5599a2dd95SBruce Richardson 
5699a2dd95SBruce Richardson 	p->pkts = calloc(conf->burst_size, sizeof(struct rte_mbuf *));
5799a2dd95SBruce Richardson 	if (!p->pkts) {
5899a2dd95SBruce Richardson 		free(p);
5999a2dd95SBruce Richardson 		return NULL;
6099a2dd95SBruce Richardson 	}
6199a2dd95SBruce Richardson 
6299a2dd95SBruce Richardson 	/* Initialization. */
6399a2dd95SBruce Richardson 	p->params.fd = conf->fd;
6499a2dd95SBruce Richardson 	p->params.mtu = conf->mtu;
6599a2dd95SBruce Richardson 	p->params.burst_size = conf->burst_size;
6699a2dd95SBruce Richardson 	p->params.mempool = conf->mempool;
6799a2dd95SBruce Richardson 
6899a2dd95SBruce Richardson 	return p;
6999a2dd95SBruce Richardson }
7099a2dd95SBruce Richardson 
7199a2dd95SBruce Richardson static void
reader_free(void * port)7299a2dd95SBruce Richardson reader_free(void *port)
7399a2dd95SBruce Richardson {
7499a2dd95SBruce Richardson 	struct reader *p = port;
7599a2dd95SBruce Richardson 	uint32_t i;
7699a2dd95SBruce Richardson 
7799a2dd95SBruce Richardson 	if (!p)
7899a2dd95SBruce Richardson 		return;
7999a2dd95SBruce Richardson 
8099a2dd95SBruce Richardson 	for (i = 0; i < p->n_pkts; i++)
8199a2dd95SBruce Richardson 		rte_pktmbuf_free(p->pkts[i]);
8299a2dd95SBruce Richardson 
8399a2dd95SBruce Richardson 	free(p->pkts);
8499a2dd95SBruce Richardson 	free(p);
8599a2dd95SBruce Richardson }
8699a2dd95SBruce Richardson 
8799a2dd95SBruce Richardson static int
reader_pkt_rx(void * port,struct rte_swx_pkt * pkt)8899a2dd95SBruce Richardson reader_pkt_rx(void *port, struct rte_swx_pkt *pkt)
8999a2dd95SBruce Richardson {
9099a2dd95SBruce Richardson 	struct reader *p = port;
9199a2dd95SBruce Richardson 	struct rte_mbuf *m;
9299a2dd95SBruce Richardson 	void *pkt_data;
9399a2dd95SBruce Richardson 	ssize_t n_bytes;
9499a2dd95SBruce Richardson 	uint32_t i, j;
9599a2dd95SBruce Richardson 
9699a2dd95SBruce Richardson 	if (p->n_pkts == p->pos) {
9799a2dd95SBruce Richardson 		if (rte_pktmbuf_alloc_bulk(p->params.mempool, p->pkts, p->params.burst_size) != 0)
9899a2dd95SBruce Richardson 			return 0;
9999a2dd95SBruce Richardson 
10099a2dd95SBruce Richardson 		for (i = 0; i < p->params.burst_size; i++) {
10199a2dd95SBruce Richardson 			m = p->pkts[i];
10299a2dd95SBruce Richardson 			pkt_data = rte_pktmbuf_mtod(m, void *);
10399a2dd95SBruce Richardson 			n_bytes = read(p->params.fd, pkt_data, (size_t) p->params.mtu);
10499a2dd95SBruce Richardson 
10599a2dd95SBruce Richardson 			if (n_bytes <= 0)
10699a2dd95SBruce Richardson 				break;
10799a2dd95SBruce Richardson 
10899a2dd95SBruce Richardson 			m->data_len = n_bytes;
10999a2dd95SBruce Richardson 			m->pkt_len = n_bytes;
11099a2dd95SBruce Richardson 
11199a2dd95SBruce Richardson 			p->stats.n_pkts++;
11299a2dd95SBruce Richardson 			p->stats.n_bytes += n_bytes;
11399a2dd95SBruce Richardson 		}
11499a2dd95SBruce Richardson 
11599a2dd95SBruce Richardson 		for (j = i; j < p->params.burst_size; j++)
11699a2dd95SBruce Richardson 			rte_pktmbuf_free(p->pkts[j]);
11799a2dd95SBruce Richardson 
11899a2dd95SBruce Richardson 		p->n_pkts = i;
11999a2dd95SBruce Richardson 		p->pos = 0;
12099a2dd95SBruce Richardson 
12199a2dd95SBruce Richardson 		if (!p->n_pkts)
12299a2dd95SBruce Richardson 			return 0;
12399a2dd95SBruce Richardson 	}
12499a2dd95SBruce Richardson 
12599a2dd95SBruce Richardson 	m = p->pkts[p->pos++];
12699a2dd95SBruce Richardson 	pkt->handle = m;
12799a2dd95SBruce Richardson 	pkt->pkt = m->buf_addr;
12899a2dd95SBruce Richardson 	pkt->offset = m->data_off;
12999a2dd95SBruce Richardson 	pkt->length = m->pkt_len;
13099a2dd95SBruce Richardson 
13199a2dd95SBruce Richardson 	TRACE("[FD %u] Pkt %d (%u bytes at offset %u)\n",
13299a2dd95SBruce Richardson 		(uint32_t)p->params.fd,
13399a2dd95SBruce Richardson 		p->pos - 1,
13499a2dd95SBruce Richardson 		pkt->length,
13599a2dd95SBruce Richardson 		pkt->offset);
13699a2dd95SBruce Richardson 
13799a2dd95SBruce Richardson 	if (TRACE_LEVEL)
13899a2dd95SBruce Richardson 		rte_hexdump(stdout, NULL,
13999a2dd95SBruce Richardson 			&((uint8_t *)m->buf_addr)[m->data_off], m->data_len);
14099a2dd95SBruce Richardson 
14199a2dd95SBruce Richardson 	return 1;
14299a2dd95SBruce Richardson }
14399a2dd95SBruce Richardson 
14499a2dd95SBruce Richardson static void
reader_stats_read(void * port,struct rte_swx_port_in_stats * stats)14599a2dd95SBruce Richardson reader_stats_read(void *port, struct rte_swx_port_in_stats *stats)
14699a2dd95SBruce Richardson {
14799a2dd95SBruce Richardson 	struct reader *p = port;
14899a2dd95SBruce Richardson 
14999a2dd95SBruce Richardson 	memcpy(stats, &p->stats, sizeof(p->stats));
15099a2dd95SBruce Richardson }
15199a2dd95SBruce Richardson 
15299a2dd95SBruce Richardson /*
15399a2dd95SBruce Richardson  * FD Writer
15499a2dd95SBruce Richardson  */
15599a2dd95SBruce Richardson struct writer {
15699a2dd95SBruce Richardson 	struct {
15799a2dd95SBruce Richardson 		int fd;
15899a2dd95SBruce Richardson 		uint32_t mtu;
15999a2dd95SBruce Richardson 		uint32_t burst_size;
16099a2dd95SBruce Richardson 		struct rte_mempool *mempool;
16199a2dd95SBruce Richardson 	} params;
16299a2dd95SBruce Richardson 
16399a2dd95SBruce Richardson 	struct rte_swx_port_out_stats stats;
16499a2dd95SBruce Richardson 	struct rte_mbuf **pkts;
16599a2dd95SBruce Richardson 	uint32_t n_pkts;
16699a2dd95SBruce Richardson };
16799a2dd95SBruce Richardson 
16899a2dd95SBruce Richardson static void *
writer_create(void * args)16999a2dd95SBruce Richardson writer_create(void *args)
17099a2dd95SBruce Richardson {
17199a2dd95SBruce Richardson 	struct rte_swx_port_fd_writer_params *conf = args;
17299a2dd95SBruce Richardson 	struct writer *p;
17399a2dd95SBruce Richardson 
17499a2dd95SBruce Richardson 	/* Check input parameters. */
17599a2dd95SBruce Richardson 	if (!conf)
17699a2dd95SBruce Richardson 		return NULL;
17799a2dd95SBruce Richardson 
17899a2dd95SBruce Richardson 	/* Memory allocation. */
17999a2dd95SBruce Richardson 	p = calloc(1, sizeof(struct writer));
18099a2dd95SBruce Richardson 	if (!p)
18199a2dd95SBruce Richardson 		return NULL;
18299a2dd95SBruce Richardson 
18399a2dd95SBruce Richardson 
18499a2dd95SBruce Richardson 	p->pkts = calloc(conf->burst_size, sizeof(struct rte_mbuf *));
18599a2dd95SBruce Richardson 	if (!p->pkts) {
18699a2dd95SBruce Richardson 		free(p);
18799a2dd95SBruce Richardson 		return NULL;
18899a2dd95SBruce Richardson 	}
18999a2dd95SBruce Richardson 
19099a2dd95SBruce Richardson 	/* Initialization. */
19199a2dd95SBruce Richardson 	p->params.fd = conf->fd;
19299a2dd95SBruce Richardson 	p->params.burst_size = conf->burst_size;
19399a2dd95SBruce Richardson 
19499a2dd95SBruce Richardson 	return p;
19599a2dd95SBruce Richardson }
19699a2dd95SBruce Richardson 
19799a2dd95SBruce Richardson static void
__writer_flush(struct writer * p)19899a2dd95SBruce Richardson __writer_flush(struct writer *p)
19999a2dd95SBruce Richardson {
20099a2dd95SBruce Richardson 	struct rte_mbuf *pkt;
20199a2dd95SBruce Richardson 	void *pkt_data;
20299a2dd95SBruce Richardson 	size_t n_bytes;
20399a2dd95SBruce Richardson 	ssize_t ret;
20499a2dd95SBruce Richardson 	uint32_t i;
20599a2dd95SBruce Richardson 
20699a2dd95SBruce Richardson 	for (i = 0; i < p->n_pkts; i++) {
20799a2dd95SBruce Richardson 		pkt = p->pkts[i];
20899a2dd95SBruce Richardson 		pkt_data = rte_pktmbuf_mtod(pkt, void*);
20999a2dd95SBruce Richardson 		n_bytes = rte_pktmbuf_data_len(pkt);
21099a2dd95SBruce Richardson 
21199a2dd95SBruce Richardson 		ret = write(p->params.fd, pkt_data, n_bytes);
21299a2dd95SBruce Richardson 		if (ret < 0)
21399a2dd95SBruce Richardson 			break;
21499a2dd95SBruce Richardson 	}
21599a2dd95SBruce Richardson 
21699a2dd95SBruce Richardson 	TRACE("[FD %u] %u packets out\n",
21799a2dd95SBruce Richardson 		(uint32_t)p->params.fd,
21899a2dd95SBruce Richardson 		p->n_pkts);
21999a2dd95SBruce Richardson 
22099a2dd95SBruce Richardson 	for (i = 0; i < p->n_pkts; i++)
22199a2dd95SBruce Richardson 		rte_pktmbuf_free(p->pkts[i]);
22299a2dd95SBruce Richardson 
22399a2dd95SBruce Richardson 	p->n_pkts = 0;
22499a2dd95SBruce Richardson }
22599a2dd95SBruce Richardson 
22699a2dd95SBruce Richardson static void
writer_pkt_tx(void * port,struct rte_swx_pkt * pkt)22799a2dd95SBruce Richardson writer_pkt_tx(void *port, struct rte_swx_pkt *pkt)
22899a2dd95SBruce Richardson {
22999a2dd95SBruce Richardson 	struct writer *p = port;
23099a2dd95SBruce Richardson 	struct rte_mbuf *m = pkt->handle;
23199a2dd95SBruce Richardson 
23299a2dd95SBruce Richardson 	TRACE("[FD %u] Pkt %u (%u bytes at offset %u)\n",
23399a2dd95SBruce Richardson 		(uint32_t)p->params.fd,
23499a2dd95SBruce Richardson 		p->n_pkts - 1,
23599a2dd95SBruce Richardson 		pkt->length,
23699a2dd95SBruce Richardson 		pkt->offset);
23799a2dd95SBruce Richardson 
23899a2dd95SBruce Richardson 	if (TRACE_LEVEL)
23999a2dd95SBruce Richardson 		rte_hexdump(stdout, NULL, &pkt->pkt[pkt->offset], pkt->length);
24099a2dd95SBruce Richardson 
241b94eb6cdSCristian Dumitrescu 	m->data_len = (uint16_t)(pkt->length + m->data_len - m->pkt_len);
24299a2dd95SBruce Richardson 	m->pkt_len = pkt->length;
24399a2dd95SBruce Richardson 	m->data_off = (uint16_t)pkt->offset;
24499a2dd95SBruce Richardson 
24599a2dd95SBruce Richardson 	p->stats.n_pkts++;
24699a2dd95SBruce Richardson 	p->stats.n_bytes += pkt->length;
24799a2dd95SBruce Richardson 
24899a2dd95SBruce Richardson 	p->pkts[p->n_pkts++] = m;
24999a2dd95SBruce Richardson 	if (p->n_pkts == p->params.burst_size)
25099a2dd95SBruce Richardson 		__writer_flush(p);
25199a2dd95SBruce Richardson }
25299a2dd95SBruce Richardson 
25399a2dd95SBruce Richardson static void
writer_pkt_fast_clone_tx(void * port,struct rte_swx_pkt * pkt)254b94eb6cdSCristian Dumitrescu writer_pkt_fast_clone_tx(void *port, struct rte_swx_pkt *pkt)
255b94eb6cdSCristian Dumitrescu {
256b94eb6cdSCristian Dumitrescu 	struct writer *p = port;
257b94eb6cdSCristian Dumitrescu 	struct rte_mbuf *m = pkt->handle;
258b94eb6cdSCristian Dumitrescu 
259b94eb6cdSCristian Dumitrescu 	TRACE("[FD %u] Pkt %u (%u bytes at offset %u) (fast clone)\n",
260b94eb6cdSCristian Dumitrescu 		(uint32_t)p->params.fd,
261b94eb6cdSCristian Dumitrescu 		p->n_pkts - 1,
262b94eb6cdSCristian Dumitrescu 		pkt->length,
263b94eb6cdSCristian Dumitrescu 		pkt->offset);
264b94eb6cdSCristian Dumitrescu 	if (TRACE_LEVEL)
265b94eb6cdSCristian Dumitrescu 		rte_hexdump(stdout, NULL, &pkt->pkt[pkt->offset], pkt->length);
266b94eb6cdSCristian Dumitrescu 
267b94eb6cdSCristian Dumitrescu 	m->data_len = (uint16_t)(pkt->length + m->data_len - m->pkt_len);
268b94eb6cdSCristian Dumitrescu 	m->pkt_len = pkt->length;
269b94eb6cdSCristian Dumitrescu 	m->data_off = (uint16_t)pkt->offset;
270b94eb6cdSCristian Dumitrescu 	rte_pktmbuf_refcnt_update(m, 1);
271b94eb6cdSCristian Dumitrescu 
272b94eb6cdSCristian Dumitrescu 	p->stats.n_pkts++;
273b94eb6cdSCristian Dumitrescu 	p->stats.n_bytes += pkt->length;
274b94eb6cdSCristian Dumitrescu 	p->stats.n_pkts_clone++;
275b94eb6cdSCristian Dumitrescu 
276b94eb6cdSCristian Dumitrescu 	p->pkts[p->n_pkts++] = m;
277b94eb6cdSCristian Dumitrescu 	if (p->n_pkts == p->params.burst_size)
278b94eb6cdSCristian Dumitrescu 		__writer_flush(p);
279b94eb6cdSCristian Dumitrescu }
280b94eb6cdSCristian Dumitrescu 
281b94eb6cdSCristian Dumitrescu static void
writer_pkt_clone_tx(void * port,struct rte_swx_pkt * pkt,uint32_t truncation_length)282b94eb6cdSCristian Dumitrescu writer_pkt_clone_tx(void *port, struct rte_swx_pkt *pkt, uint32_t truncation_length)
283b94eb6cdSCristian Dumitrescu {
284b94eb6cdSCristian Dumitrescu 	struct writer *p = port;
285b94eb6cdSCristian Dumitrescu 	struct rte_mbuf *m = pkt->handle, *m_clone;
286b94eb6cdSCristian Dumitrescu 
287b94eb6cdSCristian Dumitrescu 	TRACE("[FD %u] Pkt %u (%u bytes at offset %u) (clone)\n",
288b94eb6cdSCristian Dumitrescu 		(uint32_t)p->params.fd,
289b94eb6cdSCristian Dumitrescu 		p->n_pkts - 1,
290b94eb6cdSCristian Dumitrescu 		pkt->length,
291b94eb6cdSCristian Dumitrescu 		pkt->offset);
292b94eb6cdSCristian Dumitrescu 	if (TRACE_LEVEL)
293b94eb6cdSCristian Dumitrescu 		rte_hexdump(stdout, NULL, &pkt->pkt[pkt->offset], pkt->length);
294b94eb6cdSCristian Dumitrescu 
295b94eb6cdSCristian Dumitrescu 	m->data_len = (uint16_t)(pkt->length + m->data_len - m->pkt_len);
296b94eb6cdSCristian Dumitrescu 	m->pkt_len = pkt->length;
297b94eb6cdSCristian Dumitrescu 	m->data_off = (uint16_t)pkt->offset;
298b94eb6cdSCristian Dumitrescu 
299b94eb6cdSCristian Dumitrescu 	m_clone = rte_pktmbuf_copy(m, m->pool, 0, truncation_length);
300b94eb6cdSCristian Dumitrescu 	if (!m_clone) {
301b94eb6cdSCristian Dumitrescu 		p->stats.n_pkts_clone_err++;
302b94eb6cdSCristian Dumitrescu 		return;
303b94eb6cdSCristian Dumitrescu 	}
304b94eb6cdSCristian Dumitrescu 
305b94eb6cdSCristian Dumitrescu 	p->stats.n_pkts++;
306b94eb6cdSCristian Dumitrescu 	p->stats.n_bytes += pkt->length;
307b94eb6cdSCristian Dumitrescu 	p->stats.n_pkts_clone++;
308b94eb6cdSCristian Dumitrescu 
309b94eb6cdSCristian Dumitrescu 	p->pkts[p->n_pkts++] = m_clone;
310b94eb6cdSCristian Dumitrescu 	if (p->n_pkts == p->params.burst_size)
311b94eb6cdSCristian Dumitrescu 		__writer_flush(p);
312b94eb6cdSCristian Dumitrescu }
313b94eb6cdSCristian Dumitrescu 
314b94eb6cdSCristian Dumitrescu static void
writer_flush(void * port)31599a2dd95SBruce Richardson writer_flush(void *port)
31699a2dd95SBruce Richardson {
31799a2dd95SBruce Richardson 	struct writer *p = port;
31899a2dd95SBruce Richardson 
31999a2dd95SBruce Richardson 	if (p->n_pkts)
32099a2dd95SBruce Richardson 		__writer_flush(p);
32199a2dd95SBruce Richardson }
32299a2dd95SBruce Richardson 
32399a2dd95SBruce Richardson static void
writer_free(void * port)32499a2dd95SBruce Richardson writer_free(void *port)
32599a2dd95SBruce Richardson {
32699a2dd95SBruce Richardson 	struct writer *p = port;
32799a2dd95SBruce Richardson 
32899a2dd95SBruce Richardson 	if (!p)
32999a2dd95SBruce Richardson 		return;
33099a2dd95SBruce Richardson 
33199a2dd95SBruce Richardson 	writer_flush(p);
33299a2dd95SBruce Richardson 	free(p->pkts);
33399a2dd95SBruce Richardson 	free(p);
33499a2dd95SBruce Richardson }
33599a2dd95SBruce Richardson 
33699a2dd95SBruce Richardson static void
writer_stats_read(void * port,struct rte_swx_port_out_stats * stats)33799a2dd95SBruce Richardson writer_stats_read(void *port, struct rte_swx_port_out_stats *stats)
33899a2dd95SBruce Richardson {
33999a2dd95SBruce Richardson 	struct writer *p = port;
34099a2dd95SBruce Richardson 
34199a2dd95SBruce Richardson 	memcpy(stats, &p->stats, sizeof(p->stats));
34299a2dd95SBruce Richardson }
34399a2dd95SBruce Richardson 
34499a2dd95SBruce Richardson /*
34599a2dd95SBruce Richardson  * Summary of port operations
34699a2dd95SBruce Richardson  */
34799a2dd95SBruce Richardson struct rte_swx_port_in_ops rte_swx_port_fd_reader_ops = {
34899a2dd95SBruce Richardson 	.create = reader_create,
34999a2dd95SBruce Richardson 	.free = reader_free,
35099a2dd95SBruce Richardson 	.pkt_rx = reader_pkt_rx,
35199a2dd95SBruce Richardson 	.stats_read = reader_stats_read,
35299a2dd95SBruce Richardson };
35399a2dd95SBruce Richardson 
35499a2dd95SBruce Richardson struct rte_swx_port_out_ops rte_swx_port_fd_writer_ops = {
35599a2dd95SBruce Richardson 	.create = writer_create,
35699a2dd95SBruce Richardson 	.free = writer_free,
35799a2dd95SBruce Richardson 	.pkt_tx = writer_pkt_tx,
358b94eb6cdSCristian Dumitrescu 	.pkt_fast_clone_tx = writer_pkt_fast_clone_tx,
359b94eb6cdSCristian Dumitrescu 	.pkt_clone_tx = writer_pkt_clone_tx,
36099a2dd95SBruce Richardson 	.flush = writer_flush,
36199a2dd95SBruce Richardson 	.stats_read = writer_stats_read,
36299a2dd95SBruce Richardson };
363