trex_stateless_capture.cpp revision ac2e93d4
1/*
2 Itay Marom
3 Cisco Systems, Inc.
4*/
5
6/*
7Copyright (c) 2015-2016 Cisco Systems, Inc.
8
9Licensed under the Apache License, Version 2.0 (the "License");
10you may not use this file except in compliance with the License.
11You may obtain a copy of the License at
12
13    http://www.apache.org/licenses/LICENSE-2.0
14
15Unless required by applicable law or agreed to in writing, software
16distributed under the License is distributed on an "AS IS" BASIS,
17WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18See the License for the specific language governing permissions and
19limitations under the License.
20*/
21#include "trex_stateless_capture.h"
22#include "trex_exception.h"
23
24TrexStatelessCapture::TrexStatelessCapture(capture_id_t id, uint64_t limit, const CaptureFilter &filter) {
25    m_id         = id;
26    m_pkt_buffer = new TrexPktBuffer(limit, TrexPktBuffer::MODE_DROP_TAIL);
27    m_filter     = filter;
28    m_state      = STATE_ACTIVE;
29}
30
31TrexStatelessCapture::~TrexStatelessCapture() {
32    if (m_pkt_buffer) {
33        delete m_pkt_buffer;
34    }
35}
36
37void
38TrexStatelessCapture::handle_pkt_tx(const TrexPkt *pkt) {
39
40    if (m_state != STATE_ACTIVE) {
41        delete pkt;
42        return;
43    }
44
45    /* if not in filter - back off */
46    if (!m_filter.in_filter(pkt)) {
47        delete pkt;
48        return;
49    }
50
51    m_pkt_buffer->push(pkt);
52}
53
54void
55TrexStatelessCapture::handle_pkt_rx(const rte_mbuf_t *m, int port) {
56
57    if (m_state != STATE_ACTIVE) {
58        return;
59    }
60
61    if (!m_filter.in_rx(port)) {
62        return;
63    }
64
65    m_pkt_buffer->push(m);
66}
67
68
69Json::Value
70TrexStatelessCapture::to_json() const {
71    Json::Value output = Json::objectValue;
72
73    output["id"]     = Json::UInt64(m_id);
74    output["filter"] = m_filter.to_json();
75    output["count"]  = m_pkt_buffer->get_element_count();
76    output["bytes"]  = m_pkt_buffer->get_bytes();
77    output["limit"]  = m_pkt_buffer->get_capacity();
78
79    switch (m_state) {
80    case STATE_ACTIVE:
81        output["state"]  = "ACTIVE";
82        break;
83
84    case STATE_STOPPED:
85        output["state"]  = "STOPPED";
86        break;
87
88    default:
89        assert(0);
90
91    }
92
93    return output;
94}
95
96TrexPktBuffer *
97TrexStatelessCapture::fetch(uint32_t pkt_limit, uint32_t &pending) {
98
99    /* if the total sum of packets is within the limit range - take it */
100    if (m_pkt_buffer->get_element_count() <= pkt_limit) {
101        TrexPktBuffer *current = m_pkt_buffer;
102        m_pkt_buffer = new TrexPktBuffer(m_pkt_buffer->get_capacity(), m_pkt_buffer->get_mode());
103        pending = 0;
104        return current;
105    }
106
107    /* harder part - partial fetch */
108    TrexPktBuffer *partial = new TrexPktBuffer(pkt_limit);
109    for (int i = 0; i < pkt_limit; i++) {
110        const TrexPkt *pkt = m_pkt_buffer->pop();
111        partial->push(pkt);
112    }
113
114    pending = m_pkt_buffer->get_element_count();
115    return partial;
116}
117
118void
119TrexStatelessCaptureMngr::update_global_filter() {
120    CaptureFilter new_filter;
121
122    for (TrexStatelessCapture *capture : m_captures) {
123        new_filter += capture->get_filter();
124    }
125
126    m_global_filter = new_filter;
127}
128
129TrexStatelessCapture *
130TrexStatelessCaptureMngr::lookup(capture_id_t capture_id) {
131
132    for (int i = 0; i < m_captures.size(); i++) {
133        if (m_captures[i]->get_id() == capture_id) {
134            return m_captures[i];
135        }
136    }
137
138    /* does not exist */
139    return nullptr;
140}
141
142void
143TrexStatelessCaptureMngr::start(const CaptureFilter &filter, uint64_t limit, TrexCaptureRCStart &rc) {
144
145    if (m_captures.size() > MAX_CAPTURE_SIZE) {
146        rc.set_err(TrexCaptureRC::RC_CAPTURE_LIMIT_REACHED);
147        return;
148    }
149
150
151    int new_id = m_id_counter++;
152    TrexStatelessCapture *new_buffer = new TrexStatelessCapture(new_id, limit, filter);
153    m_captures.push_back(new_buffer);
154
155    /* update global filter */
156    update_global_filter();
157
158    /* result */
159    rc.set_new_id(new_id);
160}
161
162void
163TrexStatelessCaptureMngr::stop(capture_id_t capture_id, TrexCaptureRCStop &rc) {
164    TrexStatelessCapture *capture = lookup(capture_id);
165    if (!capture) {
166        rc.set_err(TrexCaptureRC::RC_CAPTURE_NOT_FOUND);
167        return;
168    }
169
170    capture->stop();
171    rc.set_count(capture->get_pkt_count());
172}
173
174void
175TrexStatelessCaptureMngr::fetch(capture_id_t capture_id, uint32_t pkt_limit, TrexCaptureRCFetch &rc) {
176    TrexStatelessCapture *capture = lookup(capture_id);
177    if (!capture) {
178        rc.set_err(TrexCaptureRC::RC_CAPTURE_NOT_FOUND);
179        return;
180    }
181    if (capture->is_active()) {
182        rc.set_err(TrexCaptureRC::RC_CAPTURE_FETCH_UNDER_ACTIVE);
183        return;
184    }
185
186    uint32_t pending = 0;
187    TrexPktBuffer *pkt_buffer = capture->fetch(pkt_limit, pending);
188
189    rc.set_pkt_buffer(pkt_buffer, pending);
190}
191
192void
193TrexStatelessCaptureMngr::remove(capture_id_t capture_id, TrexCaptureRCRemove &rc) {
194
195    int index = -1;
196    for (int i = 0; i < m_captures.size(); i++) {
197        if (m_captures[i]->get_id() == capture_id) {
198            index = i;
199            break;
200        }
201    }
202
203    /* does not exist */
204    if (index == -1) {
205        rc.set_err(TrexCaptureRC::RC_CAPTURE_NOT_FOUND);
206        return;
207    }
208
209    TrexStatelessCapture *capture =  m_captures[index];
210    m_captures.erase(m_captures.begin() + index);
211
212    /* free memory */
213    delete capture;
214
215    /* update global filter */
216    update_global_filter();
217}
218
219void
220TrexStatelessCaptureMngr::reset() {
221    TrexCaptureRCRemove dummy;
222
223    while (m_captures.size() > 0) {
224        remove(m_captures[0]->get_id(), dummy);
225    }
226}
227
228void
229TrexStatelessCaptureMngr::handle_pkt_tx(const TrexPkt *pkt) {
230    for (TrexStatelessCapture *capture : m_captures) {
231        capture->handle_pkt_tx(pkt);
232    }
233}
234
235void
236TrexStatelessCaptureMngr::handle_pkt_rx_slow_path(const rte_mbuf_t *m, int port) {
237    for (TrexStatelessCapture *capture : m_captures) {
238        capture->handle_pkt_rx(m, port);
239    }
240}
241
242Json::Value
243TrexStatelessCaptureMngr::to_json() const {
244    Json::Value lst = Json::arrayValue;
245
246    for (TrexStatelessCapture *capture : m_captures) {
247        lst.append(capture->to_json());
248    }
249
250    return lst;
251}
252
253