tcp_tx_seg.h revision 85b0a328
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	uint16_t bytes_left;
31
32	in_seg = mbin;
33	in_seg_data_pos = 0;
34	nbseg = 0;
35
36	/* Check that pkts_out is big enough to hold all fragments */
37	if (mss * num < (uint16_t)mbin->pkt_len)
38		return -ENOSPC;
39
40	more_in_segs = 1;
41	while (more_in_segs) {
42		struct rte_mbuf *out_pkt = NULL, *out_seg_prev = NULL;
43		uint32_t more_out_segs;
44
45		/* Allocate direct buffer */
46		out_pkt = rte_pktmbuf_alloc(dst->head_mp);
47		if (out_pkt == NULL) {
48			free_mbufs(mbout, nbseg);
49			return -ENOMEM;
50		}
51
52		bytes_left = mss;
53		out_seg_prev = out_pkt;
54		more_out_segs = 1;
55		while (more_out_segs && more_in_segs) {
56			struct rte_mbuf *out_seg = NULL;
57			uint32_t len;
58
59			/* Allocate indirect buffer */
60			out_seg = rte_pktmbuf_alloc(dst->head_mp);
61			if (out_seg == NULL) {
62				rte_pktmbuf_free(out_pkt);
63				free_mbufs(mbout, nbseg);
64				return -ENOMEM;
65			}
66			out_seg_prev->next = out_seg;
67			out_seg_prev = out_seg;
68
69			/* Prepare indirect buffer */
70			rte_pktmbuf_attach(out_seg, in_seg);
71			len = bytes_left;
72			if (len > (in_seg->data_len - in_seg_data_pos))
73				len = in_seg->data_len - in_seg_data_pos;
74
75			out_seg->data_off = in_seg->data_off + in_seg_data_pos;
76			out_seg->data_len = (uint16_t)len;
77			out_pkt->pkt_len = (uint16_t)(len + out_pkt->pkt_len);
78			out_pkt->nb_segs += 1;
79			in_seg_data_pos += len;
80			bytes_left -= len;
81
82			/* Current output packet (i.e. fragment) done ? */
83			if (bytes_left == 0)
84				more_out_segs = 0;
85
86			/* Current input segment done ? */
87			if (in_seg_data_pos == in_seg->data_len) {
88				in_seg = in_seg->next;
89				in_seg_data_pos = 0;
90
91				if (in_seg == NULL)
92					more_in_segs = 0;
93			}
94		}
95
96		/* Write the segment to the output list */
97		mbout[nbseg] = out_pkt;
98		nbseg++;
99	}
100
101	return nbseg;
102}
103
104#ifdef __cplusplus
105}
106#endif
107
108#endif /* _TCP_TX_SEG_H_ */
109