trex_stateless_rx_port_mngr.cpp revision 0fdd81a9
1/*
2  Itay Marom
3  Cisco Systems, Inc.
4*/
5
6/*
7  Copyright (c) 2016-2016 Cisco Systems, Inc.
8
9  Licensed under the Apache License, Version 2.0 (the "License");
10  you may not use this file except in compliance with the License.
11  You may obtain a copy of the License at
12
13  http://www.apache.org/licenses/LICENSE-2.0
14
15  Unless required by applicable law or agreed to in writing, software
16  distributed under the License is distributed on an "AS IS" BASIS,
17  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  See the License for the specific language governing permissions and
19  limitations under the License.
20*/
21#include "bp_sim.h"
22#include "trex_stateless_rx_port_mngr.h"
23#include "common/captureFile.h"
24#include "trex_stateless_rx_core.h"
25#include "common/Network/Packet/Arp.h"
26#include "pkt_gen.h"
27
28/**************************************
29 * latency RX feature
30 *
31 *************************************/
32RXLatency::RXLatency() {
33    m_rcv_all    = false;
34    m_rfc2544    = NULL;
35    m_err_cntrs  = NULL;
36
37    for (int i = 0; i < MAX_FLOW_STATS; i++) {
38        m_rx_pg_stat[i].clear();
39        m_rx_pg_stat_payload[i].clear();
40    }
41}
42
43void
44RXLatency::create(CRFC2544Info *rfc2544, CRxCoreErrCntrs *err_cntrs) {
45    m_rfc2544   = rfc2544;
46    m_err_cntrs = err_cntrs;
47}
48
49void
50RXLatency::handle_pkt(const rte_mbuf_t *m) {
51    CFlowStatParser parser;
52
53    if (m_rcv_all || parser.parse(rte_pktmbuf_mtod(m, uint8_t *), m->pkt_len) == 0) {
54        uint32_t ip_id;
55        if (m_rcv_all || (parser.get_ip_id(ip_id) == 0)) {
56            if (m_rcv_all || is_flow_stat_id(ip_id)) {
57                uint16_t hw_id;
58                if (m_rcv_all || is_flow_stat_payload_id(ip_id)) {
59                    bool good_packet = true;
60                    uint8_t *p = rte_pktmbuf_mtod(m, uint8_t*);
61                    struct flow_stat_payload_header *fsp_head = (struct flow_stat_payload_header *)
62                        (p + m->pkt_len - sizeof(struct flow_stat_payload_header));
63                    hw_id = fsp_head->hw_id;
64                    CRFC2544Info *curr_rfc2544;
65
66                    if (unlikely(fsp_head->magic != FLOW_STAT_PAYLOAD_MAGIC) || hw_id >= MAX_FLOW_STATS_PAYLOAD) {
67                        good_packet = false;
68                        if (!m_rcv_all)
69                            m_err_cntrs->m_bad_header++;
70                    } else {
71                        curr_rfc2544 = &m_rfc2544[hw_id];
72
73                        if (fsp_head->flow_seq != curr_rfc2544->get_exp_flow_seq()) {
74                            // bad flow seq num
75                            // Might be the first packet of a new flow, packet from an old flow, or garbage.
76
77                            if (fsp_head->flow_seq == curr_rfc2544->get_prev_flow_seq()) {
78                                // packet from previous flow using this hw_id that arrived late
79                                good_packet = false;
80                                m_err_cntrs->m_old_flow++;
81                            } else {
82                                if (curr_rfc2544->no_flow_seq()) {
83                                    // first packet we see from this flow
84                                    good_packet = true;
85                                    curr_rfc2544->set_exp_flow_seq(fsp_head->flow_seq);
86                                } else {
87                                    // garbage packet
88                                    good_packet = false;
89                                    m_err_cntrs->m_bad_header++;
90                                }
91                            }
92                        }
93                    }
94
95                    if (good_packet) {
96                        uint32_t pkt_seq = fsp_head->seq;
97                        uint32_t exp_seq = curr_rfc2544->get_seq();
98                        if (unlikely(pkt_seq != exp_seq)) {
99                            if (pkt_seq < exp_seq) {
100                                if (exp_seq - pkt_seq > 100000) {
101                                    // packet loss while we had wrap around
102                                    curr_rfc2544->inc_seq_err(pkt_seq - exp_seq);
103                                    curr_rfc2544->inc_seq_err_too_big();
104                                    curr_rfc2544->set_seq(pkt_seq + 1);
105                                } else {
106                                    if (pkt_seq == (exp_seq - 1)) {
107                                        curr_rfc2544->inc_dup();
108                                    } else {
109                                        curr_rfc2544->inc_ooo();
110                                        // We thought it was lost, but it was just out of order
111                                        curr_rfc2544->dec_seq_err();
112                                    }
113                                    curr_rfc2544->inc_seq_err_too_low();
114                                }
115                            } else {
116                                if (unlikely (pkt_seq - exp_seq > 100000)) {
117                                    // packet reorder while we had wrap around
118                                    if (pkt_seq == (exp_seq - 1)) {
119                                        curr_rfc2544->inc_dup();
120                                    } else {
121                                        curr_rfc2544->inc_ooo();
122                                        // We thought it was lost, but it was just out of order
123                                        curr_rfc2544->dec_seq_err();
124                                    }
125                                    curr_rfc2544->inc_seq_err_too_low();
126                                } else {
127                                // seq > curr_rfc2544->seq. Assuming lost packets
128                                    curr_rfc2544->inc_seq_err(pkt_seq - exp_seq);
129                                    curr_rfc2544->inc_seq_err_too_big();
130                                    curr_rfc2544->set_seq(pkt_seq + 1);
131                                }
132                            }
133                        } else {
134                            curr_rfc2544->set_seq(pkt_seq + 1);
135                        }
136                        m_rx_pg_stat_payload[hw_id].add_pkts(1);
137                        m_rx_pg_stat_payload[hw_id].add_bytes(m->pkt_len + 4); // +4 for ethernet CRC
138                        uint64_t d = (os_get_hr_tick_64() - fsp_head->time_stamp );
139                        dsec_t ctime = ptime_convert_hr_dsec(d);
140                        curr_rfc2544->add_sample(ctime);
141                    }
142                } else {
143                    hw_id = get_hw_id(ip_id);
144                    if (hw_id < MAX_FLOW_STATS) {
145                        m_rx_pg_stat[hw_id].add_pkts(1);
146                        m_rx_pg_stat[hw_id].add_bytes(m->pkt_len + 4); // +4 for ethernet CRC
147                    }
148                }
149            }
150        }
151    }
152}
153
154void
155RXLatency::reset_stats() {
156    for (int hw_id = 0; hw_id < MAX_FLOW_STATS; hw_id++) {
157        m_rx_pg_stat[hw_id].clear();
158    }
159}
160
161
162void
163RXLatency::get_stats(rx_per_flow_t *rx_stats,
164                     int min,
165                     int max,
166                     bool reset,
167                     TrexPlatformApi::driver_stat_cap_e type) {
168
169    for (int hw_id = min; hw_id <= max; hw_id++) {
170        if (type == TrexPlatformApi::IF_STAT_PAYLOAD) {
171            rx_stats[hw_id - min] = m_rx_pg_stat_payload[hw_id];
172        } else {
173            rx_stats[hw_id - min] = m_rx_pg_stat[hw_id];
174        }
175        if (reset) {
176            if (type == TrexPlatformApi::IF_STAT_PAYLOAD) {
177                m_rx_pg_stat_payload[hw_id].clear();
178            } else {
179                m_rx_pg_stat[hw_id].clear();
180            }
181        }
182    }
183}
184
185
186Json::Value
187RXLatency::to_json() const {
188    return Json::objectValue;
189}
190
191/**************************************
192 * RX feature queue
193 *
194 *************************************/
195
196RXPacketBuffer::RXPacketBuffer(uint64_t size) {
197    m_buffer           = nullptr;
198    m_head             = 0;
199    m_tail             = 0;
200    m_size             = (size + 1); // for the empty/full difference 1 slot reserved
201
202    /* generate queue */
203    m_buffer = new RXPacket*[m_size](); // zeroed
204}
205
206RXPacketBuffer::~RXPacketBuffer() {
207    assert(m_buffer);
208
209    while (!is_empty()) {
210        RXPacket *pkt = pop();
211        delete pkt;
212    }
213    delete [] m_buffer;
214}
215
216void
217RXPacketBuffer::push(const rte_mbuf_t *m) {
218    /* if full - pop the oldest */
219    if (is_full()) {
220        delete pop();
221    }
222
223    /* push packet */
224    m_buffer[m_head] = new RXPacket(m);
225    m_head = next(m_head);
226}
227
228RXPacket *
229RXPacketBuffer::pop() {
230    assert(!is_empty());
231
232    RXPacket *pkt = m_buffer[m_tail];
233    m_tail = next(m_tail);
234
235    return pkt;
236}
237
238uint64_t
239RXPacketBuffer::get_element_count() const {
240    if (m_head >= m_tail) {
241        return (m_head - m_tail);
242    } else {
243        return ( get_capacity() - (m_tail - m_head - 1) );
244    }
245}
246
247Json::Value
248RXPacketBuffer::to_json() const {
249
250    Json::Value output = Json::arrayValue;
251
252    int tmp = m_tail;
253    while (tmp != m_head) {
254        RXPacket *pkt = m_buffer[tmp];
255        output.append(pkt->to_json());
256        tmp = next(tmp);
257    }
258
259    return output;
260}
261
262
263void
264RXQueue::start(uint64_t size) {
265    if (m_pkt_buffer) {
266        delete m_pkt_buffer;
267    }
268    m_pkt_buffer = new RXPacketBuffer(size);
269}
270
271void
272RXQueue::stop() {
273    if (m_pkt_buffer) {
274        delete m_pkt_buffer;
275        m_pkt_buffer = NULL;
276    }
277}
278
279const RXPacketBuffer *
280RXQueue::fetch() {
281
282    /* if no buffer or the buffer is empty - give a NULL one */
283    if ( (!m_pkt_buffer) || (m_pkt_buffer->get_element_count() == 0) ) {
284        return nullptr;
285    }
286
287    /* hold a pointer to the old one */
288    RXPacketBuffer *old_buffer = m_pkt_buffer;
289
290    /* replace the old one with a new one and freeze the old */
291    m_pkt_buffer = new RXPacketBuffer(old_buffer->get_capacity());
292
293    return old_buffer;
294}
295
296void
297RXQueue::handle_pkt(const rte_mbuf_t *m) {
298    m_pkt_buffer->push(m);
299}
300
301Json::Value
302RXQueue::to_json() const {
303    assert(m_pkt_buffer != NULL);
304
305    Json::Value output = Json::objectValue;
306
307    output["size"]    = Json::UInt64(m_pkt_buffer->get_capacity());
308    output["count"]   = Json::UInt64(m_pkt_buffer->get_element_count());
309
310    return output;
311}
312
313/**************************************
314 * RX feature recorder
315 *
316 *************************************/
317
318RXPacketRecorder::RXPacketRecorder() {
319    m_writer = NULL;
320    m_count  = 0;
321    m_limit  = 0;
322    m_epoch  = -1;
323
324    m_pending_flush = false;
325}
326
327void
328RXPacketRecorder::start(const std::string &pcap, uint64_t limit) {
329    m_writer = CCapWriterFactory::CreateWriter(LIBPCAP, (char *)pcap.c_str());
330    if (m_writer == NULL) {
331        std::stringstream ss;
332        ss << "unable to create PCAP file: " << pcap;
333        throw TrexException(ss.str());
334    }
335
336    assert(limit > 0);
337
338    m_limit = limit;
339    m_count = 0;
340    m_pending_flush = false;
341    m_pcap_filename = pcap;
342}
343
344void
345RXPacketRecorder::stop() {
346    if (!m_writer) {
347        return;
348    }
349
350    delete m_writer;
351    m_writer = NULL;
352}
353
354void
355RXPacketRecorder::flush_to_disk() {
356
357    if (m_writer && m_pending_flush) {
358        m_writer->flush_to_disk();
359        m_pending_flush = false;
360    }
361}
362
363void
364RXPacketRecorder::handle_pkt(const rte_mbuf_t *m) {
365    if (!m_writer) {
366        return;
367    }
368
369    dsec_t now = now_sec();
370    if (m_epoch < 0) {
371        m_epoch = now;
372    }
373
374    dsec_t dt = now - m_epoch;
375
376    CPktNsecTimeStamp t_c(dt);
377    m_pkt.time_nsec = t_c.m_time_nsec;
378    m_pkt.time_sec  = t_c.m_time_sec;
379
380    const uint8_t *p = rte_pktmbuf_mtod(m, uint8_t *);
381    m_pkt.pkt_len = m->pkt_len;
382    memcpy(m_pkt.raw, p, m->pkt_len);
383
384    m_writer->write_packet(&m_pkt);
385    m_count++;
386    m_pending_flush = true;
387
388    if (m_count == m_limit) {
389        stop();
390    }
391
392}
393
394Json::Value
395RXPacketRecorder::to_json() const {
396    Json::Value output = Json::objectValue;
397
398    output["pcap_filename"] = m_pcap_filename;
399    output["limit"]         = Json::UInt64(m_limit);
400    output["count"]         = Json::UInt64(m_count);
401
402    return output;
403}
404
405
406/**************************************
407 * RX feature server (ARP, ICMP) and etc.
408 *
409 *************************************/
410
411class RXPktParser {
412public:
413    RXPktParser(const rte_mbuf_t *m) {
414
415        m_mbuf = m;
416
417        /* start point */
418        m_current   = rte_pktmbuf_mtod(m, uint8_t *);;
419        m_size_left = rte_pktmbuf_pkt_len(m);
420
421        m_ether    = NULL;
422        m_arp      = NULL;
423        m_ipv4     = NULL;
424        m_icmp     = NULL;
425        m_vlan_tag = 0;
426
427        /* ethernet */
428        m_ether = (EthernetHeader *)parse_bytes(14);
429
430        uint16_t next_proto;
431        if (m_ether->getNextProtocol() == EthernetHeader::Protocol::VLAN) {
432            parse_bytes(4);
433            m_vlan_tag = m_ether->getVlanTag();
434            next_proto = m_ether->getVlanProtocol();
435        } else {
436            next_proto = m_ether->getNextProtocol();
437        }
438
439        /**
440         * support only for ARP or IPv4 based protocols
441         */
442        switch (next_proto) {
443        case EthernetHeader::Protocol::ARP:
444            parse_arp();
445            return;
446
447        case EthernetHeader::Protocol::IP:
448            parse_ipv4();
449            return;
450
451        default:
452            return;
453        }
454
455    }
456
457    const rte_mbuf_t *m_mbuf;
458    EthernetHeader   *m_ether;
459    ArpHdr           *m_arp;
460    IPHeader         *m_ipv4;
461    ICMPHeader       *m_icmp;
462    uint16_t          m_vlan_tag;
463
464protected:
465
466    const uint8_t *parse_bytes(uint32_t size) {
467        if (m_size_left < size) {
468            parse_err();
469        }
470
471        const uint8_t *p = m_current;
472        m_current    += size;
473        m_size_left  -= size;
474
475        return p;
476    }
477
478    void parse_arp() {
479        m_arp = (ArpHdr *)parse_bytes(sizeof(ArpHdr));
480    }
481
482    void parse_ipv4() {
483        m_ipv4 = (IPHeader *)parse_bytes(IPHeader::DefaultSize);
484
485        /* advance over IP options if exists */
486        parse_bytes(m_ipv4->getOptionLen());
487
488        switch (m_ipv4->getNextProtocol()) {
489        case IPHeader::Protocol::ICMP:
490            parse_icmp();
491            return;
492
493        default:
494            return;
495        }
496    }
497
498    void parse_icmp() {
499        m_icmp = (ICMPHeader *)parse_bytes(sizeof(ICMPHeader));
500    }
501
502    void parse_err() {
503        throw TrexException(TrexException::T_RX_PKT_PARSE_ERR);
504    }
505
506    const uint8_t *m_current;
507    uint16_t       m_size_left;
508};
509
510RXServer::RXServer() {
511    m_io        = NULL;
512    m_src_addr  = NULL;
513    m_port_id   = 255;
514}
515
516void
517RXServer::create(uint8_t port_id, CPortLatencyHWBase *io, const CManyIPInfo *src_addr) {
518    m_port_id  = port_id;
519    m_io       = io;
520    m_src_addr = src_addr;
521}
522
523
524void
525RXServer::handle_pkt(const rte_mbuf_t *m) {
526
527    RXPktParser parser(m);
528
529    if (parser.m_icmp) {
530        handle_icmp(parser);
531    } else if (parser.m_arp) {
532        handle_arp(parser);
533    } else {
534        return;
535    }
536
537}
538void
539RXServer::handle_icmp(RXPktParser &parser) {
540
541    /* maybe not for us... */
542    if (!m_src_addr->exists(parser.m_ipv4->getDestIp())) {
543        return;
544    }
545
546    /* we handle only echo request */
547    if (parser.m_icmp->getType() != ICMPHeader::TYPE_ECHO_REQUEST) {
548        return;
549    }
550
551    /* duplicate the MBUF */
552    rte_mbuf_t *response = duplicate_mbuf(parser.m_mbuf);
553    if (!response) {
554        return;
555    }
556
557    /* reparse the cloned packet */
558    RXPktParser response_parser(response);
559
560    /* swap MAC */
561    MacAddress tmp = response_parser.m_ether->mySource;
562    response_parser.m_ether->mySource = response_parser.m_ether->myDestination;
563    response_parser.m_ether->myDestination = tmp;
564
565    /* swap IP */
566    std::swap(response_parser.m_ipv4->mySource, response_parser.m_ipv4->myDestination);
567
568    /* new packet - new TTL */
569    response_parser.m_ipv4->setTimeToLive(128);
570    response_parser.m_ipv4->updateCheckSum();
571
572    /* update type and fix checksum */
573    response_parser.m_icmp->setType(ICMPHeader::TYPE_ECHO_REPLY);
574    response_parser.m_icmp->updateCheckSum(response_parser.m_ipv4->getTotalLength() - response_parser.m_ipv4->getHeaderLength());
575
576    /* send */
577    m_io->tx(response);
578}
579
580void
581RXServer::handle_arp(RXPktParser &parser) {
582    MacAddress src_mac;
583
584    /* only ethernet format supported */
585    if (parser.m_arp->getHrdType() != ArpHdr::ARP_HDR_HRD_ETHER) {
586        return;
587    }
588
589    /* IPV4 only */
590    if (parser.m_arp->getProtocolType() != ArpHdr::ARP_HDR_PROTO_IPV4) {
591        return;
592    }
593
594    /* support only for ARP request */
595    if (parser.m_arp->getOp() != ArpHdr::ARP_HDR_OP_REQUEST) {
596        return;
597    }
598
599    /* are we the target ? if not - go home */
600    if (!m_src_addr->lookup(parser.m_arp->getTip(), 0, src_mac)) {
601        return;
602    }
603
604    /* duplicate the MBUF */
605    rte_mbuf_t *response = duplicate_mbuf(parser.m_mbuf);
606    if (!response) {
607        return;
608    }
609
610    /* reparse the cloned packet */
611    RXPktParser response_parser(response);
612
613    /* reply */
614    response_parser.m_arp->setOp(ArpHdr::ARP_HDR_OP_REPLY);
615
616    /* fix the MAC addresses */
617    response_parser.m_ether->mySource = src_mac;
618    response_parser.m_ether->myDestination = parser.m_ether->mySource;
619
620    /* fill up the fields */
621
622    /* src */
623    response_parser.m_arp->m_arp_sha = src_mac;
624    response_parser.m_arp->setSip(parser.m_arp->getTip());
625
626    /* dst */
627    response_parser.m_arp->m_arp_tha = parser.m_arp->m_arp_sha;
628    response_parser.m_arp->m_arp_tip = parser.m_arp->m_arp_sip;
629
630    /* send */
631    m_io->tx(response);
632
633}
634
635rte_mbuf_t *
636RXServer::duplicate_mbuf(const rte_mbuf_t *m) {
637    /* RX packets should always be one segment */
638    assert(m->nb_segs == 1);
639
640    /* allocate */
641    rte_mbuf_t *clone_mbuf = CGlobalInfo::pktmbuf_alloc_by_port(m_port_id, rte_pktmbuf_pkt_len(m));
642    if (!clone_mbuf) {
643        return NULL;
644    }
645
646    /* append data */
647    uint8_t *dest = (uint8_t *)rte_pktmbuf_append(clone_mbuf, rte_pktmbuf_pkt_len(m));
648    if (!dest) {
649        return NULL;
650    }
651
652    /* copy data */
653    const uint8_t *src = rte_pktmbuf_mtod(m, const uint8_t *);
654    memcpy(dest, src, rte_pktmbuf_pkt_len(m));
655
656    return clone_mbuf;
657}
658
659/**************************************
660 * Gratidious ARP
661 *
662 *************************************/
663void
664RXGratARP::create(uint8_t port_id,
665                  CPortLatencyHWBase *io,
666                  CManyIPInfo *src_addr,
667                  CRXCoreIgnoreStat *ign_stats) {
668
669    m_port_id     = port_id;
670    m_io          = io;
671    m_src_addr    = src_addr;
672    m_ign_stats   = ign_stats;
673}
674
675void
676RXGratARP::send_next_grat_arp() {
677    uint8_t src_mac[ETHER_ADDR_LEN];
678
679    const COneIPInfo *ip_info = m_src_addr->get_next_loop();
680    if (!ip_info) {
681        return;
682    }
683
684    rte_mbuf_t *m = CGlobalInfo::pktmbuf_alloc_small(CGlobalInfo::m_socket.port_to_socket(m_port_id));
685    assert(m);
686
687    uint8_t *p = (uint8_t *)rte_pktmbuf_append(m, ip_info->get_grat_arp_len());
688    ip_info->get_mac(src_mac);
689    uint16_t vlan = ip_info->get_vlan();
690
691    /* for now only IPv4 */
692    assert(ip_info->ip_ver() == COneIPInfo::IP4_VER);
693    uint32_t sip = ((COneIPv4Info *)ip_info)->get_ip();
694
695    CTestPktGen::create_arp_req(p, sip, sip, src_mac, vlan, m_port_id);
696
697    if (m_io->tx(m) == 0) {
698        m_ign_stats->m_tx_arp    += 1;
699        m_ign_stats->m_tot_bytes += 64;
700    }
701
702}
703
704Json::Value
705RXGratARP::to_json() const {
706    Json::Value output = Json::objectValue;
707    output["interval_sec"] = (double)CGlobalInfo::m_options.m_arp_ref_per;
708
709    return output;
710}
711
712/**************************************
713 * Port manager
714 *
715 *************************************/
716
717RXPortManager::RXPortManager() {
718    clear_all_features();
719    m_io          = NULL;
720    m_cpu_dp_u    = NULL;
721    m_port_id     = UINT8_MAX;
722}
723
724
725void
726RXPortManager::create(const TRexPortAttr *port_attr,
727                      CPortLatencyHWBase *io,
728                      CRFC2544Info *rfc2544,
729                      CRxCoreErrCntrs *err_cntrs,
730                      CCpuUtlDp *cpu_util,
731                      uint8_t crc_bytes_num) {
732
733    m_port_id = port_attr->get_port_id();
734    m_io = io;
735    m_cpu_dp_u = cpu_util;
736    m_num_crc_fix_bytes = crc_bytes_num;
737
738    /* if IPv4 is configured - add it to the grat service */
739    uint32_t src_ipv4 = port_attr->get_src_ipv4();
740    if (src_ipv4) {
741        m_src_addr.insert(COneIPv4Info(src_ipv4, 0, port_attr->get_src_mac(), m_port_id));
742    }
743
744    /* init features */
745    m_latency.create(rfc2544, err_cntrs);
746    m_server.create(m_port_id, io, &m_src_addr);
747    m_grat_arp.create(m_port_id, io, &m_src_addr, &m_ign_stats);
748
749    /* by default, server is always on */
750    set_feature(SERVER);
751}
752
753void RXPortManager::handle_pkt(const rte_mbuf_t *m) {
754
755    /* handle features */
756
757    if (is_feature_set(LATENCY)) {
758        m_latency.handle_pkt(m);
759    }
760
761    if (is_feature_set(RECORDER)) {
762        m_recorder.handle_pkt(m);
763    }
764
765    if (is_feature_set(QUEUE)) {
766        m_queue.handle_pkt(m);
767    }
768
769    if (is_feature_set(SERVER)) {
770        m_server.handle_pkt(m);
771    }
772}
773
774int RXPortManager::process_all_pending_pkts(bool flush_rx) {
775
776    rte_mbuf_t *rx_pkts[64];
777
778    /* try to read 64 packets clean up the queue */
779    uint16_t cnt_p = m_io->rx_burst(rx_pkts, 64);
780    if (cnt_p == 0) {
781        return cnt_p;
782    }
783
784
785    m_cpu_dp_u->start_work1();
786
787    for (int j = 0; j < cnt_p; j++) {
788        rte_mbuf_t *m = rx_pkts[j];
789
790        if (!flush_rx) {
791            // patch relevant only for e1000 driver
792            if (m_num_crc_fix_bytes) {
793                rte_pktmbuf_trim(m, m_num_crc_fix_bytes);
794            }
795
796            handle_pkt(m);
797        }
798
799        rte_pktmbuf_free(m);
800    }
801
802    /* commit only if there was work to do ! */
803    m_cpu_dp_u->commit1();
804
805
806    return cnt_p;
807}
808
809void
810RXPortManager::tick() {
811    if (is_feature_set(RECORDER)) {
812        m_recorder.flush_to_disk();
813    }
814}
815
816void
817RXPortManager::send_next_grat_arp() {
818    if (is_feature_set(GRAT_ARP)) {
819        m_grat_arp.send_next_grat_arp();
820    }
821}
822
823
824void
825RXPortManager::set_l2_mode() {
826
827    /* no IPv4 addresses */
828    m_src_addr.clear();
829
830    /* stop grat arp */
831    stop_grat_arp();
832}
833
834void
835RXPortManager::set_l3_mode(const CManyIPInfo &ip_info, bool is_grat_arp_needed) {
836
837    /* copy L3 address */
838    m_src_addr = ip_info;
839
840    if (is_grat_arp_needed) {
841        start_grat_arp();
842    }
843    else {
844        stop_grat_arp();
845    }
846
847}
848
849
850
851Json::Value
852RXPortManager::to_json() const {
853    Json::Value output = Json::objectValue;
854
855    if (is_feature_set(LATENCY)) {
856        output["latency"] = m_latency.to_json();
857        output["latency"]["is_active"] = true;
858    } else {
859        output["latency"]["is_active"] = false;
860    }
861
862    if (is_feature_set(RECORDER)) {
863        output["sniffer"] = m_recorder.to_json();
864        output["sniffer"]["is_active"] = true;
865    } else {
866        output["sniffer"]["is_active"] = false;
867    }
868
869    if (is_feature_set(QUEUE)) {
870        output["queue"] = m_queue.to_json();
871        output["queue"]["is_active"] = true;
872    } else {
873        output["queue"]["is_active"] = false;
874    }
875
876    if (is_feature_set(GRAT_ARP)) {
877        output["grat_arp"] = m_grat_arp.to_json();
878        output["grat_arp"]["is_active"] = true;
879    } else {
880        output["grat_arp"]["is_active"] = false;
881    }
882
883    return output;
884}
885
886
887void RXPortManager::get_ignore_stats(CRXCoreIgnoreStat &stat, bool get_diff) {
888    if (get_diff) {
889        stat = m_ign_stats - m_ign_stats_prev;
890        m_ign_stats_prev = m_ign_stats;
891    } else {
892        stat = m_ign_stats;
893    }
894}
895
896