stateful_rx_core.cpp revision 511a6dac
1/*
2 Hanoh Haim
3 Ido Barnea
4 Cisco Systems, Inc.
5*/
6
7/*
8Copyright (c) 2015-2016 Cisco Systems, Inc.
9
10Licensed under the Apache License, Version 2.0 (the "License");
11you may not use this file except in compliance with the License.
12You may obtain a copy of the License at
13
14    http://www.apache.org/licenses/LICENSE-2.0
15
16Unless required by applicable law or agreed to in writing, software
17distributed under the License is distributed on an "AS IS" BASIS,
18WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19See the License for the specific language governing permissions and
20limitations under the License.
21*/
22#include "bp_sim.h"
23#include "flow_stat_parser.h"
24#include "utl_json.h"
25#include "trex_watchdog.h"
26#include "pkt_gen.h"
27#include "common/basic_utils.h"
28#include "stateful_rx_core.h"
29
30const uint8_t sctp_pkt[]={
31
32    0x00,0x04,0x96,0x08,0xe0,0x40,
33    0x00,0x0e,0x2e,0x24,0x37,0x5f,
34    0x08,0x00,
35
36    0x45,0x03,0x00,0x30,
37    0x00,0x00,0x40,0x00,
38    0xff,0x84,0xbd,0x04,
39    0x9b,0xe6,0x18,0x9b, //sIP
40    0xcb,0xff,0xfc,0xc2, //DIP
41
42    0x80,0x44,//SPORT
43    0x00,0x50,//DPORT
44
45    0x00,0x00,0x00,0x00, //checksum
46
47    0x11,0x22,0x33,0x44, // magic
48    0x00,0x00,0x00,0x00, //64 bit counter
49    0x00,0x00,0x00,0x00,
50    0x00,0x01,0xa0,0x00, //seq
51    0x00,0x00,0x00,0x00,
52
53};
54
55const uint8_t icmp_pkt[]={
56    0x00,0x04,0x96,0x08,0xe0,0x40,
57    0x00,0x0e,0x2e,0x24,0x37,0x5f,
58    0x08,0x00,
59
60    0x45,0x03,0x00,0x30,
61    0x00,0x00,0x40,0x00,
62    0xff,0x01,0xbd,0x04,
63    0x9b,0xe6,0x18,0x9b, //SIP
64    0xcb,0xff,0xfc,0xc2, //DIP
65
66    0x08, 0x00,
67    0x01, 0x02,  //checksum
68    0xaa, 0xbb,  // id
69    0x00, 0x00,  // Sequence number
70
71    0x11,0x22,0x33,0x44, // magic
72    0x00,0x00,0x00,0x00, //64 bit counter
73    0x00,0x00,0x00,0x00,
74    0x00,0x01,0xa0,0x00, //seq
75    0x00,0x00,0x00,0x00,
76
77};
78
79
80void CLatencyPktInfo::Create(class CLatencyPktMode *m_l_pkt_info){
81    uint8_t pkt_size = m_l_pkt_info->getPacketLen();
82
83    m_packet = new CCapPktRaw( pkt_size);
84    m_packet->pkt_cnt=0;
85    m_packet->time_sec=0;
86    m_packet->time_nsec=0;
87    memcpy(m_packet->raw, m_l_pkt_info->getPacketData(), pkt_size);
88    m_packet->pkt_len=pkt_size;
89
90    m_pkt_indication.m_packet  =m_packet;
91
92    m_pkt_indication.m_ether = (EthernetHeader *)m_packet->raw;
93    m_pkt_indication.l3.m_ipv4=(IPHeader       *)(m_packet->raw+14);
94    m_pkt_indication.m_is_ipv6 = false;
95    m_pkt_indication.l4.m_icmp=(ICMPHeader *)m_packet->raw+14+20;
96    m_pkt_indication.m_payload=(uint8_t *)m_packet->raw+14+20+16;
97    m_pkt_indication.m_payload_len=0;
98    m_pkt_indication.m_packet_padding=4;
99
100
101    m_pkt_indication.m_ether_offset =0;
102    m_pkt_indication.m_ip_offset =14;
103    m_pkt_indication.m_udp_tcp_offset = 34;
104    m_pkt_indication.m_payload_offset = 34+8;
105
106    CPacketDescriptor * lpd=&m_pkt_indication.m_desc;
107    lpd->Clear();
108    lpd->SetInitSide(true);
109    lpd->SetSwapTuple(false);
110    lpd->SetIsValidPkt(true);
111    lpd->SetIsIcmp(true);
112    lpd->SetIsLastPkt(true);
113    m_pkt_info.Create(&m_pkt_indication);
114
115    memset(&m_dummy_node,0,sizeof(m_dummy_node));
116
117    m_dummy_node.set_socket_id( CGlobalInfo::m_socket.port_to_socket(0) );
118
119    m_dummy_node.m_time =0.1;
120    m_dummy_node.m_pkt_info = &m_pkt_info;
121    m_dummy_node.m_dest_ip  = 0;
122    m_dummy_node.m_src_ip   = 0;
123    m_dummy_node.m_src_port =  0x11;
124    m_dummy_node.m_flow_id =0;
125    m_dummy_node.m_flags =CGenNode::NODE_FLAGS_LATENCY;
126
127}
128
129rte_mbuf_t * CLatencyPktInfo::generate_pkt(int port_id,uint32_t extern_ip){
130    bool is_client_to_server=(port_id%2==0)?true:false;
131
132    int dual_port_index=(port_id>>1);
133    uint32_t c=m_client_ip.v4;
134    uint32_t s=m_server_ip.v4;
135    if ( extern_ip ){
136        c=extern_ip;
137    }
138
139    if (!is_client_to_server) {
140        /*swap */
141        uint32_t t=c;
142        c=s;
143        s=t;
144    }
145    uint32_t mask=dual_port_index*m_dual_port_mask;
146    if ( extern_ip==0 ){
147       c+=mask;
148    }
149    s+=mask;
150    m_dummy_node.m_src_ip  = c;
151    m_dummy_node.m_dest_ip   = s;
152
153    rte_mbuf_t * m=m_pkt_info.generate_new_mbuf(&m_dummy_node);
154    return (m);
155}
156
157void CLatencyPktInfo::set_ip(uint32_t src,
158                             uint32_t dst,
159                             uint32_t dual_port_mask){
160    m_client_ip.v4=src;
161    m_server_ip.v4=dst;
162    m_dual_port_mask=dual_port_mask;
163}
164
165void CLatencyPktInfo::Delete(){
166    m_pkt_info.Delete();
167    delete m_packet;
168}
169
170void CCPortLatency::reset(){
171    m_rx_seq    =m_tx_seq;
172    m_pad       = 0;
173    m_tx_pkt_err=0;
174    m_tx_pkt_ok =0;
175    m_ign_stats.clear();
176    m_ign_stats_prev.clear();
177    m_pkt_ok=0;
178    m_rx_check=0;
179    m_no_magic=0;
180    m_unsup_prot=0;
181    m_no_id=0;
182    m_seq_error=0;
183    m_length_error=0;
184    m_no_ipv4_option=0;
185    m_hist.Reset();
186}
187
188static uint8_t nat_is_port_can_send(uint8_t port_id){
189    uint8_t client_index = (port_id %2);
190    return (client_index ==0 ?1:0);
191}
192
193bool CCPortLatency::Create(CLatencyManager * parent,
194                           uint8_t id,
195                           uint16_t payload_offset,
196                           uint16_t l4_offset,
197                           uint16_t pkt_size,
198                           CCPortLatency * rx_port){
199    m_parent    = parent;
200    m_id        = id;
201    m_tx_seq    =0x12345678;
202    m_icmp_tx_seq = 1;
203    m_icmp_rx_seq = 0;
204    m_l4_offset = l4_offset;
205    m_payload_offset    = payload_offset;
206    m_pkt_size  = pkt_size;
207    m_rx_port   = rx_port;
208    m_nat_can_send = nat_is_port_can_send(m_id);
209    m_nat_learn    = m_nat_can_send;
210    m_nat_external_ip=0;
211
212    m_hist.Create();
213    reset();
214    return (true);
215}
216
217void CCPortLatency::Delete(){
218    m_hist.Delete();
219}
220
221void CCPortLatency::update_packet(rte_mbuf_t * m, int port_id){
222    uint8_t *p=rte_pktmbuf_mtod(m, uint8_t*);
223    bool is_client_to_server=(port_id%2==0)?true:false;
224
225    /* update mac addr dest/src 12 bytes */
226    memcpy(p,CGlobalInfo::m_options.get_dst_src_mac_addr(m_id),12);
227
228    latency_header * h=(latency_header *)(p+m_payload_offset);
229    h->magic = LATENCY_MAGIC | m_id ;
230    h->time_stamp = os_get_hr_tick_64();
231    h->seq = m_tx_seq;
232    m_tx_seq++;
233
234    CLatencyPktMode *c_l_pkt_mode = m_parent->c_l_pkt_mode;
235    c_l_pkt_mode->update_pkt(p + m_l4_offset, is_client_to_server, m_pkt_size - m_l4_offset, &m_icmp_tx_seq);
236}
237
238
239void CCPortLatency::DumpShortHeader(FILE *fd){
240    fprintf(fd," if|   tx_ok , rx_ok  , rx check ,error,       latency (usec) ,    Jitter          max window \n");
241    fprintf(fd,"   |         ,        ,          ,     ,   average   ,   max  ,    (usec)                     \n");
242    fprintf(fd," ---------------------------------------------------------------------------------------------------------------- \n");
243}
244
245
246
247std::string CCPortLatency::get_field(std::string name,float f){
248    char buff[200];
249    sprintf(buff,"\"%s-%d\":%.1f,",name.c_str(),m_id,f);
250    return (std::string(buff));
251}
252
253
254void CCPortLatency::dump_json_v2(std::string & json ){
255    char buff[200];
256    sprintf(buff,"\"port-%d\": {",m_id);
257    json+=std::string(buff);
258    m_hist.dump_json("hist",json);
259    dump_counters_json(json);
260    json+="},";
261}
262
263void CCPortLatency::dump_json(std::string & json ){
264    json += get_field("avg",m_hist.get_average_latency() );
265    json += get_field("max",m_hist.get_max_latency() );
266    json += get_field("c-max",m_hist.get_max_latency_last_update() );
267    json += get_field("error",(float)(m_unsup_prot+m_no_magic+m_no_id+m_seq_error+m_length_error) );
268    json += get_field("jitter",(float)get_jitter_usec() );
269}
270
271
272void CCPortLatency::DumpShort(FILE *fd){
273
274//	m_hist.update(); <- moved to CLatencyManager::update()
275    fprintf(fd,"%8lu,%8lu,%10lu,%5lu,",
276                    m_tx_pkt_ok,
277                    m_pkt_ok,
278                    m_rx_check,
279                    m_unsup_prot+m_no_magic+m_no_id+m_seq_error+m_length_error+m_no_ipv4_option+m_tx_pkt_err
280            );
281
282    fprintf(fd,"   %8.0f  ,%8.0f,%8d ",
283                          m_hist.get_average_latency(),
284                          m_hist.get_max_latency(),
285                          get_jitter_usec()
286                        );
287    fprintf(fd,"     | ");
288    m_hist.DumpWinMax(fd);
289
290}
291
292#define DPL_J(f)  json+=add_json(#f,f);
293#define DPL_J_LAST(f)  json+=add_json(#f,f,true);
294
295void CCPortLatency::dump_counters_json(std::string & json ){
296
297    json+="\"stats\" : {";
298    DPL_J(m_tx_pkt_ok);
299    json+=add_json("tx_arp", m_ign_stats.get_tx_arp());
300    json+=add_json("ipv6_n_solic", m_ign_stats.get_tx_n_solic());
301    json+=add_json("ignore_bytes", m_ign_stats.get_tx_bytes());
302    DPL_J(m_tx_pkt_err);
303    DPL_J(m_pkt_ok);
304    DPL_J(m_unsup_prot);
305    DPL_J(m_no_magic);
306    DPL_J(m_no_id);
307    DPL_J(m_seq_error);
308    DPL_J(m_length_error);
309    DPL_J(m_no_ipv4_option);
310    json+=add_json("m_jitter",get_jitter_usec());
311    /* must be last */
312    DPL_J_LAST(m_rx_check);
313    json+="}";
314
315
316}
317
318void CCPortLatency::DumpCounters(FILE *fd){
319#define DP_A1(f) if (f) fprintf(fd," %-40s : %llu \n",#f, (unsigned long long)f)
320#define DP_A2(str, f) if (f) fprintf(fd," %-40s : %llu \n", str, (unsigned long long)f)
321
322    fprintf(fd," counter  \n");
323    fprintf(fd," -----------\n");
324
325    DP_A1(m_tx_pkt_err);
326    DP_A1(m_tx_pkt_ok);
327    DP_A1(m_pkt_ok);
328    DP_A1(m_unsup_prot);
329    DP_A1(m_no_magic);
330    DP_A1(m_no_id);
331    DP_A1(m_seq_error);
332    DP_A1(m_length_error);
333    DP_A1(m_rx_check);
334    DP_A1(m_no_ipv4_option);
335    DP_A2("tx_arp", m_ign_stats.get_tx_arp());
336    DP_A2("ipv6_n_solic", m_ign_stats.get_tx_n_solic());
337    DP_A2("ignore_bytes", m_ign_stats.get_tx_bytes());
338
339    fprintf(fd," -----------\n");
340    m_hist.Dump(fd);
341    fprintf(fd," %-40s : %lu \n","jitter", (ulong)get_jitter_usec());
342}
343
344bool CCPortLatency::dump_packet(rte_mbuf_t * m){
345    fprintf(stdout," %f.03 dump packet ..\n",now_sec());
346    uint8_t *p=rte_pktmbuf_mtod(m, uint8_t*);
347    uint16_t pkt_size=rte_pktmbuf_pkt_len(m);
348    utl_DumpBuffer(stdout,p,pkt_size,0);
349    return (0);
350#if 0
351    if (pkt_size < ( sizeof(CRx_check_header)+14+20) ) {
352        assert(0);
353    }
354    CRx_check_header * lp=(CRx_check_header *)(p+pkt_size-sizeof(CRx_check_header));
355
356    lp->dump(stdout);
357
358    return (0);
359#endif
360
361}
362
363bool CCPortLatency::check_rx_check(rte_mbuf_t * m) {
364    m_rx_check++;
365    return (true);
366}
367
368bool CCPortLatency::do_learn(uint32_t external_ip) {
369    m_nat_learn=true;
370    m_nat_can_send=true;
371    m_nat_external_ip=external_ip;
372    return (true);
373}
374
375bool CCPortLatency::check_packet(rte_mbuf_t * m,CRx_check_header * & rx_p) {
376    CSimplePacketParser parser(m);
377    if ( !parser.Parse()  ) {
378        m_unsup_prot++;  // Unsupported protocol
379        return (false);
380    }
381    CLatencyPktMode *c_l_pkt_mode = m_parent->c_l_pkt_mode;
382    uint16_t pkt_size=rte_pktmbuf_pkt_len(m);
383    uint16_t vlan_offset=parser.m_vlan_offset;
384    uint8_t *p=rte_pktmbuf_mtod(m, uint8_t*);
385
386    rx_p = (CRx_check_header *)0;
387
388    bool is_lateancy_pkt =  c_l_pkt_mode->IsLatencyPkt(parser.m_ipv4) & IsLatencyPkt(parser.m_l4 + c_l_pkt_mode->l4_header_len());
389
390    if ( ! is_lateancy_pkt) {
391
392#ifdef NAT_TRACE_
393        printf(" %.3f RX : got packet !!! \n",now_sec() );
394#endif
395
396        /* ipv6+rx-check */
397        if ( parser.m_ipv6 ) {
398            /* if we have ipv6 packet */
399            if (parser.m_protocol == RX_CHECK_V6_OPT_TYPE) {
400                if ( get_is_rx_check_mode() ){
401                    m_rx_check++;
402                    rx_p=(CRx_check_header *)((uint8_t*)parser.m_ipv6  +IPv6Header::DefaultSize);
403                    return (true);
404                }
405
406            }
407            m_seq_error++;
408           return (false);
409        }
410
411        uint8_t opt_len = parser.m_ipv4->getOptionLen();
412        uint8_t *opt_ptr = parser.m_ipv4->getOption();
413        /* Process IP option header(s) */
414        while ( opt_len != 0 ) {
415            switch (*opt_ptr) {
416            case RX_CHECK_V4_OPT_TYPE:
417                    /* rx-check option header */
418                    if ( ( !get_is_rx_check_mode() ) ||
419                        (opt_len < RX_CHECK_LEN) ) {
420                        m_seq_error++;
421                        return (false);
422                    }
423                    m_rx_check++;
424                    rx_p=(CRx_check_header *)opt_ptr;
425                    opt_len -= RX_CHECK_LEN;
426                    opt_ptr += RX_CHECK_LEN;
427                    break;
428            case CNatOption::noIPV4_OPTION:
429                    /* NAT learn option header */
430                    CNatOption *lp;
431                    if ( ( !CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_IP_OPTION) ) ||
432                         (opt_len < CNatOption::noOPTION_LEN) ) {
433                        m_seq_error++;
434                        return (false);
435                    }
436                    lp = (CNatOption *)opt_ptr;
437                    if ( !lp->is_valid_ipv4_magic() ) {
438                        m_no_ipv4_option++;
439                        return (false);
440                    }
441                    m_parent->get_nat_manager()->handle_packet_ipv4(lp, parser.m_ipv4, true);
442                    opt_len -= CNatOption::noOPTION_LEN;
443                    opt_ptr += CNatOption::noOPTION_LEN;
444                    break;
445            default:
446                    m_seq_error++;
447                    return (false);
448            } // End of switch
449        } // End of while
450
451        bool first;
452        if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_TCP) && parser.IsNatInfoPkt(first)) {
453            m_parent->get_nat_manager()->handle_packet_ipv4(NULL, parser.m_ipv4, first);
454        }
455
456        return (true);
457    } // End of check for non-latency packet
458    // learn for latency packets. We only have one flow for latency, so translation is for it.
459    if ( CGlobalInfo::is_learn_mode() && (m_nat_learn ==false) ) {
460        do_learn(parser.m_ipv4->getSourceIp());
461    }
462
463    if ( (pkt_size-vlan_offset) != m_pkt_size ) {
464        // patch for e1000 card. e1000 hands us the packet with Ethernet FCS, so it is 4 bytes longer
465        if ((pkt_size - vlan_offset - 4) != m_pkt_size ) {
466            m_length_error++;
467            return (false);
468        }
469    }
470    c_l_pkt_mode->update_recv(p + m_l4_offset + vlan_offset, &m_icmp_rx_seq, &m_icmp_tx_seq);
471#ifdef LATENCY_DEBUG
472    c_l_pkt_mode->rcv_debug_print(p + m_l4_offset + vlan_offset);
473#endif
474    latency_header * h=(latency_header *)(p+m_payload_offset + vlan_offset);
475    if ( h->seq != m_rx_seq ){
476        m_seq_error++;
477        m_rx_seq =h->seq +1;
478        return (false);
479    }else{
480        m_rx_seq++;
481    }
482    m_pkt_ok++;
483    uint64_t d = (os_get_hr_tick_64() - h->time_stamp );
484    dsec_t ctime=ptime_convert_hr_dsec(d);
485    m_hist.Add(ctime);
486    m_jitter.calc(ctime);
487    return (true);
488}
489
490void CLatencyManager::Delete(){
491    m_pkt_gen.Delete();
492
493    if ( get_is_rx_check_mode() ) {
494        m_rx_check_manager.Delete();
495    }
496    if ( CGlobalInfo::is_learn_mode() ){
497        m_nat_check_manager.Delete();
498    }
499    m_cpu_cp_u.Delete();
500}
501
502/* 0->1
503   1->0
504   2->3
505   3->2
506*/
507static uint8_t swap_port(uint8_t port_id){
508    uint8_t offset= ((port_id>>1)<<1);
509    uint8_t client_index = (port_id %2);
510    return (offset + (client_index ^ 1));
511}
512
513
514
515bool CLatencyManager::Create(CLatencyManagerCfg * cfg){
516    switch (CGlobalInfo::m_options.get_l_pkt_mode()) {
517    default:
518    case 0:
519        c_l_pkt_mode = (CLatencyPktModeSCTP *) new CLatencyPktModeSCTP(CGlobalInfo::m_options.get_l_pkt_mode());
520        break;
521    case 1:
522    case 2:
523    case 3:
524        c_l_pkt_mode =  (CLatencyPktModeICMP *) new CLatencyPktModeICMP(CGlobalInfo::m_options.get_l_pkt_mode());
525        break;
526    }
527
528    m_max_ports=cfg->m_max_ports;
529    assert (m_max_ports <= TREX_MAX_PORTS);
530    assert ((m_max_ports%2)==0);
531    m_port_mask =0xffffffff;
532    m_do_stop =false;
533    m_is_active =false;
534    m_pkt_gen.Create(c_l_pkt_mode);
535    int i;
536    for (i=0; i<m_max_ports; i++) {
537        CLatencyManagerPerPort * lp=&m_ports[i];
538        CCPortLatency * lpo=&m_ports[swap_port(i)].m_port;
539
540        lp->m_io=cfg->m_ports[i];
541        lp->m_port.Create(this,
542                          i,
543                          m_pkt_gen.get_payload_offset(),
544                          m_pkt_gen.get_l4_offset(),
545                          m_pkt_gen.get_pkt_size(),lpo );
546    }
547    m_cps= cfg->m_cps;
548    if (m_cps != 0) {
549        m_delta_sec =(1.0/m_cps);
550    } else {
551        m_delta_sec = 0.0;
552    }
553
554    if ( get_is_rx_check_mode() ) {
555        assert(m_rx_check_manager.Create());
556        m_rx_check_manager.m_cur_time= now_sec();
557     }
558
559
560    m_pkt_gen.set_ip(cfg->m_client_ip.v4,cfg->m_server_ip.v4,cfg->m_dual_port_mask);
561    m_cpu_cp_u.Create(&m_cpu_dp_u);
562    if ( CGlobalInfo::is_learn_mode() ){
563        m_nat_check_manager.Create();
564    }
565
566    return (true);
567}
568
569void  CLatencyManager::send_pkt_all_ports(){
570    m_start_time = os_get_hr_tick_64();
571    int i;
572    for (i=0; i<m_max_ports; i++) {
573        if ( m_port_mask & (1<<i)  ){
574            CLatencyManagerPerPort * lp=&m_ports[i];
575            if (lp->m_port.can_send_packet(i%2) ){
576                rte_mbuf_t * m=m_pkt_gen.generate_pkt(i,lp->m_port.external_nat_ip());
577                lp->m_port.update_packet(m, i);
578
579#ifdef LATENCY_DEBUG
580                uint8_t *p = rte_pktmbuf_mtod(m, uint8_t*);
581                c_l_pkt_mode->send_debug_print(p + 34);
582#endif
583                if ( lp->m_io->tx(m) == 0 ){
584                    lp->m_port.m_tx_pkt_ok++;
585                }else{
586                    lp->m_port.m_tx_pkt_err++;
587                }
588
589            }
590        }
591    }
592}
593
594double CLatencyManager::grat_arp_timeout() {
595    return (double)CGlobalInfo::m_options.m_arp_ref_per / m_arp_info.size();
596}
597
598void  CLatencyManager::add_grat_arp_src(COneIPv4Info &ip) {
599    m_arp_info.insert(ip);
600}
601
602void CLatencyManager::send_one_grat_arp() {
603    const COneIPInfo *ip_info;
604    uint16_t port_id;
605    CLatencyManagerPerPort * lp;
606    rte_mbuf_t *m;
607    uint8_t src_mac[ETHER_ADDR_LEN];
608    uint16_t vlan;
609    uint32_t sip;
610
611    ip_info = m_arp_info.get_next();
612    if (!ip_info)
613        ip_info = m_arp_info.get_next();
614    // Two times NULL means there are no addresses
615    if (!ip_info)
616        return;
617
618    port_id = ip_info->get_port();
619    lp = &m_ports[port_id];
620    m = CGlobalInfo::pktmbuf_alloc_small(CGlobalInfo::m_socket.port_to_socket(port_id));
621    assert(m);
622    uint8_t *p = (uint8_t *)rte_pktmbuf_append(m, ip_info->get_grat_arp_len());
623    ip_info->get_mac(src_mac);
624    vlan = ip_info->get_vlan();
625    switch(ip_info->ip_ver()) {
626    case COneIPInfo::IP4_VER:
627        sip = ((COneIPv4Info *)ip_info)->get_ip();
628        CTestPktGen::create_arp_req(p, sip, sip, src_mac, vlan, port_id);
629        if (CGlobalInfo::m_options.preview.getVMode() >= 3) {
630            printf("Sending gratuitous ARP on port %d vlan:%d, sip:%s\n", port_id, vlan
631                   , ip_to_str(sip).c_str());
632            utl_DumpBuffer(stdout, p, 60, 0);
633        }
634        if ( lp->m_io->tx(m) == 0 ) {
635            lp->m_port.m_ign_stats.m_tx_arp++;
636            lp->m_port.m_ign_stats.m_tot_bytes += 64; // mbuf size is smaller, but 64 bytes will be sent
637        } else {
638            lp->m_port.m_tx_pkt_err++;
639        }
640        break;
641    case COneIPInfo::IP6_VER:
642        //??? implement ipv6
643        break;
644    }
645}
646
647void  CLatencyManager::wait_for_rx_dump(){
648    rte_mbuf_t * rx_pkts[64];
649    int i;
650    while ( true  ) {
651        rte_pause();
652        rte_pause();
653        rte_pause();
654        for (i=0; i<m_max_ports; i++) {
655            CLatencyManagerPerPort * lp=&m_ports[i];
656            rte_mbuf_t * m;
657            uint16_t cnt_p = lp->m_io->rx_burst(rx_pkts, 64);
658            if (cnt_p) {
659                int j;
660                for (j=0; j<cnt_p; j++) {
661                    m=rx_pkts[j] ;
662                    lp->m_port.dump_packet( m);
663                    rte_pktmbuf_free(m);
664                }
665            } /*cnt_p*/
666        }/* for*/
667    }
668}
669
670
671void CLatencyManager::handle_rx_pkt(CLatencyManagerPerPort * lp,
672                                    rte_mbuf_t * m){
673    CRx_check_header *rxc = NULL;
674
675    lp->m_port.check_packet(m,rxc);
676    if ( unlikely(rxc!=NULL) ){
677        m_rx_check_manager.handle_packet(rxc);
678    }
679
680    rte_pktmbuf_free(m);
681}
682
683void  CLatencyManager::try_rx(){
684    rte_mbuf_t * rx_pkts[64];
685    int i;
686    for (i=0; i<m_max_ports; i++) {
687        CLatencyManagerPerPort * lp=&m_ports[i];
688        rte_mbuf_t * m;
689        /* try to read 64 packets clean up the queue */
690        uint16_t cnt_p = lp->m_io->rx_burst(rx_pkts, 64);
691        if (cnt_p) {
692            m_cpu_dp_u.start_work1();
693            int j;
694            for (j=0; j<cnt_p; j++) {
695                m=rx_pkts[j] ;
696                handle_rx_pkt(lp,m);
697            }
698            /* commit only if there was work to do ! */
699            m_cpu_dp_u.commit1();
700          }/* if work */
701      }// all ports
702}
703
704
705void  CLatencyManager::reset(){
706
707    int i;
708    for (i=0; i<m_max_ports; i++) {
709        CLatencyManagerPerPort * lp=&m_ports[i];
710        lp->m_port.reset();
711    }
712
713}
714
715void CLatencyManager::tickle() {
716    m_monitor.tickle();
717}
718
719void  CLatencyManager::start(int iter, bool activate_watchdog) {
720    m_do_stop =false;
721    m_is_active =false;
722    int cnt=0;
723
724    double n_time;
725    CGenNode * node = new CGenNode();
726    node->m_type = CGenNode::FLOW_SYNC;   /* general stuff */
727    node->m_time = now_sec()+0.007;
728    m_p_queue.push(node);
729
730    if (m_delta_sec > 0) {
731        node = new CGenNode();
732        node->m_type = CGenNode::FLOW_PKT; /* latency */
733        node->m_time = now_sec(); /* 1/cps rate */
734        m_p_queue.push(node);
735    }
736
737    if (CGlobalInfo::m_options.m_arp_ref_per > 0) {
738        node = new CGenNode();
739        node->m_type = CGenNode::GRAT_ARP; /* gratuitous ARP */
740        node->m_time = now_sec() + (double) CGlobalInfo::m_options.m_arp_ref_per;
741        m_p_queue.push(node);
742    }
743
744    if (activate_watchdog) {
745        m_monitor.create("STF RX CORE", 1);
746        TrexWatchDog::getInstance().register_monitor(&m_monitor);
747    }
748
749    while (  !m_p_queue.empty() ) {
750        node = m_p_queue.top();
751        n_time = node->m_time;
752
753        /* wait for event */
754        while ( true ) {
755            double dt = now_sec() - n_time ;
756            if (dt> (0.0)) {
757                break;
758            }
759            try_rx();
760            rte_pause();
761        }
762
763        switch (node->m_type) {
764        case CGenNode::FLOW_SYNC:
765
766            tickle();
767
768            if ( CGlobalInfo::is_learn_mode() ) {
769                m_nat_check_manager.handle_aging();
770            }
771
772            m_p_queue.pop();
773            node->m_time += SYNC_TIME_OUT;
774            m_p_queue.push(node);
775
776            break;
777        case CGenNode::FLOW_PKT:
778            m_cpu_dp_u.start_work1();
779            send_pkt_all_ports();
780            m_p_queue.pop();
781            node->m_time += m_delta_sec;
782            m_p_queue.push(node);
783            m_cpu_dp_u.commit1();
784            break;
785
786        case CGenNode::GRAT_ARP:
787            m_cpu_dp_u.start_work1();
788            send_one_grat_arp();
789            m_p_queue.pop();
790            node->m_time += grat_arp_timeout();
791            m_p_queue.push(node);
792            m_cpu_dp_u.commit1();
793            break;
794        }
795
796        /* this will be called every sync which is 1msec */
797        if ( m_do_stop ) {
798             break;
799        }
800        if ( iter>0   ){
801            if ( ( cnt>iter) ){
802                printf("stop due iter %d\n",iter);
803                break;
804            }
805        }
806        cnt++;
807    }
808
809    /* free all nodes in the queue */
810    while (!m_p_queue.empty()) {
811        node = m_p_queue.top();
812        m_p_queue.pop();
813        delete node;
814    }
815
816    printf(" latency daemon has stopped\n");
817    if ( get_is_rx_check_mode() ) {
818        m_rx_check_manager.tw_drain();
819    }
820
821    /* disable the monitor */
822    if (activate_watchdog) {
823        m_monitor.disable();
824    }
825
826}
827
828void  CLatencyManager::stop(){
829    m_do_stop =true;
830}
831
832bool  CLatencyManager::is_active(){
833    return (m_is_active);
834}
835
836// return the statistics we want to ignore for port port_id
837// stat - hold values we return.
838// if get_diff is true, return diff from last read. Else return total.
839void CLatencyManager::get_ignore_stats(int port_id, CRXCoreIgnoreStat &stat, bool get_diff) {
840    CLatencyManagerPerPort * lp = &m_ports[port_id];
841    CRXCoreIgnoreStat temp;
842    temp = lp->m_port.m_ign_stats;
843    if (get_diff) {
844        stat = temp - lp->m_port.m_ign_stats_prev;
845        lp->m_port.m_ign_stats_prev = temp;
846    } else {
847        stat = lp->m_port.m_ign_stats;
848    }
849}
850
851double CLatencyManager::get_max_latency(){
852    double l=0.0;
853    int i;
854    for (i=0; i<m_max_ports; i++) {
855        CLatencyManagerPerPort * lp=&m_ports[i];
856        if ( l <lp->m_port.m_hist.get_max_latency() ){
857            l=lp->m_port.m_hist.get_max_latency();
858        }
859    }
860    return (l);
861}
862
863double CLatencyManager::get_avr_latency(){
864    double l=0.0;
865    int i;
866    for (i=0; i<m_max_ports; i++) {
867        CLatencyManagerPerPort * lp=&m_ports[i];
868        if ( l <lp->m_port.m_hist.get_average_latency() ){
869            l=lp->m_port.m_hist.get_average_latency();
870        }
871    }
872    return (l);
873}
874
875uint64_t CLatencyManager::get_total_pkt(){
876    int i;
877    uint64_t t=0;
878    for (i=0; i<m_max_ports; i++) {
879        CLatencyManagerPerPort * lp=&m_ports[i];
880        t+=lp->m_port.m_tx_pkt_ok ;
881    }
882    return  t;
883}
884
885uint64_t CLatencyManager::get_total_bytes(){
886    int i;
887    uint64_t t=0;
888    for (i=0; i<m_max_ports; i++) {
889        CLatencyManagerPerPort * lp=&m_ports[i];
890        t+=lp->m_port.m_tx_pkt_ok* (m_pkt_gen.get_pkt_size()+4);
891    }
892    return  t;
893
894}
895
896
897bool   CLatencyManager::is_any_error(){
898    int i;
899    for (i=0; i<m_max_ports; i++) {
900        CLatencyManagerPerPort * lp=&m_ports[i];
901        if ( lp->m_port.is_any_err() ){
902            return (true);
903        }
904    }
905    return  (false);
906}
907
908
909void CLatencyManager::dump_json(std::string & json ){
910    json="{\"name\":\"trex-latecny\",\"type\":0,\"data\":{";
911    int i;
912    for (i=0; i<m_max_ports; i++) {
913        CLatencyManagerPerPort * lp=&m_ports[i];
914        lp->m_port.dump_json(json);
915    }
916
917    json+="\"unknown\":0}}"  ;
918
919}
920
921void CLatencyManager::dump_json_v2(std::string & json ){
922    json="{\"name\":\"trex-latecny-v2\",\"type\":0,\"data\":{";
923    json+=add_json("cpu_util",m_cpu_cp_u.GetVal());
924
925    int i;
926    for (i=0; i<m_max_ports; i++) {
927        CLatencyManagerPerPort * lp=&m_ports[i];
928        lp->m_port.dump_json_v2(json);
929    }
930
931    json+="\"unknown\":0}}"  ;
932
933}
934
935void CLatencyManager::DumpRxCheck(FILE *fd){
936    if ( get_is_rx_check_mode() ) {
937        fprintf(fd," rx checker : \n");
938        m_rx_check_manager.DumpShort(fd);
939        m_rx_check_manager.Dump(fd);
940    }
941}
942
943void CLatencyManager::DumpShortRxCheck(FILE *fd){
944    if ( get_is_rx_check_mode() ) {
945        m_rx_check_manager.DumpShort(fd);
946    }
947}
948
949void CLatencyManager::dump_nat_flow_table(FILE *fd) {
950    m_nat_check_manager.Dump(fd);
951}
952
953void CLatencyManager::rx_check_dump_json(std::string & json){
954    if ( get_is_rx_check_mode() ) {
955        m_rx_check_manager.dump_json(json );
956    }
957}
958
959
960void CLatencyManager::update_fast(){
961    m_cpu_cp_u.Update() ;
962}
963
964void CLatencyManager::update(){
965    for (int i=0; i<m_max_ports; i++) {
966        CLatencyManagerPerPort * lp=&m_ports[i];
967        lp->m_port.m_hist.update();
968    }
969}
970
971void CLatencyManager::DumpShort(FILE *fd){
972    int i;
973    fprintf(fd," Cpu Utilization : %2.1f %%  \n",m_cpu_cp_u.GetVal());
974    CCPortLatency::DumpShortHeader(fd);
975    for (i=0; i<m_max_ports; i++) {
976        fprintf(fd," %d | ",i);
977        CLatencyManagerPerPort * lp=&m_ports[i];
978        lp->m_port.DumpShort(fd);
979        fprintf(fd,"\n");
980    }
981
982
983}
984
985void CLatencyManager::Dump(FILE *fd){
986    int i;
987    fprintf(fd," cpu : %2.1f  %% \n",m_cpu_cp_u.GetVal());
988    for (i=0; i<m_max_ports; i++) {
989        fprintf(fd," port   %d \n",i);
990        fprintf(fd," -----------------\n");
991        CLatencyManagerPerPort * lp=&m_ports[i];
992        lp->m_port.DumpCounters(fd);
993    }
994}
995
996void CLatencyManager::DumpRxCheckVerification(FILE *fd,
997                                              uint64_t total_tx_rx_check){
998    if ( !get_is_rx_check_mode() ) {
999        fprintf(fd," rx_checker is disabled  \n");
1000        return;
1001    }
1002    fprintf(fd," rx_check Tx : %llu \n", (unsigned long long)total_tx_rx_check);
1003    fprintf(fd," rx_check Rx : %llu \n", (unsigned long long)m_rx_check_manager.getTotalRx() );
1004    fprintf(fd," rx_check verification :" );
1005    if (m_rx_check_manager.getTotalRx() == total_tx_rx_check) {
1006        fprintf(fd," OK \n" );
1007    }else{
1008        fprintf(fd," FAIL \n" );
1009    }
1010}
1011
1012uint8_t CLatencyPktModeICMP::getPacketLen() {return sizeof(icmp_pkt);}
1013const uint8_t *CLatencyPktModeICMP::getPacketData() {return icmp_pkt;}
1014void CLatencyPktModeICMP::rcv_debug_print(uint8_t *pkt) {
1015    ICMPHeader *m_icmp = (ICMPHeader *)pkt;
1016    printf ("received latency ICMP packet code:%d seq:%x\n"
1017            , m_icmp->getType(), m_icmp->getSeqNum());
1018};
1019
1020void CLatencyPktModeICMP::send_debug_print(uint8_t *pkt) {
1021    ICMPHeader *m_icmp = (ICMPHeader *)pkt;
1022    printf ("Sending latency ICMP packet code:%d seq:%x\n", m_icmp->getType(), m_icmp->getSeqNum());
1023}
1024
1025void CLatencyPktModeICMP::update_pkt(uint8_t *pkt, bool is_client_to_server, uint16_t l4_len, uint16_t *tx_seq) {
1026    ICMPHeader * m_icmp =(ICMPHeader *)(pkt);
1027
1028    if (m_submode == L_PKT_SUBMODE_0_SEQ) {
1029        m_icmp->setSeqNum(0);
1030    } else {
1031        m_icmp->setSeqNum(*tx_seq);
1032        (*tx_seq)++;
1033    }
1034
1035    if ((!is_client_to_server) && (m_submode == L_PKT_SUBMODE_REPLY)) {
1036      m_icmp->setType(0); // echo reply
1037    } else {
1038      m_icmp->setType(8); // echo request
1039    }
1040    // ICMP checksum is calculated on payload + ICMP header
1041    m_icmp->updateCheckSum(l4_len);
1042
1043}
1044
1045bool CLatencyPktModeICMP::IsLatencyPkt(IPHeader *ip) {
1046    if (!ip)
1047        return false;
1048    if (ip->getProtocol() != 0x1)
1049        return false;
1050    return true;
1051};
1052
1053void CLatencyPktModeICMP::update_recv(uint8_t *pkt, uint16_t *r_seq, uint16_t *t_seq) {
1054    ICMPHeader *m_icmp = (ICMPHeader *)(pkt);
1055    *r_seq = m_icmp->getSeqNum();
1056    // Previously, we assumed we can send for sequences smaller than r_seq.
1057    // Actually, if the DUT (firewall) dropped an ICMP request, we should not send response for the dropped packet.
1058    // We are only sure that we can send reqponse for the request we just got.
1059    // This should be OK, since we send requests and responses in the same rate.
1060    *t_seq = *r_seq;
1061}
1062
1063
1064uint8_t CLatencyPktModeSCTP::getPacketLen() {return sizeof(sctp_pkt);}
1065const uint8_t *CLatencyPktModeSCTP::getPacketData() {return sctp_pkt;}
1066void CLatencyPktModeSCTP::rcv_debug_print(uint8_t *pkt) {printf("Received latency SCTP packet\n");}
1067void CLatencyPktModeSCTP::send_debug_print(uint8_t *pkt) {printf("Sending latency SCTP packet\n");
1068    // utl_DumpBuffer(stdout,pkt-20,28,0);
1069}
1070void CLatencyPktModeSCTP::update_pkt(uint8_t *pkt, bool is_client_to_server, uint16_t l4_len, uint16_t *tx_seq) {}
1071bool CLatencyPktModeSCTP::IsLatencyPkt(IPHeader *ip) {
1072    if (!ip) {
1073        return false;
1074    }
1075    if (ip->getProtocol() != 0x84) {
1076        return false;
1077    }
1078    return true;
1079};
1080void CLatencyPktModeSCTP::update_recv(uint8_t *pkt, uint16_t *r_seq, uint16_t *t_seq) {}
1081