199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson * Copyright(c) 2010-2014 Intel Corporation
399a2dd95SBruce Richardson */
499a2dd95SBruce Richardson #include <string.h>
599a2dd95SBruce Richardson
699a2dd95SBruce Richardson #include <rte_ip_frag.h>
799a2dd95SBruce Richardson
899a2dd95SBruce Richardson #include "rte_port_frag.h"
999a2dd95SBruce Richardson
10ae67895bSDavid Marchand #include "port_log.h"
11ae67895bSDavid Marchand
1299a2dd95SBruce Richardson /* Max number of fragments per packet allowed */
1399a2dd95SBruce Richardson #define RTE_PORT_FRAG_MAX_FRAGS_PER_PACKET 0x80
1499a2dd95SBruce Richardson
1599a2dd95SBruce Richardson #ifdef RTE_PORT_STATS_COLLECT
1699a2dd95SBruce Richardson
1799a2dd95SBruce Richardson #define RTE_PORT_RING_READER_FRAG_STATS_PKTS_IN_ADD(port, val) \
1899a2dd95SBruce Richardson port->stats.n_pkts_in += val
1999a2dd95SBruce Richardson #define RTE_PORT_RING_READER_FRAG_STATS_PKTS_DROP_ADD(port, val) \
2099a2dd95SBruce Richardson port->stats.n_pkts_drop += val
2199a2dd95SBruce Richardson
2299a2dd95SBruce Richardson #else
2399a2dd95SBruce Richardson
2499a2dd95SBruce Richardson #define RTE_PORT_RING_READER_FRAG_STATS_PKTS_IN_ADD(port, val)
2599a2dd95SBruce Richardson #define RTE_PORT_RING_READER_FRAG_STATS_PKTS_DROP_ADD(port, val)
2699a2dd95SBruce Richardson
2799a2dd95SBruce Richardson #endif
2899a2dd95SBruce Richardson
2999a2dd95SBruce Richardson typedef int32_t
3099a2dd95SBruce Richardson (*frag_op)(struct rte_mbuf *pkt_in,
3199a2dd95SBruce Richardson struct rte_mbuf **pkts_out,
3299a2dd95SBruce Richardson uint16_t nb_pkts_out,
3399a2dd95SBruce Richardson uint16_t mtu_size,
3499a2dd95SBruce Richardson struct rte_mempool *pool_direct,
3599a2dd95SBruce Richardson struct rte_mempool *pool_indirect);
3699a2dd95SBruce Richardson
37*c6552d9aSTyler Retzlaff struct __rte_cache_aligned rte_port_ring_reader_frag {
3899a2dd95SBruce Richardson struct rte_port_in_stats stats;
3999a2dd95SBruce Richardson
4099a2dd95SBruce Richardson /* Input parameters */
4199a2dd95SBruce Richardson struct rte_ring *ring;
4299a2dd95SBruce Richardson uint32_t mtu;
4399a2dd95SBruce Richardson uint32_t metadata_size;
4499a2dd95SBruce Richardson struct rte_mempool *pool_direct;
4599a2dd95SBruce Richardson struct rte_mempool *pool_indirect;
4699a2dd95SBruce Richardson
4799a2dd95SBruce Richardson /* Internal buffers */
4899a2dd95SBruce Richardson struct rte_mbuf *pkts[RTE_PORT_IN_BURST_SIZE_MAX];
4999a2dd95SBruce Richardson struct rte_mbuf *frags[RTE_PORT_FRAG_MAX_FRAGS_PER_PACKET];
5099a2dd95SBruce Richardson uint32_t n_pkts;
5199a2dd95SBruce Richardson uint32_t pos_pkts;
5299a2dd95SBruce Richardson uint32_t n_frags;
5399a2dd95SBruce Richardson uint32_t pos_frags;
5499a2dd95SBruce Richardson
5599a2dd95SBruce Richardson frag_op f_frag;
56*c6552d9aSTyler Retzlaff };
5799a2dd95SBruce Richardson
5899a2dd95SBruce Richardson static void *
rte_port_ring_reader_frag_create(void * params,int socket_id,int is_ipv4)5999a2dd95SBruce Richardson rte_port_ring_reader_frag_create(void *params, int socket_id, int is_ipv4)
6099a2dd95SBruce Richardson {
6199a2dd95SBruce Richardson struct rte_port_ring_reader_frag_params *conf =
6299a2dd95SBruce Richardson params;
6399a2dd95SBruce Richardson struct rte_port_ring_reader_frag *port;
6499a2dd95SBruce Richardson
6599a2dd95SBruce Richardson /* Check input parameters */
6699a2dd95SBruce Richardson if (conf == NULL) {
67ae67895bSDavid Marchand PORT_LOG(ERR, "%s: Parameter conf is NULL", __func__);
6899a2dd95SBruce Richardson return NULL;
6999a2dd95SBruce Richardson }
7099a2dd95SBruce Richardson if (conf->ring == NULL) {
71ae67895bSDavid Marchand PORT_LOG(ERR, "%s: Parameter ring is NULL", __func__);
7299a2dd95SBruce Richardson return NULL;
7399a2dd95SBruce Richardson }
7499a2dd95SBruce Richardson if (conf->mtu == 0) {
75ae67895bSDavid Marchand PORT_LOG(ERR, "%s: Parameter mtu is invalid", __func__);
7699a2dd95SBruce Richardson return NULL;
7799a2dd95SBruce Richardson }
7899a2dd95SBruce Richardson if (conf->pool_direct == NULL) {
79ae67895bSDavid Marchand PORT_LOG(ERR, "%s: Parameter pool_direct is NULL",
8099a2dd95SBruce Richardson __func__);
8199a2dd95SBruce Richardson return NULL;
8299a2dd95SBruce Richardson }
8399a2dd95SBruce Richardson if (conf->pool_indirect == NULL) {
84ae67895bSDavid Marchand PORT_LOG(ERR, "%s: Parameter pool_indirect is NULL",
8599a2dd95SBruce Richardson __func__);
8699a2dd95SBruce Richardson return NULL;
8799a2dd95SBruce Richardson }
8899a2dd95SBruce Richardson
8999a2dd95SBruce Richardson /* Memory allocation */
9099a2dd95SBruce Richardson port = rte_zmalloc_socket("PORT", sizeof(*port), RTE_CACHE_LINE_SIZE,
9199a2dd95SBruce Richardson socket_id);
9299a2dd95SBruce Richardson if (port == NULL) {
93ae67895bSDavid Marchand PORT_LOG(ERR, "%s: port is NULL", __func__);
9499a2dd95SBruce Richardson return NULL;
9599a2dd95SBruce Richardson }
9699a2dd95SBruce Richardson
9799a2dd95SBruce Richardson /* Initialization */
9899a2dd95SBruce Richardson port->ring = conf->ring;
9999a2dd95SBruce Richardson port->mtu = conf->mtu;
10099a2dd95SBruce Richardson port->metadata_size = conf->metadata_size;
10199a2dd95SBruce Richardson port->pool_direct = conf->pool_direct;
10299a2dd95SBruce Richardson port->pool_indirect = conf->pool_indirect;
10399a2dd95SBruce Richardson
10499a2dd95SBruce Richardson port->n_pkts = 0;
10599a2dd95SBruce Richardson port->pos_pkts = 0;
10699a2dd95SBruce Richardson port->n_frags = 0;
10799a2dd95SBruce Richardson port->pos_frags = 0;
10899a2dd95SBruce Richardson
10999a2dd95SBruce Richardson port->f_frag = (is_ipv4) ?
11099a2dd95SBruce Richardson rte_ipv4_fragment_packet : rte_ipv6_fragment_packet;
11199a2dd95SBruce Richardson
11299a2dd95SBruce Richardson return port;
11399a2dd95SBruce Richardson }
11499a2dd95SBruce Richardson
11599a2dd95SBruce Richardson static void *
rte_port_ring_reader_ipv4_frag_create(void * params,int socket_id)11699a2dd95SBruce Richardson rte_port_ring_reader_ipv4_frag_create(void *params, int socket_id)
11799a2dd95SBruce Richardson {
11899a2dd95SBruce Richardson return rte_port_ring_reader_frag_create(params, socket_id, 1);
11999a2dd95SBruce Richardson }
12099a2dd95SBruce Richardson
12199a2dd95SBruce Richardson static void *
rte_port_ring_reader_ipv6_frag_create(void * params,int socket_id)12299a2dd95SBruce Richardson rte_port_ring_reader_ipv6_frag_create(void *params, int socket_id)
12399a2dd95SBruce Richardson {
12499a2dd95SBruce Richardson return rte_port_ring_reader_frag_create(params, socket_id, 0);
12599a2dd95SBruce Richardson }
12699a2dd95SBruce Richardson
12799a2dd95SBruce Richardson static int
rte_port_ring_reader_frag_rx(void * port,struct rte_mbuf ** pkts,uint32_t n_pkts)12899a2dd95SBruce Richardson rte_port_ring_reader_frag_rx(void *port,
12999a2dd95SBruce Richardson struct rte_mbuf **pkts,
13099a2dd95SBruce Richardson uint32_t n_pkts)
13199a2dd95SBruce Richardson {
13299a2dd95SBruce Richardson struct rte_port_ring_reader_frag *p =
13399a2dd95SBruce Richardson port;
13499a2dd95SBruce Richardson uint32_t n_pkts_out;
13599a2dd95SBruce Richardson
13699a2dd95SBruce Richardson n_pkts_out = 0;
13799a2dd95SBruce Richardson
13899a2dd95SBruce Richardson /* Get packets from the "frag" buffer */
13999a2dd95SBruce Richardson if (p->n_frags >= n_pkts) {
14099a2dd95SBruce Richardson memcpy(pkts, &p->frags[p->pos_frags], n_pkts * sizeof(void *));
14199a2dd95SBruce Richardson p->pos_frags += n_pkts;
14299a2dd95SBruce Richardson p->n_frags -= n_pkts;
14399a2dd95SBruce Richardson
14499a2dd95SBruce Richardson return n_pkts;
14599a2dd95SBruce Richardson }
14699a2dd95SBruce Richardson
14799a2dd95SBruce Richardson memcpy(pkts, &p->frags[p->pos_frags], p->n_frags * sizeof(void *));
14899a2dd95SBruce Richardson n_pkts_out = p->n_frags;
14999a2dd95SBruce Richardson p->n_frags = 0;
15099a2dd95SBruce Richardson
15199a2dd95SBruce Richardson /* Look to "pkts" buffer to get more packets */
15299a2dd95SBruce Richardson for ( ; ; ) {
15399a2dd95SBruce Richardson struct rte_mbuf *pkt;
15499a2dd95SBruce Richardson uint32_t n_pkts_to_provide, i;
15599a2dd95SBruce Richardson int status;
15699a2dd95SBruce Richardson
15799a2dd95SBruce Richardson /* If "pkts" buffer is empty, read packet burst from ring */
15899a2dd95SBruce Richardson if (p->n_pkts == 0) {
15999a2dd95SBruce Richardson p->n_pkts = rte_ring_sc_dequeue_burst(p->ring,
16099a2dd95SBruce Richardson (void **) p->pkts, RTE_PORT_IN_BURST_SIZE_MAX,
16199a2dd95SBruce Richardson NULL);
16299a2dd95SBruce Richardson RTE_PORT_RING_READER_FRAG_STATS_PKTS_IN_ADD(p, p->n_pkts);
16399a2dd95SBruce Richardson if (p->n_pkts == 0)
16499a2dd95SBruce Richardson return n_pkts_out;
16599a2dd95SBruce Richardson p->pos_pkts = 0;
16699a2dd95SBruce Richardson }
16799a2dd95SBruce Richardson
16899a2dd95SBruce Richardson /* Read next packet from "pkts" buffer */
16999a2dd95SBruce Richardson pkt = p->pkts[p->pos_pkts++];
17099a2dd95SBruce Richardson p->n_pkts--;
17199a2dd95SBruce Richardson
17299a2dd95SBruce Richardson /* If not jumbo, pass current packet to output */
17399a2dd95SBruce Richardson if (pkt->pkt_len <= p->mtu) {
17499a2dd95SBruce Richardson pkts[n_pkts_out++] = pkt;
17599a2dd95SBruce Richardson
17699a2dd95SBruce Richardson n_pkts_to_provide = n_pkts - n_pkts_out;
17799a2dd95SBruce Richardson if (n_pkts_to_provide == 0)
17899a2dd95SBruce Richardson return n_pkts;
17999a2dd95SBruce Richardson
18099a2dd95SBruce Richardson continue;
18199a2dd95SBruce Richardson }
18299a2dd95SBruce Richardson
18399a2dd95SBruce Richardson /* Fragment current packet into the "frags" buffer */
18499a2dd95SBruce Richardson status = p->f_frag(
18599a2dd95SBruce Richardson pkt,
18699a2dd95SBruce Richardson p->frags,
18799a2dd95SBruce Richardson RTE_PORT_FRAG_MAX_FRAGS_PER_PACKET,
18899a2dd95SBruce Richardson p->mtu,
18999a2dd95SBruce Richardson p->pool_direct,
19099a2dd95SBruce Richardson p->pool_indirect
19199a2dd95SBruce Richardson );
19299a2dd95SBruce Richardson
19399a2dd95SBruce Richardson if (status < 0) {
19499a2dd95SBruce Richardson rte_pktmbuf_free(pkt);
19599a2dd95SBruce Richardson RTE_PORT_RING_READER_FRAG_STATS_PKTS_DROP_ADD(p, 1);
19699a2dd95SBruce Richardson continue;
19799a2dd95SBruce Richardson }
19899a2dd95SBruce Richardson
19999a2dd95SBruce Richardson p->n_frags = (uint32_t) status;
20099a2dd95SBruce Richardson p->pos_frags = 0;
20199a2dd95SBruce Richardson
20299a2dd95SBruce Richardson /* Copy meta-data from input jumbo packet to its fragments */
20399a2dd95SBruce Richardson for (i = 0; i < p->n_frags; i++) {
20499a2dd95SBruce Richardson uint8_t *src =
20599a2dd95SBruce Richardson RTE_MBUF_METADATA_UINT8_PTR(pkt, sizeof(struct rte_mbuf));
20699a2dd95SBruce Richardson uint8_t *dst =
20799a2dd95SBruce Richardson RTE_MBUF_METADATA_UINT8_PTR(p->frags[i], sizeof(struct rte_mbuf));
20899a2dd95SBruce Richardson
20999a2dd95SBruce Richardson memcpy(dst, src, p->metadata_size);
21099a2dd95SBruce Richardson }
21199a2dd95SBruce Richardson
21299a2dd95SBruce Richardson /* Free input jumbo packet */
21399a2dd95SBruce Richardson rte_pktmbuf_free(pkt);
21499a2dd95SBruce Richardson
21599a2dd95SBruce Richardson /* Get packets from "frag" buffer */
21699a2dd95SBruce Richardson n_pkts_to_provide = n_pkts - n_pkts_out;
21799a2dd95SBruce Richardson if (p->n_frags >= n_pkts_to_provide) {
21899a2dd95SBruce Richardson memcpy(&pkts[n_pkts_out], p->frags,
21999a2dd95SBruce Richardson n_pkts_to_provide * sizeof(void *));
22099a2dd95SBruce Richardson p->n_frags -= n_pkts_to_provide;
22199a2dd95SBruce Richardson p->pos_frags += n_pkts_to_provide;
22299a2dd95SBruce Richardson
22399a2dd95SBruce Richardson return n_pkts;
22499a2dd95SBruce Richardson }
22599a2dd95SBruce Richardson
22699a2dd95SBruce Richardson memcpy(&pkts[n_pkts_out], p->frags,
22799a2dd95SBruce Richardson p->n_frags * sizeof(void *));
22899a2dd95SBruce Richardson n_pkts_out += p->n_frags;
22999a2dd95SBruce Richardson p->n_frags = 0;
23099a2dd95SBruce Richardson }
23199a2dd95SBruce Richardson }
23299a2dd95SBruce Richardson
23399a2dd95SBruce Richardson static int
rte_port_ring_reader_frag_free(void * port)23499a2dd95SBruce Richardson rte_port_ring_reader_frag_free(void *port)
23599a2dd95SBruce Richardson {
23699a2dd95SBruce Richardson if (port == NULL) {
237ae67895bSDavid Marchand PORT_LOG(ERR, "%s: Parameter port is NULL", __func__);
23899a2dd95SBruce Richardson return -1;
23999a2dd95SBruce Richardson }
24099a2dd95SBruce Richardson
24199a2dd95SBruce Richardson rte_free(port);
24299a2dd95SBruce Richardson
24399a2dd95SBruce Richardson return 0;
24499a2dd95SBruce Richardson }
24599a2dd95SBruce Richardson
24699a2dd95SBruce Richardson static int
rte_port_frag_reader_stats_read(void * port,struct rte_port_in_stats * stats,int clear)24799a2dd95SBruce Richardson rte_port_frag_reader_stats_read(void *port,
24899a2dd95SBruce Richardson struct rte_port_in_stats *stats, int clear)
24999a2dd95SBruce Richardson {
25099a2dd95SBruce Richardson struct rte_port_ring_reader_frag *p =
25199a2dd95SBruce Richardson port;
25299a2dd95SBruce Richardson
25399a2dd95SBruce Richardson if (stats != NULL)
25499a2dd95SBruce Richardson memcpy(stats, &p->stats, sizeof(p->stats));
25599a2dd95SBruce Richardson
25699a2dd95SBruce Richardson if (clear)
25799a2dd95SBruce Richardson memset(&p->stats, 0, sizeof(p->stats));
25899a2dd95SBruce Richardson
25999a2dd95SBruce Richardson return 0;
26099a2dd95SBruce Richardson }
26199a2dd95SBruce Richardson
26299a2dd95SBruce Richardson /*
26399a2dd95SBruce Richardson * Summary of port operations
26499a2dd95SBruce Richardson */
26599a2dd95SBruce Richardson struct rte_port_in_ops rte_port_ring_reader_ipv4_frag_ops = {
26699a2dd95SBruce Richardson .f_create = rte_port_ring_reader_ipv4_frag_create,
26799a2dd95SBruce Richardson .f_free = rte_port_ring_reader_frag_free,
26899a2dd95SBruce Richardson .f_rx = rte_port_ring_reader_frag_rx,
26999a2dd95SBruce Richardson .f_stats = rte_port_frag_reader_stats_read,
27099a2dd95SBruce Richardson };
27199a2dd95SBruce Richardson
27299a2dd95SBruce Richardson struct rte_port_in_ops rte_port_ring_reader_ipv6_frag_ops = {
27399a2dd95SBruce Richardson .f_create = rte_port_ring_reader_ipv6_frag_create,
27499a2dd95SBruce Richardson .f_free = rte_port_ring_reader_frag_free,
27599a2dd95SBruce Richardson .f_rx = rte_port_ring_reader_frag_rx,
27699a2dd95SBruce Richardson .f_stats = rte_port_frag_reader_stats_read,
27799a2dd95SBruce Richardson };
278