tcp_tx_seg.h revision 7e18fa1b
1/*
2 * Copyright (c) 2016-2017  Intel Corporation.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#ifndef _TCP_TX_SEG_H_
17#define _TCP_TX_SEG_H_
18
19#ifdef __cplusplus
20extern "C" {
21#endif
22
23static inline int32_t
24tcp_segmentation(struct rte_mbuf *mbin, struct rte_mbuf *mbout[], uint16_t num,
25	const struct tle_dest *dst, uint16_t mss)
26{
27	struct rte_mbuf *in_seg = NULL;
28	uint32_t nbseg, in_seg_data_pos;
29	uint32_t more_in_segs;
30
31	in_seg = mbin;
32	in_seg_data_pos = 0;
33	nbseg = 0;
34
35	/* Check that pkts_out is big enough to hold all fragments */
36	if (mss * num < (uint16_t)mbin->pkt_len)
37		return -ENOSPC;
38
39	more_in_segs = 1;
40	while (more_in_segs) {
41		struct rte_mbuf *out_pkt = NULL, *out_seg_prev = NULL;
42		uint32_t more_out_segs;
43
44		/* Allocate direct buffer */
45		out_pkt = rte_pktmbuf_alloc(dst->head_mp);
46		if (out_pkt == NULL) {
47			free_mbufs(mbout, nbseg);
48			return -ENOMEM;
49		}
50
51		out_seg_prev = out_pkt;
52		more_out_segs = 1;
53		while (more_out_segs && more_in_segs) {
54			struct rte_mbuf *out_seg = NULL;
55			uint32_t len;
56
57			/* Allocate indirect buffer */
58			out_seg = rte_pktmbuf_alloc(dst->head_mp);
59			if (out_seg == NULL) {
60				rte_pktmbuf_free(out_pkt);
61				free_mbufs(mbout, nbseg);
62				return -ENOMEM;
63			}
64			out_seg_prev->next = out_seg;
65			out_seg_prev = out_seg;
66
67			/* Prepare indirect buffer */
68			rte_pktmbuf_attach(out_seg, in_seg);
69			len = mss;
70			if (len > (in_seg->data_len - in_seg_data_pos))
71				len = in_seg->data_len - in_seg_data_pos;
72
73			out_seg->data_off = in_seg->data_off + in_seg_data_pos;
74			out_seg->data_len = (uint16_t)len;
75			out_pkt->pkt_len = (uint16_t)(len + out_pkt->pkt_len);
76			out_pkt->nb_segs += 1;
77			in_seg_data_pos += len;
78
79			/* Current output packet (i.e. fragment) done ? */
80			if (out_pkt->pkt_len >= mss)
81				more_out_segs = 0;
82
83			/* Current input segment done ? */
84			if (in_seg_data_pos == in_seg->data_len) {
85				in_seg = in_seg->next;
86				in_seg_data_pos = 0;
87
88				if (in_seg == NULL)
89					more_in_segs = 0;
90			}
91		}
92
93		/* Write the segment to the output list */
94		mbout[nbseg] = out_pkt;
95		nbseg++;
96	}
97
98	return nbseg;
99}
100
101#ifdef __cplusplus
102}
103#endif
104
105#endif /* _TCP_TX_SEG_H_ */
106