2 * Copyright (c) 2016 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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
29 struct rte_mbuf **obj;
39 _ofodb_move(struct ofodb *dst, struct ofodb *src)
43 dst->nb_elem = src->nb_elem;
45 for (i = 0; i < src->nb_elem; i++)
46 dst->obj[i] = src->obj[i];
50 _ofodb_free(struct ofodb *db)
54 for (i = 0; i != db->nb_elem; i++)
55 rte_pktmbuf_free(db->obj[i]);
59 _ofo_remove(struct ofo *ofo, uint32_t pos, uint32_t num)
63 n = ofo->nb_elem - num - pos;
64 for (i = 0; i != n; i++)
65 _ofodb_move(&ofo->db[pos + i], &ofo->db[pos + num + i]);
70 tcp_ofo_reset(struct ofo *ofo)
74 for (i = 0; i != ofo->nb_elem; i++)
75 _ofodb_free(&ofo->db[i]);
77 _ofo_remove(ofo, 0, ofo->nb_elem);
80 static inline uint32_t
81 _ofo_insert_mbuf(struct ofo* ofo, uint32_t pos, union seqlen* sl,
82 struct rte_mbuf* mb[], uint32_t num, bool is_compact) {
86 struct ofodb* db = ofo->db + pos;
88 /* new pkts may overlap with right side db,
89 * don't insert overlapped part from 'end'
90 * function could be called from _ofo_compact,
91 * no overlap in this condition.
93 if (!is_compact && pos < ofo->nb_elem - 1)
94 end = ofo->db[pos + 1].sl.seq;
96 end = sl->seq + sl->len;
98 /* copy non-overlapping mbufs */
100 n = RTE_MIN(db->nb_max - k, num);
101 for (i = 0, seq = sl->seq; i != n && tcp_seq_lt(seq, end); i++) {
102 seq += mb[i]->pkt_len;
103 db->obj[k + i] = mb[i];
105 if (tcp_seq_lt(end, seq))
106 rte_pktmbuf_trim(mb[i - 1], seq - end);
109 db->sl.len += tcp_seq_min(seq, end) - sl->seq;
110 sl->len = sl->seq + sl->len - seq;
115 static inline uint32_t
116 _ofo_insert_new(struct ofo *ofo, uint32_t pos, union seqlen *sl,
117 struct rte_mbuf *mb[], uint32_t num)
124 if (n == ofo->nb_max)
127 /* allocate new one */
128 ofo->nb_elem = n + 1;
130 /* insert into a proper position. */
131 for (i = n; i != pos; i--)
132 _ofodb_move(&ofo->db[i], &ofo->db[i - 1]);
134 ofo->db[pos].nb_elem = 0;
135 ofo->db[pos].sl.seq = sl->seq;
136 ofo->db[pos].sl.len = 0;
138 i = _ofo_insert_mbuf(ofo, pos, sl, mb, num, false);
142 static inline uint32_t
143 _ofo_insert_right(struct ofo *ofo, uint32_t pos, union seqlen *sl,
144 struct rte_mbuf *mb[], uint32_t num, bool is_compact)
147 uint32_t end, plen, skip;
151 end = db->sl.seq + db->sl.len;
153 skip = end - sl->seq;
155 /* skip overlapping packets */
156 for (i = 0, n = skip; i != num && n != 0; i++, n -= plen) {
157 plen = mb[i]->pkt_len;
159 /* adjust partially overlapped packet. */
160 rte_pktmbuf_adj(mb[i], n);
165 /* free totally overlapped packets. */
166 for (j = 0; j != i; j++)
167 rte_pktmbuf_free(mb[j]);
171 j = _ofo_insert_mbuf(ofo, pos, sl, mb + i, num - i, is_compact);
175 static inline uint32_t
176 _ofo_step(struct ofo *ofo, union seqlen *sl, struct rte_mbuf *mb[],
180 struct ofodb *db, *nextdb;
186 * start from the right side, assume that after some gap,
187 * we keep receiving packets in order.
189 for (i = n; i-- != 0; ) {
191 if (tcp_seq_leq(db->sl.seq, sl->seq))
196 * if db has right consecutive dbs, find the most right one.
197 * we should insert new packets after this db, rather than left ones.
199 for (; i < n - 1; i++) {
201 if (db->sl.seq + db->sl.len != nextdb->sl.seq)
206 /* new db required */
207 if ((int32_t)i < 0 || tcp_seq_lt(db->sl.seq + db->sl.len, sl->seq))
208 return _ofo_insert_new(ofo, i + 1, sl, mb, num);
210 /* new one is right adjacent, or overlap */
212 /* new one is completely overlapped by old one */
213 if (tcp_seq_leq(sl->seq + sl->len, db->sl.seq + db->sl.len))
216 /* either overlap OR (adjacent AND some free space remains) */
217 if (tcp_seq_lt(sl->seq, db->sl.seq + db->sl.len) ||
218 db->nb_elem != db->nb_max)
219 return _ofo_insert_right(ofo, i, sl, mb, num, false);
221 /* adjacent, no free space in current block */
222 return _ofo_insert_new(ofo, i + 1, sl, mb, num);
226 _ofo_compact(struct ofo *ofo)
228 uint32_t i, j, k, n, ro;
231 for (i = 0; i < ofo->nb_elem; i++) {
233 for (j = i + 1; j != ofo->nb_elem; j++) {
235 /* no intersection */
236 ro = ofo->db[j].sl.seq - ofo->db[i].sl.seq;
237 if (ro > ofo->db[i].sl.len)
241 n = _ofo_insert_right(ofo, i, &db->sl, db->obj,
243 if (n < db->nb_elem) {
245 for (k = 0; k < db->nb_elem; k++)
246 db->obj[k] = db->obj[n + k];
253 _ofo_remove(ofo, i + 1, n);
257 static inline uint32_t
258 _ofodb_enqueue(struct rte_ring *r, const struct ofodb *db, uint32_t *seq)
260 uint32_t i, n, num, begin, end;
261 struct rte_mbuf *pkt;
269 /* removed overlapped part from db */
270 while (tcp_seq_lt(begin, *seq)) {
271 end = begin + pkt->pkt_len;
272 if (tcp_seq_leq(end, *seq)) {
273 /* pkt is completely overlapped */
275 rte_pktmbuf_free(pkt);
278 /* pkt is partly overlapped */
279 db->obj[i] = _rte_pktmbuf_adj(pkt, *seq - begin);
285 n += _rte_ring_enqueue_burst(r, (void * const *)(db->obj + i), num - i);
287 *seq = db->sl.seq + db->sl.len;
288 *seq -= tcp_mbuf_seq_free(db->obj + n, num - n);
293 tcp_ofo_calc_elems(uint32_t nbufs, uint32_t *nobj, uint32_t *ndb, uint32_t *sz);
296 tcp_ofo_init(struct ofo *ofo, uint32_t nobj, uint32_t ndb);
302 #endif /* _TCP_OFO_H_ */