1d2f1c845Simarom/*
2d2f1c845Simarom  Itay Marom
3d2f1c845Simarom  Cisco Systems, Inc.
4d2f1c845Simarom*/
5d2f1c845Simarom
6d2f1c845Simarom/*
7d2f1c845Simarom  Copyright (c) 2016-2016 Cisco Systems, Inc.
8d2f1c845Simarom
9d2f1c845Simarom  Licensed under the Apache License, Version 2.0 (the "License");
10d2f1c845Simarom  you may not use this file except in compliance with the License.
11d2f1c845Simarom  You may obtain a copy of the License at
12d2f1c845Simarom
13d2f1c845Simarom  http://www.apache.org/licenses/LICENSE-2.0
14d2f1c845Simarom
15d2f1c845Simarom  Unless required by applicable law or agreed to in writing, software
16d2f1c845Simarom  distributed under the License is distributed on an "AS IS" BASIS,
17d2f1c845Simarom  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18d2f1c845Simarom  See the License for the specific language governing permissions and
19d2f1c845Simarom  limitations under the License.
20d2f1c845Simarom*/
21d2f1c845Simarom
22d2f1c845Simarom#include "trex_stateless_pkt.h"
23d2f1c845Simarom#include <assert.h>
24d2f1c845Simarom
25d2f1c845Simarom
26d2f1c845Simarom/**
27d2f1c845Simarom * copy MBUF to a flat buffer
28d2f1c845Simarom *
29d2f1c845Simarom * @author imarom (12/20/2016)
30d2f1c845Simarom *
31d2f1c845Simarom * @param dest - buffer with at least rte_pktmbuf_pkt_len(m)
32d2f1c845Simarom *               bytes
33d2f1c845Simarom * @param m - MBUF to copy
34d2f1c845Simarom *
35d2f1c845Simarom * @return uint8_t*
36d2f1c845Simarom */
3719df0634Simaromvoid mbuf_to_buffer(uint8_t *dest, const rte_mbuf_t *m) {
38d2f1c845Simarom
39d2f1c845Simarom    int index = 0;
40d2f1c845Simarom    for (const rte_mbuf_t *it = m; it != NULL; it = it->next) {
41d2f1c845Simarom        const uint8_t *src = rte_pktmbuf_mtod(it, const uint8_t *);
42d2f1c845Simarom        memcpy(dest + index, src, it->data_len);
43d2f1c845Simarom        index += it->data_len;
44d2f1c845Simarom    }
45d2f1c845Simarom}
46d2f1c845Simarom
47d2f1c845Simarom/**************************************
48d2f1c845Simarom * TRex packet
49d2f1c845Simarom *
50d2f1c845Simarom *************************************/
51d2f1c845SimaromTrexPkt::TrexPkt(const rte_mbuf_t *m, int port, origin_e origin, uint64_t index) {
52d2f1c845Simarom
53d2f1c845Simarom    /* allocate buffer */
54d2f1c845Simarom    m_size = m->pkt_len;
55d2f1c845Simarom    m_raw = new uint8_t[m_size];
56d2f1c845Simarom
57d2f1c845Simarom    /* copy data */
5819df0634Simarom    mbuf_to_buffer(m_raw, m);
59d2f1c845Simarom
60d2f1c845Simarom    /* generate a packet timestamp */
61d2f1c845Simarom    m_timestamp = now_sec();
62d2f1c845Simarom
63d2f1c845Simarom    m_port   = port;
64d2f1c845Simarom    m_origin = origin;
65d2f1c845Simarom    m_index  = index;
66d2f1c845Simarom}
67d2f1c845Simarom
68d2f1c845SimaromTrexPkt::TrexPkt(const TrexPkt &other) {
69d2f1c845Simarom    m_size = other.m_size;
70d2f1c845Simarom    memcpy(m_raw, other.m_raw, m_size);
71d2f1c845Simarom
72d2f1c845Simarom    m_timestamp = other.m_timestamp;
73d2f1c845Simarom
74d2f1c845Simarom    m_port   = other.m_port;
75d2f1c845Simarom    m_origin = other.m_origin;
76d2f1c845Simarom    m_index  = other.m_index;
77d2f1c845Simarom}
78d2f1c845Simarom
7919df0634Simarom
8019df0634Simarom/**************************************
8119df0634Simarom * TRex packet buffer
8219df0634Simarom *
8319df0634Simarom *************************************/
8419df0634Simarom
85d2f1c845SimaromTrexPktBuffer::TrexPktBuffer(uint64_t size, mode_e mode) {
86d2f1c845Simarom    m_mode             = mode;
87d2f1c845Simarom    m_buffer           = nullptr;
88d2f1c845Simarom    m_head             = 0;
89d2f1c845Simarom    m_tail             = 0;
90d2f1c845Simarom    m_bytes            = 0;
91d2f1c845Simarom    m_size             = (size + 1); // for the empty/full difference 1 slot reserved
92d2f1c845Simarom
93d2f1c845Simarom    /* generate queue */
94d2f1c845Simarom    m_buffer = new const TrexPkt*[m_size](); // zeroed
95d2f1c845Simarom}
96d2f1c845Simarom
97d2f1c845SimaromTrexPktBuffer::~TrexPktBuffer() {
98d2f1c845Simarom    assert(m_buffer);
99d2f1c845Simarom
100d2f1c845Simarom    while (!is_empty()) {
101d2f1c845Simarom        const TrexPkt *pkt = pop();
102d2f1c845Simarom        delete pkt;
103d2f1c845Simarom    }
104d2f1c845Simarom    delete [] m_buffer;
105d2f1c845Simarom}
106d2f1c845Simarom
107d2f1c845Simarom/**
108d2f1c845Simarom * packet will be copied to an internal object
109d2f1c845Simarom */
110d2f1c845Simaromvoid
111d2f1c845SimaromTrexPktBuffer::push(const rte_mbuf_t *m, int port, TrexPkt::origin_e origin, uint64_t pkt_index) {
112d2f1c845Simarom
113d2f1c845Simarom    /* if full - decide by the policy */
114d2f1c845Simarom    if (is_full()) {
115d2f1c845Simarom        if (m_mode == MODE_DROP_HEAD) {
116d2f1c845Simarom            delete pop();
117d2f1c845Simarom        } else {
118d2f1c845Simarom            /* drop the tail (current packet) */
119d2f1c845Simarom            return;
120d2f1c845Simarom        }
121d2f1c845Simarom    }
122d2f1c845Simarom
1233689edf3Simarom    push_internal(new TrexPkt(m, port, origin, pkt_index));
124d2f1c845Simarom}
125d2f1c845Simarom
126d2f1c845Simarom/**
127d2f1c845Simarom * packet will be handled internally
12819df0634Simarom * packet pointer is invalid after this call
129d2f1c845Simarom */
130d2f1c845Simaromvoid
1313689edf3SimaromTrexPktBuffer::push(const TrexPkt *pkt, uint64_t pkt_index) {
132d2f1c845Simarom    /* if full - decide by the policy */
133d2f1c845Simarom    if (is_full()) {
134d2f1c845Simarom        if (m_mode == MODE_DROP_HEAD) {
135d2f1c845Simarom            delete pop();
136d2f1c845Simarom        } else {
137d2f1c845Simarom            /* drop the tail (current packet) */
138d2f1c845Simarom            return;
139d2f1c845Simarom        }
140d2f1c845Simarom    }
141d2f1c845Simarom
1423689edf3Simarom    /* duplicate packet */
1433689edf3Simarom    TrexPkt *dup = new TrexPkt(*pkt);
1443689edf3Simarom
1453689edf3Simarom    /* update packet index if given */
1463689edf3Simarom    if (pkt_index != 0) {
1473689edf3Simarom        dup->set_index(pkt_index);
1483689edf3Simarom    }
1493689edf3Simarom
1503689edf3Simarom    push_internal(dup);
1513689edf3Simarom}
1523689edf3Simarom
1533689edf3Simarom
1543689edf3Simaromvoid
1553689edf3SimaromTrexPktBuffer::push_internal(const TrexPkt *pkt) {
1563689edf3Simarom    /* push the packet */
157d2f1c845Simarom    m_buffer[m_head] = pkt;
15819df0634Simarom    m_bytes += pkt->get_size();
15919df0634Simarom
160d2f1c845Simarom    m_head = next(m_head);
161d2f1c845Simarom}
162d2f1c845Simarom
163d2f1c845Simaromconst TrexPkt *
164d2f1c845SimaromTrexPktBuffer::pop() {
165d2f1c845Simarom    assert(!is_empty());
166d2f1c845Simarom
167d2f1c845Simarom    const TrexPkt *pkt = m_buffer[m_tail];
168d2f1c845Simarom    m_tail = next(m_tail);
169d2f1c845Simarom
170d2f1c845Simarom    m_bytes -= pkt->get_size();
171d2f1c845Simarom
172d2f1c845Simarom    return pkt;
173d2f1c845Simarom}
174d2f1c845Simarom
175d2f1c845Simaromuint32_t
176d2f1c845SimaromTrexPktBuffer::get_element_count() const {
177d2f1c845Simarom    if (m_head >= m_tail) {
178d2f1c845Simarom        return (m_head - m_tail);
179d2f1c845Simarom    } else {
180d2f1c845Simarom        return ( get_capacity() - (m_tail - m_head - 1) );
181d2f1c845Simarom    }
182d2f1c845Simarom}
183d2f1c845Simarom
184d2f1c845SimaromJson::Value
185d2f1c845SimaromTrexPktBuffer::to_json() const {
186d2f1c845Simarom
187d2f1c845Simarom    Json::Value output = Json::arrayValue;
188d2f1c845Simarom
189d2f1c845Simarom    int tmp = m_tail;
190d2f1c845Simarom    while (tmp != m_head) {
191d2f1c845Simarom        const TrexPkt *pkt = m_buffer[tmp];
192d2f1c845Simarom        output.append(pkt->to_json());
193d2f1c845Simarom        tmp = next(tmp);
194d2f1c845Simarom    }
195d2f1c845Simarom
196d2f1c845Simarom    return output;
197d2f1c845Simarom}
198d2f1c845Simarom
1993689edf3SimaromTrexPktBuffer *
2003689edf3SimaromTrexPktBuffer::pop_n(uint32_t count) {
2013689edf3Simarom    /* can't pop more than total */
2023689edf3Simarom    assert(count <= get_element_count());
2033689edf3Simarom
2043689edf3Simarom    // TODO: consider returning NULL if no packets exists
2053689edf3Simarom    //       to avoid mallocing
2063689edf3Simarom
2073689edf3Simarom    TrexPktBuffer *partial = new TrexPktBuffer(count);
2083689edf3Simarom
2093689edf3Simarom    for (int i = 0; i < count; i++) {
2103689edf3Simarom        const TrexPkt *pkt = pop();
2113689edf3Simarom        partial->push_internal(pkt);
2123689edf3Simarom    }
2133689edf3Simarom
2143689edf3Simarom    return partial;
2153689edf3Simarom}
216