14d53d6e2Simarom/*
24d53d6e2Simarom Itay Marom
34d53d6e2Simarom Cisco Systems, Inc.
44d53d6e2Simarom*/
54d53d6e2Simarom
64d53d6e2Simarom/*
74d53d6e2SimaromCopyright (c) 2015-2015 Cisco Systems, Inc.
84d53d6e2Simarom
94d53d6e2SimaromLicensed under the Apache License, Version 2.0 (the "License");
104d53d6e2Simaromyou may not use this file except in compliance with the License.
114d53d6e2SimaromYou may obtain a copy of the License at
124d53d6e2Simarom
134d53d6e2Simarom    http://www.apache.org/licenses/LICENSE-2.0
144d53d6e2Simarom
154d53d6e2SimaromUnless required by applicable law or agreed to in writing, software
164d53d6e2Simaromdistributed under the License is distributed on an "AS IS" BASIS,
174d53d6e2SimaromWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
184d53d6e2SimaromSee the License for the specific language governing permissions and
194d53d6e2Simaromlimitations under the License.
204d53d6e2Simarom*/
21ea0b6efcSimarom
2274b648a8Simarom#include <trex_stateless.h>
234d53d6e2Simarom#include <trex_stateless_port.h>
24ea0b6efcSimarom#include <trex_stateless_messaging.h>
25788ba38bSimarom#include <trex_streams_compiler.h>
2621fe2befSimarom#include <common/basic_utils.h>
278691f401Simarom#include <common/captureFile.h>
280337db2bSimarom#include "trex_stateless_rx_defs.h"
29ea0b6efcSimarom
304d53d6e2Simarom#include <string>
314d53d6e2Simarom
3251ad0781SHanoh Haim#ifndef TREX_RPC_MOCK_SERVER
3367bcc46bSimarom
343b827c95Simarom// DPDK c++ issue
3567bcc46bSimarom#ifndef UINT8_MAX
3667bcc46bSimarom    #define UINT8_MAX 255
3767bcc46bSimarom#endif
3867bcc46bSimarom
3967bcc46bSimarom#ifndef UINT16_MAX
4067bcc46bSimarom    #define UINT16_MAX 0xFFFF
4167bcc46bSimarom#endif
4267bcc46bSimarom
433b827c95Simarom// DPDK c++ issue
4451ad0781SHanoh Haim#endif
453b827c95Simarom
466c7880b9Simarom#include <os_time.h>
473b827c95Simarom
48c0a49eefSimaromvoid
49c0a49eefSimaromport_id_to_cores(uint8_t port_id, std::vector<std::pair<uint8_t, uint8_t>> &cores_id_list);
50c0a49eefSimarom
514d53d6e2Simaromusing namespace std;
524d53d6e2Simarom
5359a3b58dSimarom
5459a3b58dSimarom
5559a3b58dSimarom/***************************
5659a3b58dSimarom * trex DP events handlers
5759a3b58dSimarom *
5859a3b58dSimarom **************************/
5959a3b58dSimaromclass AsyncStopEvent : public TrexDpPortEvent {
6059a3b58dSimarom
6159a3b58dSimaromprotected:
6259a3b58dSimarom    /**
6359a3b58dSimarom     * when an async event occurs (all cores have reported in)
6459a3b58dSimarom     *
6559a3b58dSimarom     * @author imarom (29-Feb-16)
6659a3b58dSimarom     */
6759a3b58dSimarom    virtual void on_event() {
6859a3b58dSimarom        get_port()->change_state(TrexStatelessPort::PORT_STATE_STREAMS);
6959a3b58dSimarom
7059a3b58dSimarom        get_port()->common_port_stop_actions(true);
7159a3b58dSimarom
7259a3b58dSimarom        assert(get_port()->m_pending_async_stop_event != TrexDpPortEvents::INVALID_ID);
7359a3b58dSimarom        get_port()->m_pending_async_stop_event = TrexDpPortEvents::INVALID_ID;
7459a3b58dSimarom    }
758691f401Simarom
768691f401Simarom    /**
778691f401Simarom     * when a DP core encountered an error
788691f401Simarom     *
798691f401Simarom     * @author imarom (20-Apr-16)
808691f401Simarom     */
818691f401Simarom    virtual void on_error(int thread_id) {
828691f401Simarom        Json::Value data;
838691f401Simarom
848691f401Simarom        data["port_id"]   = get_port()->get_port_id();
858691f401Simarom        data["thread_id"] = thread_id;
868691f401Simarom
878691f401Simarom        get_stateless_obj()->get_publisher()->publish_event(TrexPublisher::EVENT_PORT_ERROR, data);
888691f401Simarom    }
8959a3b58dSimarom};
9059a3b58dSimarom
919a1356bcSimarom/*************************************
929a1356bcSimarom * Streams Feeder
939a1356bcSimarom * A class that holds a temporary
949a1356bcSimarom * clone of streams that can be
959a1356bcSimarom * manipulated
969a1356bcSimarom *
979a1356bcSimarom * this is a RAII object meant for
989a1356bcSimarom * graceful cleanup
999a1356bcSimarom ************************************/
1009a1356bcSimaromclass StreamsFeeder {
1019a1356bcSimarompublic:
1026a6047fdSimarom
1039a1356bcSimarom    StreamsFeeder(TrexStatelessPort *port) {
1049a1356bcSimarom        /* start pesimistic */
1059a1356bcSimarom        m_success = false;
1066a6047fdSimarom
1076a6047fdSimarom        m_port = port;
1086a6047fdSimarom    }
1096a6047fdSimarom
1106a6047fdSimarom    void feed() {
1116a6047fdSimarom
1129a1356bcSimarom        /* fetch the original streams */
1136a6047fdSimarom        m_port->get_object_list(m_in_streams);
1149a1356bcSimarom
1159a1356bcSimarom        for (const TrexStream *in_stream : m_in_streams) {
1169a1356bcSimarom            TrexStream *out_stream = in_stream->clone(true);
1179a1356bcSimarom
1189a1356bcSimarom            m_out_streams.push_back(out_stream);
1196a6047fdSimarom
1206a6047fdSimarom            get_stateless_obj()->m_rx_flow_stat.start_stream(out_stream);
1216a6047fdSimarom
1229a1356bcSimarom        }
1239a1356bcSimarom    }
1249a1356bcSimarom
1259a1356bcSimarom    void set_status(bool status) {
1269a1356bcSimarom        m_success = status;
1279a1356bcSimarom    }
1289a1356bcSimarom
1299a1356bcSimarom    vector<TrexStream *> &get_streams() {
1309a1356bcSimarom        return m_out_streams;
1319a1356bcSimarom    }
1329a1356bcSimarom
1339a1356bcSimarom    /**
1349a1356bcSimarom     * RAII
1359a1356bcSimarom     */
1369a1356bcSimarom    ~StreamsFeeder() {
1379a1356bcSimarom        for (int i = 0; i < m_out_streams.size(); i++) {
1389a1356bcSimarom            TrexStream *out_stream = m_out_streams[i];
1399a1356bcSimarom            TrexStream *in_stream  = m_in_streams[i];
1409a1356bcSimarom
1419a1356bcSimarom            if (m_success) {
1429a1356bcSimarom                /* success path */
1439a1356bcSimarom                get_stateless_obj()->m_rx_flow_stat.copy_state(out_stream, in_stream);
1449a1356bcSimarom            } else {
1459a1356bcSimarom                /* fail path */
1469a1356bcSimarom                get_stateless_obj()->m_rx_flow_stat.stop_stream(out_stream);
1479a1356bcSimarom            }
1489a1356bcSimarom            delete out_stream;
1499a1356bcSimarom        }
1509a1356bcSimarom    }
1519a1356bcSimarom
1529a1356bcSimaromprivate:
1539a1356bcSimarom    vector<TrexStream *>  m_in_streams;
1549a1356bcSimarom    vector<TrexStream *>  m_out_streams;
1559a1356bcSimarom    bool                  m_success;
1566a6047fdSimarom
1576a6047fdSimarom    TrexStatelessPort    *m_port;
1589a1356bcSimarom};
1599a1356bcSimarom
1609a1356bcSimarom
1614d53d6e2Simarom/***************************
1624d53d6e2Simarom * trex stateless port
1634d53d6e2Simarom *
1644d53d6e2Simarom **************************/
165418fd3d0SimaromTrexStatelessPort::TrexStatelessPort(uint8_t port_id, const TrexPlatformApi *api) : m_dp_events(this) {
166a7317d45Simarom    std::vector<std::pair<uint8_t, uint8_t>> core_pair_list;
167a7317d45Simarom
168418fd3d0Simarom    m_port_id             = port_id;
169418fd3d0Simarom    m_port_state          = PORT_STATE_IDLE;
170418fd3d0Simarom    m_platform_api        = api;
171418fd3d0Simarom    m_is_service_mode_on  = false;
172418fd3d0Simarom
173045d0f8fSimarom    /* get the platform specific data */
17421fe2befSimarom    api->get_interface_info(port_id, m_api_info);
175045d0f8fSimarom
176235a14fcSimarom    /* get RX caps */
177fa606839SIdo Barnea    uint16_t ip_id_base;
178fa606839SIdo Barnea    api->get_interface_stat_info(port_id, m_rx_count_num, m_rx_caps, ip_id_base);
179235a14fcSimarom
180a7317d45Simarom    /* get the DP cores belonging to this port */
181a7317d45Simarom    api->port_id_to_cores(m_port_id, core_pair_list);
182a7317d45Simarom
183a7317d45Simarom    for (auto core_pair : core_pair_list) {
184a7317d45Simarom
185a7317d45Simarom        /* send the core id */
186a7317d45Simarom        m_cores_id_list.push_back(core_pair.first);
187a7317d45Simarom    }
188a7317d45Simarom
189a6677655Simarom    m_graph_obj = NULL;
19059a3b58dSimarom
19159a3b58dSimarom    m_pending_async_stop_event = TrexDpPortEvents::INVALID_ID;
1924d53d6e2Simarom}
1934d53d6e2Simarom
194a7223338SimaromTrexStatelessPort::~TrexStatelessPort() {
19559a3b58dSimarom
19660fbd456Simarom    stop_traffic();
19760fbd456Simarom    remove_and_delete_all_streams();
198a7223338Simarom}
1994d53d6e2Simarom
2009c32c36bSimarom/**
2019c32c36bSimarom * acquire the port
2029c32c36bSimarom *
2039c32c36bSimarom * @author imarom (09-Nov-15)
2049c32c36bSimarom *
2059c32c36bSimarom * @param user
2069c32c36bSimarom * @param force
2079c32c36bSimarom */
2089c32c36bSimaromvoid
209d71dbce9SimaromTrexStatelessPort::acquire(const std::string &user, uint32_t session_id, bool force) {
21095c2405dSimarom
2117e599394Simarom    bool used_force = !get_owner().is_free() && force;
212d71dbce9Simarom
2137e599394Simarom    if (get_owner().is_free() || force) {
2147e599394Simarom        get_owner().own(user, session_id);
21595c2405dSimarom
21695c2405dSimarom    } else {
21795c2405dSimarom        /* not same user or session id and not force - report error */
21895c2405dSimarom        if (get_owner().get_name() == user) {
219f9dcbd38Simarom            throw TrexException("port is already owned by another session of '" + user + "'");
22095c2405dSimarom        } else {
221f9dcbd38Simarom            throw TrexException("port is already taken by '" + get_owner().get_name() + "'");
22295c2405dSimarom        }
2239c32c36bSimarom    }
2249c32c36bSimarom
2257e599394Simarom    Json::Value data;
2267e599394Simarom
2277e599394Simarom    data["port_id"]    = m_port_id;
2287e599394Simarom    data["who"]        = user;
2297e599394Simarom    data["session_id"] = session_id;
2307e599394Simarom    data["force"]      = used_force;
2317e599394Simarom
2327e599394Simarom    get_stateless_obj()->get_publisher()->publish_event(TrexPublisher::EVENT_PORT_ACQUIRED, data);
2337e599394Simarom
2349c32c36bSimarom}
2359c32c36bSimarom
2369c32c36bSimaromvoid
2379c32c36bSimaromTrexStatelessPort::release(void) {
2387e599394Simarom
2397e599394Simarom
2407e599394Simarom    Json::Value data;
2417e599394Simarom
2427e599394Simarom    data["port_id"]    = m_port_id;
2437e599394Simarom    data["who"]        = get_owner().get_name();
2447e599394Simarom    data["session_id"] = get_owner().get_session_id();
2457e599394Simarom
24695c2405dSimarom    get_owner().release();
2477e599394Simarom
2487e599394Simarom    get_stateless_obj()->get_publisher()->publish_event(TrexPublisher::EVENT_PORT_RELEASED, data);
2499c32c36bSimarom}
2509c32c36bSimarom
2514d53d6e2Simarom/**
2524d53d6e2Simarom * starts the traffic on the port
2534d53d6e2Simarom *
2544d53d6e2Simarom */
2559c32c36bSimaromvoid
256ba7b5dffSimaromTrexStatelessPort::start_traffic(const TrexPortMultiplier &mul, double duration, bool force, uint64_t core_mask) {
2574d53d6e2Simarom
2589c32c36bSimarom    /* command allowed only on state stream */
25904eae221Simarom    verify_state(PORT_STATE_STREAMS, "start");
260788ba38bSimarom
26159548ae8Simarom    /* just making sure no leftovers... */
26259548ae8Simarom    delete_streams_graph();
26359548ae8Simarom
2644c94931cSimarom    /* on start - we can only provide absolute values */
2654c94931cSimarom    assert(mul.m_op == TrexPortMultiplier::OP_ABS);
2664c94931cSimarom
2671016c3d4SYaroslav Brustinov    /* check link state */
268111bd366SYaroslav Brustinov    if ( !m_platform_api->getPortAttrObj(m_port_id)->is_link_up() && !force ) {
2691016c3d4SYaroslav Brustinov        throw TrexException("Link state is DOWN.");
2701016c3d4SYaroslav Brustinov    }
2711016c3d4SYaroslav Brustinov
272b87ac8e2Simarom    /* caclulate the effective factor for DP */
273b87ac8e2Simarom    double factor = calculate_effective_factor(mul, force);
27459548ae8Simarom
2759a1356bcSimarom    StreamsFeeder feeder(this);
2766a6047fdSimarom    feeder.feed();
2771f6977d1Simarom
278788ba38bSimarom    /* compiler it */
2793aa3a83fSimarom    std::vector<TrexStreamsCompiledObj *> compiled_objs;
280a6af2a8eSimarom    std::string fail_msg;
2813aa3a83fSimarom
2823aa3a83fSimarom    TrexStreamsCompiler compiler;
283ba7b5dffSimarom    TrexDPCoreMask mask(get_dp_core_count(), core_mask);
284ba7b5dffSimarom
2853aa3a83fSimarom    bool rc = compiler.compile(m_port_id,
2869a1356bcSimarom                               feeder.get_streams(),
2873aa3a83fSimarom                               compiled_objs,
288ba7b5dffSimarom                               mask,
28923e1f07eSimarom                               factor,
2903aa3a83fSimarom                               &fail_msg);
2919a1356bcSimarom
292cb8bc9bdSimarom    if (!rc) {
2939a1356bcSimarom        feeder.set_status(false);
294f9dcbd38Simarom        throw TrexException(fail_msg);
295ea0b6efcSimarom    }
296ea0b6efcSimarom
2979a1356bcSimarom    feeder.set_status(true);
2989a1356bcSimarom
2992dab6b6dSYaroslav Brustinov    /* generate a message to all the relevant DP cores to stop transmitting */
30059a3b58dSimarom    assert(m_pending_async_stop_event == TrexDpPortEvents::INVALID_ID);
30159a3b58dSimarom    m_pending_async_stop_event = m_dp_events.create_event(new AsyncStopEvent());
30254c1f0fcSHanoh Haim
3033aa3a83fSimarom    /* update object status */
3043aa3a83fSimarom    m_factor = factor;
305ba7b5dffSimarom    m_last_all_streams_continues = compiled_objs[mask.get_active_cores()[0]]->get_all_streams_continues();
3063aa3a83fSimarom    m_last_duration = duration;
30759a3b58dSimarom
308a7317d45Simarom    change_state(PORT_STATE_TX);
309ea0b6efcSimarom
3103aa3a83fSimarom    /* update the DP - messages will be freed by the DP */
3113aa3a83fSimarom    int index = 0;
3123aa3a83fSimarom    for (auto core_id : m_cores_id_list) {
3133aa3a83fSimarom
31411bcf4caSimarom        /* was the core assigned a compiled object ? */
31511bcf4caSimarom        if (compiled_objs[index]) {
31659a3b58dSimarom            TrexStatelessCpToDpMsgBase *start_msg = new TrexStatelessDpStart(m_port_id,
31759a3b58dSimarom                                                                             m_pending_async_stop_event,
31859a3b58dSimarom                                                                             compiled_objs[index],
31959a3b58dSimarom                                                                             duration);
32011bcf4caSimarom            send_message_to_dp(core_id, start_msg);
32111bcf4caSimarom        } else {
32211bcf4caSimarom
32311bcf4caSimarom            /* mimic an end event */
32459a3b58dSimarom            m_dp_events.on_core_reporting_in(m_pending_async_stop_event, core_id);
32511bcf4caSimarom        }
3263aa3a83fSimarom
3273aa3a83fSimarom        index++;
3283aa3a83fSimarom    }
329a7317d45Simarom
33059a3b58dSimarom    /* for debug - this can be turn on */
33159a3b58dSimarom    //m_dp_events.barrier();
33259a3b58dSimarom
3333aa3a83fSimarom    /* update subscribers */
334b6ec2066Simarom    Json::Value data;
335b6ec2066Simarom    data["port_id"] = m_port_id;
336b6ec2066Simarom    get_stateless_obj()->get_publisher()->publish_event(TrexPublisher::EVENT_PORT_STARTED, data);
3373aa3a83fSimarom
3381f6977d1Simarom}
3391f6977d1Simarom
3401f6977d1Simarom
34175ce59e5Simarombool TrexStatelessPort::is_active() const {
34275ce59e5Simarom    return   (  (m_port_state == PORT_STATE_TX)
34375ce59e5Simarom             || (m_port_state == PORT_STATE_PAUSE)
34475ce59e5Simarom             || (m_port_state == PORT_STATE_PCAP_TX)
34575ce59e5Simarom             );
34675ce59e5Simarom}
34775ce59e5Simarom
3489c32c36bSimarom/**
3499c32c36bSimarom * stop traffic on port
3509c32c36bSimarom *
3519c32c36bSimarom * @author imarom (09-Nov-15)
3529c32c36bSimarom *
3539c32c36bSimarom * @return TrexStatelessPort::rc_e
3549c32c36bSimarom */
3559c32c36bSimaromvoid
3564d53d6e2SimaromTrexStatelessPort::stop_traffic(void) {
35775ce59e5Simarom    if (!is_active()) {
358467382a7Simarom        return;
359467382a7Simarom    }
360ea0b6efcSimarom
36159548ae8Simarom    /* delete any previous graphs */
36259548ae8Simarom    delete_streams_graph();
36359548ae8Simarom
36459a3b58dSimarom    /* to avoid race, first destroy any previous stop/pause events */
36559a3b58dSimarom    if (m_pending_async_stop_event != TrexDpPortEvents::INVALID_ID) {
36659a3b58dSimarom        m_dp_events.destroy_event(m_pending_async_stop_event);
36759a3b58dSimarom        m_pending_async_stop_event = TrexDpPortEvents::INVALID_ID;
36890e28392Simarom
36959a3b58dSimarom    }
37059a3b58dSimarom
371ea0b6efcSimarom    /* generate a message to all the relevant DP cores to start transmitting */
372a1971ec3Simarom    TrexStatelessCpToDpMsgBase *stop_msg = new TrexStatelessDpStop(m_port_id);
3733aa3a83fSimarom    send_message_to_all_dp(stop_msg);
3743978adceSimarom
37559a3b58dSimarom    /* a barrier - make sure all the DP cores stopped */
37659a3b58dSimarom    m_dp_events.barrier();
37759a3b58dSimarom
37859a3b58dSimarom    change_state(PORT_STATE_STREAMS);
37959a3b58dSimarom
380f0ab9ebaSIdo Barnea    common_port_stop_actions(false);
381f0ab9ebaSIdo Barnea}
382f0ab9ebaSIdo Barnea
383d4791e05Simarom/**
384d4791e05Simarom * remove all RX filters from port
385d4791e05Simarom *
386d4791e05Simarom * @author imarom (28-Mar-16)
387d4791e05Simarom */
388d4791e05Simaromvoid
389d4791e05SimaromTrexStatelessPort::remove_rx_filters(void) {
390d4791e05Simarom    /* only valid when IDLE or with streams and not TXing */
39104eae221Simarom    verify_state(PORT_STATE_STREAMS, "remove_rx_filters");
392d4791e05Simarom
393d4791e05Simarom    for (auto entry : m_stream_table) {
394d4791e05Simarom        get_stateless_obj()->m_rx_flow_stat.stop_stream(entry.second);
395d4791e05Simarom    }
396d4791e05Simarom
397d4791e05Simarom}
398d4791e05Simarom
399f0ab9ebaSIdo Barnea/**
400f0ab9ebaSIdo Barnea * when a port stops, perform various actions
401f0ab9ebaSIdo Barnea *
402f0ab9ebaSIdo Barnea */
403f0ab9ebaSIdo Barneavoid
40459a3b58dSimaromTrexStatelessPort::common_port_stop_actions(bool async) {
405f0ab9ebaSIdo Barnea
406b6ec2066Simarom    Json::Value data;
407b6ec2066Simarom    data["port_id"] = m_port_id;
408b6ec2066Simarom
40959a3b58dSimarom    if (async) {
410f0ab9ebaSIdo Barnea        get_stateless_obj()->get_publisher()->publish_event(TrexPublisher::EVENT_PORT_FINISHED_TX, data);
411aaef3f95Simarom    } else {
412aaef3f95Simarom        get_stateless_obj()->get_publisher()->publish_event(TrexPublisher::EVENT_PORT_STOPPED, data);
413f0ab9ebaSIdo Barnea    }
414f0ab9ebaSIdo Barnea
4159c32c36bSimarom}
4169c32c36bSimarom
417ddef1a09Simarom/**
418ddef1a09Simarom * core is considered active if it has a pending for async stop
419ddef1a09Simarom *
420ddef1a09Simarom */
421ddef1a09Simarombool
422ddef1a09SimaromTrexStatelessPort::is_core_active(int core_id) {
423ddef1a09Simarom    return ( (m_pending_async_stop_event != TrexDpPortEvents::INVALID_ID) &&
424ddef1a09Simarom             (m_dp_events.is_core_pending_on_event(m_pending_async_stop_event, core_id))
425ddef1a09Simarom           );
426ddef1a09Simarom}
427ddef1a09Simarom
4289c32c36bSimaromvoid
4299c32c36bSimaromTrexStatelessPort::pause_traffic(void) {
4309c32c36bSimarom
43104eae221Simarom    verify_state(PORT_STATE_TX, "pause");
4323978adceSimarom
43354c1f0fcSHanoh Haim    if (m_last_all_streams_continues == false) {
434f9dcbd38Simarom        throw TrexException(" pause is supported when all streams are in continues mode ");
43554c1f0fcSHanoh Haim    }
43654c1f0fcSHanoh Haim
43754c1f0fcSHanoh Haim    if ( m_last_duration>0.0 ) {
438f9dcbd38Simarom        throw TrexException(" pause is supported when duration is not enable is start command ");
43954c1f0fcSHanoh Haim    }
44054c1f0fcSHanoh Haim
44159a3b58dSimarom    /* send a pause message */
4423aa3a83fSimarom    TrexStatelessCpToDpMsgBase *pause_msg = new TrexStatelessDpPause(m_port_id);
443ddef1a09Simarom
444ddef1a09Simarom    /* send message to all cores */
445ddef1a09Simarom    send_message_to_all_dp(pause_msg, true);
4469c32c36bSimarom
44759a3b58dSimarom    /* make sure all DP cores paused */
44859a3b58dSimarom    m_dp_events.barrier();
44995c2405dSimarom
45059a3b58dSimarom    /* change state */
45159a3b58dSimarom    change_state(PORT_STATE_PAUSE);
452106a9ecdSimarom
453106a9ecdSimarom    Json::Value data;
454106a9ecdSimarom    data["port_id"] = m_port_id;
455106a9ecdSimarom    get_stateless_obj()->get_publisher()->publish_event(TrexPublisher::EVENT_PORT_PAUSED, data);
4564d53d6e2Simarom}
4574d53d6e2Simarom
45859a3b58dSimarom
4599c32c36bSimaromvoid
4609c32c36bSimaromTrexStatelessPort::resume_traffic(void) {
4619c32c36bSimarom
46204eae221Simarom    verify_state(PORT_STATE_PAUSE, "resume");
4639c32c36bSimarom
4649c32c36bSimarom    /* generate a message to all the relevant DP cores to start transmitting */
4653aa3a83fSimarom    TrexStatelessCpToDpMsgBase *resume_msg = new TrexStatelessDpResume(m_port_id);
4669c32c36bSimarom
467ddef1a09Simarom    send_message_to_all_dp(resume_msg, true);
4689c32c36bSimarom    change_state(PORT_STATE_TX);
46995c2405dSimarom
47095c2405dSimarom    Json::Value data;
47195c2405dSimarom    data["port_id"] = m_port_id;
47295c2405dSimarom    get_stateless_obj()->get_publisher()->publish_event(TrexPublisher::EVENT_PORT_RESUMED, data);
4734d53d6e2Simarom}
4744d53d6e2Simarom
4759c32c36bSimaromvoid
476b87ac8e2SimaromTrexStatelessPort::update_traffic(const TrexPortMultiplier &mul, bool force) {
4774c94931cSimarom
4784c94931cSimarom    double factor;
4799c32c36bSimarom
48004eae221Simarom    verify_state(PORT_STATE_TX | PORT_STATE_PAUSE, "update");
4819c32c36bSimarom
4829c32c36bSimarom    /* generate a message to all the relevant DP cores to start transmitting */
483b87ac8e2Simarom    double new_factor = calculate_effective_factor(mul, force);
4844c94931cSimarom
4854c94931cSimarom    switch (mul.m_op) {
4864c94931cSimarom    case TrexPortMultiplier::OP_ABS:
4873aa3a83fSimarom        factor = new_factor / m_factor;
4884c94931cSimarom        break;
4894c94931cSimarom
4904c94931cSimarom    case TrexPortMultiplier::OP_ADD:
4913aa3a83fSimarom        factor = (m_factor + new_factor) / m_factor;
4924c94931cSimarom        break;
4934c94931cSimarom
4944c94931cSimarom    case TrexPortMultiplier::OP_SUB:
4953aa3a83fSimarom        factor = (m_factor - new_factor) / m_factor;
4964c94931cSimarom        if (factor <= 0) {
497f9dcbd38Simarom            throw TrexException("Update request will lower traffic to less than zero");
4984c94931cSimarom        }
4994c94931cSimarom        break;
5004c94931cSimarom
5014c94931cSimarom    default:
5024c94931cSimarom        assert(0);
5034c94931cSimarom        break;
5044c94931cSimarom    }
50559548ae8Simarom
50659548ae8Simarom    TrexStatelessCpToDpMsgBase *update_msg = new TrexStatelessDpUpdate(m_port_id, factor);
507ba7b5dffSimarom    send_message_to_all_dp(update_msg, true);
5089c32c36bSimarom
5093aa3a83fSimarom    m_factor *= factor;
51059548ae8Simarom
5119c32c36bSimarom}
5124d53d6e2Simarom
5138691f401Simaromvoid
514db9145d2SimaromTrexStatelessPort::push_remote(const std::string &pcap_filename,
515db9145d2Simarom                               double ipg_usec,
516e4c8e44bSYaroslav Brustinov                               double min_ipg_sec,
517db9145d2Simarom                               double speedup,
518db9145d2Simarom                               uint32_t count,
51904eae221Simarom                               double duration,
52004eae221Simarom                               bool is_dual) {
521db9145d2Simarom
5228691f401Simarom    /* command allowed only on state stream */
52304eae221Simarom    verify_state(PORT_STATE_IDLE | PORT_STATE_STREAMS, "push_remote");
5248691f401Simarom
5258691f401Simarom    /* check that file exists */
5268691f401Simarom    std::stringstream ss;
527540da82eSimarom    CCapReaderBase *reader = CCapReaderFactory::CreateReader((char *)pcap_filename.c_str(), 0, ss);
5288691f401Simarom    if (!reader) {
5298691f401Simarom        throw TrexException(ss.str());
5308691f401Simarom    }
5310d4c9932Simarom
5320d4c9932Simarom    if ( (is_dual) && (reader->get_type() != ERF) ) {
5330d4c9932Simarom        throw TrexException("dual mode is only supported on ERF format");
5340d4c9932Simarom    }
5358691f401Simarom    delete reader;
5368691f401Simarom
5378691f401Simarom    /* only one core gets to play */
5388691f401Simarom    int tx_core = m_cores_id_list[0];
5398691f401Simarom
5408691f401Simarom    /* create async event */
5418691f401Simarom    assert(m_pending_async_stop_event == TrexDpPortEvents::INVALID_ID);
5428691f401Simarom    m_pending_async_stop_event = m_dp_events.create_event(new AsyncStopEvent());
5438691f401Simarom
5448691f401Simarom    /* mark all other cores as done */
5458691f401Simarom    for (int index = 1; index < m_cores_id_list.size(); index++) {
5468691f401Simarom        /* mimic an end event */
5478691f401Simarom        m_dp_events.on_core_reporting_in(m_pending_async_stop_event, m_cores_id_list[index]);
5488691f401Simarom    }
5498691f401Simarom
5508691f401Simarom    /* send a message to core */
55175ce59e5Simarom    change_state(PORT_STATE_PCAP_TX);
5528691f401Simarom    TrexStatelessCpToDpMsgBase *push_msg = new TrexStatelessDpPushPCAP(m_port_id,
5538691f401Simarom                                                                       m_pending_async_stop_event,
55475ce59e5Simarom                                                                       pcap_filename,
55575ce59e5Simarom                                                                       ipg_usec,
556e4c8e44bSYaroslav Brustinov                                                                       min_ipg_sec,
55775ce59e5Simarom                                                                       speedup,
558db9145d2Simarom                                                                       count,
55904eae221Simarom                                                                       duration,
56004eae221Simarom                                                                       is_dual);
5618691f401Simarom    send_message_to_dp(tx_core, push_msg);
5628691f401Simarom
5638691f401Simarom    /* update subscribers */
5648691f401Simarom    Json::Value data;
5658691f401Simarom    data["port_id"] = m_port_id;
5668691f401Simarom    get_stateless_obj()->get_publisher()->publish_event(TrexPublisher::EVENT_PORT_STARTED, data);
5678691f401Simarom}
5688691f401Simarom
5694d53d6e2Simaromstd::string
5709c32c36bSimaromTrexStatelessPort::get_state_as_string() const {
5714d53d6e2Simarom
5724d53d6e2Simarom    switch (get_state()) {
5734d53d6e2Simarom    case PORT_STATE_DOWN:
57478c6593cSimarom        return "DOWN";
5754d53d6e2Simarom
5769c32c36bSimarom    case PORT_STATE_IDLE:
57778c6593cSimarom        return  "IDLE";
5789c32c36bSimarom
5799c32c36bSimarom    case PORT_STATE_STREAMS:
58078c6593cSimarom        return "STREAMS";
5814d53d6e2Simarom
5829c32c36bSimarom    case PORT_STATE_TX:
58378c6593cSimarom        return "TX";
5849c32c36bSimarom
5859c32c36bSimarom    case PORT_STATE_PAUSE:
58678c6593cSimarom        return "PAUSE";
58775ce59e5Simarom
58875ce59e5Simarom    case PORT_STATE_PCAP_TX:
58975ce59e5Simarom        return "PCAP_TX";
5904d53d6e2Simarom    }
5914d53d6e2Simarom
59278c6593cSimarom    return "UNKNOWN";
5934d53d6e2Simarom}
5944d53d6e2Simarom
595f5a5e50bSimaromint
596f5a5e50bSimaromTrexStatelessPort::get_max_stream_id() const {
597f5a5e50bSimarom    return m_stream_table.get_max_stream_id();
598f5a5e50bSimarom}
599f5a5e50bSimarom
6004d53d6e2Simaromvoid
601234779fdSimaromTrexStatelessPort::get_properties(std::string &driver) {
6024d53d6e2Simarom
60321fe2befSimarom    driver = m_api_info.driver_name;
6044d53d6e2Simarom}
6054d53d6e2Simarom
6069c32c36bSimarombool
60704eae221SimaromTrexStatelessPort::verify_state(int state, const char *cmd_name, bool should_throw) const {
6089c32c36bSimarom    if ( (state & m_port_state) == 0 ) {
6099c32c36bSimarom        if (should_throw) {
61004eae221Simarom            std::stringstream ss;
61104eae221Simarom            ss << "command '" << cmd_name << "' cannot be executed on current state: '" << get_state_as_string() << "'";
61204eae221Simarom            throw TrexException(ss.str());
6139c32c36bSimarom        } else {
6149c32c36bSimarom            return false;
6159c32c36bSimarom        }
6169c32c36bSimarom    }
6179c32c36bSimarom
6189c32c36bSimarom    return true;
6199c32c36bSimarom}
6209c32c36bSimarom
6219c32c36bSimaromvoid
6229c32c36bSimaromTrexStatelessPort::change_state(port_state_e new_state) {
6239c32c36bSimarom
6249c32c36bSimarom    m_port_state = new_state;
6259c32c36bSimarom}
6264d53d6e2Simarom
6274d53d6e2Simarom
6284d53d6e2Simaromvoid
6294d53d6e2SimaromTrexStatelessPort::encode_stats(Json::Value &port) {
6304d53d6e2Simarom
631b77fef12Simarom    TrexPlatformInterfaceStats stats;
632111bd366SYaroslav Brustinov    m_platform_api->get_interface_stats(m_port_id, stats);
6334d53d6e2Simarom
634b77fef12Simarom    port["tx_bps"]          = stats.m_stats.m_tx_bps;
635b77fef12Simarom    port["rx_bps"]          = stats.m_stats.m_rx_bps;
6366c7880b9Simarom
637b77fef12Simarom    port["tx_pps"]          = stats.m_stats.m_tx_pps;
638b77fef12Simarom    port["rx_pps"]          = stats.m_stats.m_rx_pps;
6396c7880b9Simarom
640b77fef12Simarom    port["total_tx_pkts"]   = Json::Value::UInt64(stats.m_stats.m_total_tx_pkts);
641b77fef12Simarom    port["total_rx_pkts"]   = Json::Value::UInt64(stats.m_stats.m_total_rx_pkts);
6426c7880b9Simarom
643b77fef12Simarom    port["total_tx_bytes"]  = Json::Value::UInt64(stats.m_stats.m_total_tx_bytes);
644b77fef12Simarom    port["total_rx_bytes"]  = Json::Value::UInt64(stats.m_stats.m_total_rx_bytes);
645b77fef12Simarom
646b77fef12Simarom    port["tx_rx_errors"]    = Json::Value::UInt64(stats.m_stats.m_tx_rx_errors);
6476c7880b9Simarom}
6486c7880b9Simarom
649c0a49eefSimaromvoid
650ddef1a09SimaromTrexStatelessPort::send_message_to_all_dp(TrexStatelessCpToDpMsgBase *msg, bool send_to_active_only) {
651c0a49eefSimarom
652a7317d45Simarom    for (auto core_id : m_cores_id_list) {
653ddef1a09Simarom
654ddef1a09Simarom        /* skip non active cores if requested */
655ddef1a09Simarom        if ( (send_to_active_only) && (!is_core_active(core_id)) ) {
656ddef1a09Simarom            continue;
657ddef1a09Simarom        }
658ddef1a09Simarom
6593aa3a83fSimarom        send_message_to_dp(core_id, msg->clone());
660c0a49eefSimarom    }
661c0a49eefSimarom
6623aa3a83fSimarom    /* original was not sent - delete it */
6633aa3a83fSimarom    delete msg;
6643aa3a83fSimarom}
6653aa3a83fSimarom
6663aa3a83fSimaromvoid
6673aa3a83fSimaromTrexStatelessPort::send_message_to_dp(uint8_t core_id, TrexStatelessCpToDpMsgBase *msg) {
6683aa3a83fSimarom
6693aa3a83fSimarom    /* send the message to the core */
6703aa3a83fSimarom    CNodeRing *ring = CMsgIns::Ins()->getCpDp()->getRingCpToDp(core_id);
6713aa3a83fSimarom    ring->Enqueue((CGenNode *)msg);
672c0a49eefSimarom}
673a7317d45Simarom
6741e93f5b1SIdo Barneavoid
6751e93f5b1SIdo BarneaTrexStatelessPort::send_message_to_rx(TrexStatelessCpToRxMsgBase *msg) {
6761e93f5b1SIdo Barnea
6771e93f5b1SIdo Barnea    /* send the message to the core */
6781e93f5b1SIdo Barnea    CNodeRing *ring = CMsgIns::Ins()->getCpRx()->getRingCpToDp(0);
6791e93f5b1SIdo Barnea    ring->Enqueue((CGenNode *)msg);
6801e93f5b1SIdo Barnea}
68159548ae8Simarom
6824c94931cSimaromuint64_t
683a6af2a8eSimaromTrexStatelessPort::get_port_speed_bps() const {
684111bd366SYaroslav Brustinov    return (uint64_t) m_platform_api->getPortAttrObj(m_port_id)->get_link_speed() * 1000 * 1000;
6854c94931cSimarom}
6864c94931cSimarom
687b87ac8e2Simaromstatic inline double
688b87ac8e2Simarombps_to_gbps(double bps) {
689b87ac8e2Simarom    return (bps / (1000.0 * 1000 * 1000));
690b87ac8e2Simarom}
691b87ac8e2Simarom
69259548ae8Simaromdouble
693b87ac8e2SimaromTrexStatelessPort::calculate_effective_factor(const TrexPortMultiplier &mul, bool force) {
69459548ae8Simarom
695b87ac8e2Simarom    double factor = calculate_effective_factor_internal(mul);
696b87ac8e2Simarom
697b87ac8e2Simarom    /* did we exceeded the max L1 line rate ? */
698946e5c48Simarom    double expected_l1_rate = m_graph_obj->get_max_bps_l1(factor);
699b87ac8e2Simarom
7001016c3d4SYaroslav Brustinov
7011016c3d4SYaroslav Brustinov    /* L1 BW must be positive */
7021016c3d4SYaroslav Brustinov    if (expected_l1_rate <= 0){
7031016c3d4SYaroslav Brustinov        stringstream ss;
7041016c3d4SYaroslav Brustinov        ss << "Effective bandwidth must be positive, got: " << expected_l1_rate;
7051016c3d4SYaroslav Brustinov        throw TrexException(ss.str());
7061016c3d4SYaroslav Brustinov    }
7071016c3d4SYaroslav Brustinov
7081016c3d4SYaroslav Brustinov    /* factor must be positive */
7091016c3d4SYaroslav Brustinov    if (factor <= 0) {
7101016c3d4SYaroslav Brustinov        stringstream ss;
7111016c3d4SYaroslav Brustinov        ss << "Factor must be positive, got: " << factor;
7121016c3d4SYaroslav Brustinov        throw TrexException(ss.str());
71359548ae8Simarom    }
71459548ae8Simarom
7155681d70eSimarom    /* if force simply return the value */
7165681d70eSimarom    if (force) {
7175681d70eSimarom        return factor;
7185681d70eSimarom    } else {
7195681d70eSimarom
7205681d70eSimarom        /* due to float calculations we allow 0.1% roundup */
7215681d70eSimarom        if ( (expected_l1_rate / get_port_speed_bps()) > 1.0001 )  {
7225681d70eSimarom            stringstream ss;
7235681d70eSimarom            ss << "Expected L1 B/W: '" << bps_to_gbps(expected_l1_rate) << " Gbps' exceeds port line rate: '" << bps_to_gbps(get_port_speed_bps()) << " Gbps'";
7245681d70eSimarom            throw TrexException(ss.str());
7255681d70eSimarom        }
7265681d70eSimarom
7275681d70eSimarom        /* in any case, without force, do not return any value higher than the max factor */
7285681d70eSimarom        double max_factor = m_graph_obj->get_factor_bps_l1(get_port_speed_bps());
7295681d70eSimarom        return std::min(max_factor, factor);
7305681d70eSimarom    }
7315681d70eSimarom
732b87ac8e2Simarom}
733b87ac8e2Simarom
734b87ac8e2Simaromdouble
735b87ac8e2SimaromTrexStatelessPort::calculate_effective_factor_internal(const TrexPortMultiplier &mul) {
736b87ac8e2Simarom
73759548ae8Simarom    /* we now need the graph - generate it if we don't have it (happens once) */
73859548ae8Simarom    if (!m_graph_obj) {
73959548ae8Simarom        generate_streams_graph();
74059548ae8Simarom    }
74159548ae8Simarom
7424c94931cSimarom    switch (mul.m_type) {
743b87ac8e2Simarom
744b87ac8e2Simarom    case TrexPortMultiplier::MUL_FACTOR:
745b87ac8e2Simarom        return (mul.m_value);
746b87ac8e2Simarom
7474c94931cSimarom    case TrexPortMultiplier::MUL_BPS:
74852bc62a3Simarom        return m_graph_obj->get_factor_bps_l2(mul.m_value);
7494c94931cSimarom
750e3b43560Simarom    case TrexPortMultiplier::MUL_BPSL1:
751e3b43560Simarom        return m_graph_obj->get_factor_bps_l1(mul.m_value);
752e3b43560Simarom
7534c94931cSimarom    case TrexPortMultiplier::MUL_PPS:
75452bc62a3Simarom        return m_graph_obj->get_factor_pps(mul.m_value);
7554c94931cSimarom
7564c94931cSimarom    case TrexPortMultiplier::MUL_PERCENTAGE:
7574c94931cSimarom        /* if abs percentage is from the line speed - otherwise its from the current speed */
7584c94931cSimarom
7594c94931cSimarom        if (mul.m_op == TrexPortMultiplier::OP_ABS) {
7604c94931cSimarom            double required = (mul.m_value / 100.0) * get_port_speed_bps();
76152bc62a3Simarom            return m_graph_obj->get_factor_bps_l1(required);
7624c94931cSimarom        } else {
7633aa3a83fSimarom            return (m_factor * (mul.m_value / 100.0));
7644c94931cSimarom        }
7654c94931cSimarom
7664c94931cSimarom    default:
76759548ae8Simarom        assert(0);
76859548ae8Simarom    }
7694c94931cSimarom
77059548ae8Simarom}
77159548ae8Simarom
7724c94931cSimarom
77359548ae8Simaromvoid
77459548ae8SimaromTrexStatelessPort::generate_streams_graph() {
77559548ae8Simarom
77659548ae8Simarom    /* dispose of the old one */
77759548ae8Simarom    if (m_graph_obj) {
77859548ae8Simarom        delete_streams_graph();
77959548ae8Simarom    }
78059548ae8Simarom
78159548ae8Simarom    /* fetch all the streams from the table */
78259548ae8Simarom    vector<TrexStream *> streams;
78359548ae8Simarom    get_object_list(streams);
78459548ae8Simarom
78559548ae8Simarom    TrexStreamsGraph graph;
78659548ae8Simarom    m_graph_obj = graph.generate(streams);
78759548ae8Simarom}
78859548ae8Simarom
78959548ae8Simaromvoid
79059548ae8SimaromTrexStatelessPort::delete_streams_graph() {
79159548ae8Simarom    if (m_graph_obj) {
79259548ae8Simarom        delete m_graph_obj;
79359548ae8Simarom        m_graph_obj = NULL;
79459548ae8Simarom    }
79559548ae8Simarom}
79659548ae8Simarom
7974c94931cSimarom
7984c94931cSimarom
7994c94931cSimarom/***************************
8004c94931cSimarom * port multiplier
8014c94931cSimarom *
8024c94931cSimarom **************************/
803e3b43560Simaromconst std::initializer_list<std::string> TrexPortMultiplier::g_types = {"raw", "bps", "bpsl1", "pps", "percentage"};
8044c94931cSimaromconst std::initializer_list<std::string> TrexPortMultiplier::g_ops   = {"abs", "add", "sub"};
8054c94931cSimarom
8064c94931cSimaromTrexPortMultiplier::
8074c94931cSimaromTrexPortMultiplier(const std::string &type_str, const std::string &op_str, double value) {
8084c94931cSimarom    mul_type_e type;
8094c94931cSimarom    mul_op_e   op;
8104c94931cSimarom
8114c94931cSimarom    if (type_str == "raw") {
8124c94931cSimarom        type = MUL_FACTOR;
8134c94931cSimarom
8144c94931cSimarom    } else if (type_str == "bps") {
8154c94931cSimarom        type = MUL_BPS;
8164c94931cSimarom
817e3b43560Simarom    } else if (type_str == "bpsl1") {
818e3b43560Simarom        type = MUL_BPSL1;
819e3b43560Simarom
8204c94931cSimarom    } else if (type_str == "pps") {
8214c94931cSimarom        type = MUL_PPS;
8224c94931cSimarom
8234c94931cSimarom    } else if (type_str == "percentage") {
8244c94931cSimarom        type = MUL_PERCENTAGE;
8254c94931cSimarom    } else {
8264c94931cSimarom        throw TrexException("bad type str: " + type_str);
8274c94931cSimarom    }
8284c94931cSimarom
8294c94931cSimarom    if (op_str == "abs") {
8304c94931cSimarom        op = OP_ABS;
8314c94931cSimarom
8324c94931cSimarom    } else if (op_str == "add") {
8334c94931cSimarom        op = OP_ADD;
8344c94931cSimarom
8354c94931cSimarom    } else if (op_str == "sub") {
8364c94931cSimarom        op = OP_SUB;
8374c94931cSimarom
8384c94931cSimarom    } else {
8394c94931cSimarom        throw TrexException("bad op str: " + op_str);
8404c94931cSimarom    }
8414c94931cSimarom
8424c94931cSimarom    m_type  = type;
8434c94931cSimarom    m_op    = op;
8444c94931cSimarom    m_value = value;
8454c94931cSimarom
8464c94931cSimarom}
8474c94931cSimarom
848a6af2a8eSimaromconst TrexStreamsGraphObj *
849a6af2a8eSimaromTrexStatelessPort::validate(void) {
850a6af2a8eSimarom
851a6af2a8eSimarom    /* first compile the graph */
852a6af2a8eSimarom
853a6af2a8eSimarom    vector<TrexStream *> streams;
854a6af2a8eSimarom    get_object_list(streams);
855a6af2a8eSimarom
856a6af2a8eSimarom    if (streams.size() == 0) {
857a6af2a8eSimarom        throw TrexException("no streams attached to port");
858a6af2a8eSimarom    }
859a6af2a8eSimarom
860a6af2a8eSimarom    TrexStreamsCompiler compiler;
861ba7b5dffSimarom
862ba7b5dffSimarom    /* TODO: think of this mask...*/
863ba7b5dffSimarom    TrexDPCoreMask core_mask(get_dp_core_count(), TrexDPCoreMask::MASK_ALL);
864ba7b5dffSimarom
8653aa3a83fSimarom    std::vector<TrexStreamsCompiledObj *> compiled_objs;
866a6af2a8eSimarom
867a6af2a8eSimarom    std::string fail_msg;
8683aa3a83fSimarom    bool rc = compiler.compile(m_port_id,
8693aa3a83fSimarom                               streams,
8703aa3a83fSimarom                               compiled_objs,
871ba7b5dffSimarom                               core_mask,
87223e1f07eSimarom                               1.0,
8733aa3a83fSimarom                               &fail_msg);
874a6af2a8eSimarom    if (!rc) {
875a6af2a8eSimarom        throw TrexException(fail_msg);
876a6af2a8eSimarom    }
877a6af2a8eSimarom
8783aa3a83fSimarom    for (auto obj : compiled_objs) {
8793aa3a83fSimarom        delete obj;
8803aa3a83fSimarom    }
8813aa3a83fSimarom
882a6af2a8eSimarom    /* now create a stream graph */
883a6af2a8eSimarom    if (!m_graph_obj) {
884a6af2a8eSimarom        generate_streams_graph();
885a6af2a8eSimarom    }
886a6af2a8eSimarom
887a6af2a8eSimarom    return m_graph_obj;
888a6af2a8eSimarom}
88995c2405dSimarom
89095c2405dSimarom
8912dff2ccfSimarom
8922dff2ccfSimaromvoid
893eb899885SimaromTrexStatelessPort::get_port_effective_rate(double &pps,
894eb899885Simarom                                           double &bps_L1,
895eb899885Simarom                                           double &bps_L2,
896eb899885Simarom                                           double &percentage) {
89779b2a5eaSimarom
89879b2a5eaSimarom    if (get_stream_count() == 0) {
8992dff2ccfSimarom        return;
9002dff2ccfSimarom    }
90179b2a5eaSimarom
90279b2a5eaSimarom    if (!m_graph_obj) {
90379b2a5eaSimarom        generate_streams_graph();
90479b2a5eaSimarom    }
90579b2a5eaSimarom
906946e5c48Simarom    pps        = m_graph_obj->get_max_pps(m_factor);
907946e5c48Simarom    bps_L1     = m_graph_obj->get_max_bps_l1(m_factor);
908946e5c48Simarom    bps_L2     = m_graph_obj->get_max_bps_l2(m_factor);
909eb899885Simarom    percentage = (bps_L1 / get_port_speed_bps()) * 100.0;
910eb899885Simarom
9112dff2ccfSimarom}
9122dff2ccfSimarom
91321fe2befSimaromvoid
91421fe2befSimaromTrexStatelessPort::get_pci_info(std::string &pci_addr, int &numa_node) {
91521fe2befSimarom    pci_addr  = m_api_info.pci_addr;
91621fe2befSimarom    numa_node = m_api_info.numa_node;
9175f17c48aSimarom}
918aaef3f95Simarom
91939000f46SYaroslav Brustinovvoid
92039000f46SYaroslav BrustinovTrexStatelessPort::get_hw_mac(std::string &hw_mac) {
92139000f46SYaroslav Brustinov    utl_macaddr_to_str(m_api_info.hw_macaddr, hw_mac);
92239000f46SYaroslav Brustinov}
92339000f46SYaroslav Brustinov
924f0ab9ebaSIdo Barneavoid
925f0ab9ebaSIdo BarneaTrexStatelessPort::add_stream(TrexStream *stream) {
926f0ab9ebaSIdo Barnea
92704eae221Simarom    verify_state(PORT_STATE_IDLE | PORT_STATE_STREAMS, "add_stream");
928f0ab9ebaSIdo Barnea
9295cfeb192SYaroslav Brustinov    if (m_stream_table.size() >= MAX_STREAMS) {
9305cfeb192SYaroslav Brustinov        throw TrexException("Reached limit of " + std::to_string(MAX_STREAMS) + " streams at the port.");
931cc4bd93bSYaroslav Brustinov    }
9324d311b49SIdo Barnea    get_stateless_obj()->m_rx_flow_stat.add_stream(stream);
9334d311b49SIdo Barnea
934f0ab9ebaSIdo Barnea    m_stream_table.add_stream(stream);
935f0ab9ebaSIdo Barnea    delete_streams_graph();
936f0ab9ebaSIdo Barnea
937f0ab9ebaSIdo Barnea    change_state(PORT_STATE_STREAMS);
938f0ab9ebaSIdo Barnea}
939f0ab9ebaSIdo Barnea
940f0ab9ebaSIdo Barneavoid
941f0ab9ebaSIdo BarneaTrexStatelessPort::remove_stream(TrexStream *stream) {
942f0ab9ebaSIdo Barnea
94304eae221Simarom    verify_state(PORT_STATE_STREAMS, "remove_stream");
944f0ab9ebaSIdo Barnea
945f0ab9ebaSIdo Barnea    get_stateless_obj()->m_rx_flow_stat.del_stream(stream);
946f0ab9ebaSIdo Barnea
947f0ab9ebaSIdo Barnea    m_stream_table.remove_stream(stream);
948f0ab9ebaSIdo Barnea    delete_streams_graph();
949f0ab9ebaSIdo Barnea
950f0ab9ebaSIdo Barnea    if (m_stream_table.size() == 0) {
951f0ab9ebaSIdo Barnea        change_state(PORT_STATE_IDLE);
952f0ab9ebaSIdo Barnea    }
953f0ab9ebaSIdo Barnea}
954f0ab9ebaSIdo Barnea
955f0ab9ebaSIdo Barneavoid
956f0ab9ebaSIdo BarneaTrexStatelessPort::remove_and_delete_all_streams() {
95704eae221Simarom    verify_state(PORT_STATE_IDLE | PORT_STATE_STREAMS, "remove_and_delete_all_streams");
958f0ab9ebaSIdo Barnea
959f0ab9ebaSIdo Barnea    vector<TrexStream *> streams;
960f0ab9ebaSIdo Barnea    get_object_list(streams);
961f0ab9ebaSIdo Barnea
962f0ab9ebaSIdo Barnea    for (auto stream : streams) {
963f0ab9ebaSIdo Barnea        remove_stream(stream);
964f0ab9ebaSIdo Barnea        delete stream;
965f0ab9ebaSIdo Barnea    }
966f0ab9ebaSIdo Barnea}
967f0ab9ebaSIdo Barnea
968418fd3d0Simarom/**
969418fd3d0Simarom * enable/disable service mode
970418fd3d0Simarom * sends a query to the RX core
971418fd3d0Simarom *
972418fd3d0Simarom */
973418fd3d0Simaromvoid
974418fd3d0SimaromTrexStatelessPort::set_service_mode(bool enabled) {
975418fd3d0Simarom    static MsgReply<TrexStatelessRxQuery::query_rc_e> reply;
976418fd3d0Simarom    reply.reset();
977418fd3d0Simarom
978418fd3d0Simarom    TrexStatelessRxQuery::query_type_e query_type = (enabled ? TrexStatelessRxQuery::SERVICE_MODE_ON : TrexStatelessRxQuery::SERVICE_MODE_OFF);
979418fd3d0Simarom
980418fd3d0Simarom    TrexStatelessRxQuery *msg = new TrexStatelessRxQuery(m_port_id, query_type, reply);
981418fd3d0Simarom    send_message_to_rx( (TrexStatelessCpToRxMsgBase *)msg );
982418fd3d0Simarom
983418fd3d0Simarom    TrexStatelessRxQuery::query_rc_e rc = reply.wait_for_reply();
984418fd3d0Simarom
985418fd3d0Simarom    switch (rc) {
986418fd3d0Simarom    case TrexStatelessRxQuery::RC_OK:
987418fd3d0Simarom        if (enabled) {
988418fd3d0Simarom            getPortAttrObj()->set_rx_filter_mode(RX_FILTER_MODE_ALL);
989418fd3d0Simarom        } else {
990418fd3d0Simarom            getPortAttrObj()->set_rx_filter_mode(RX_FILTER_MODE_HW);
991418fd3d0Simarom        }
992418fd3d0Simarom        m_is_service_mode_on = enabled;
99317d58dbaSimarom        break;
994418fd3d0Simarom
995418fd3d0Simarom    case TrexStatelessRxQuery::RC_FAIL_RX_QUEUE_ACTIVE:
996418fd3d0Simarom        throw TrexException("unable to disable service mode - please remove RX queue");
997418fd3d0Simarom
998418fd3d0Simarom    case TrexStatelessRxQuery::RC_FAIL_CAPTURE_ACTIVE:
999418fd3d0Simarom        throw TrexException("unable to disable service mode - an active capture on port " + std::to_string(m_port_id) + " exists");
1000418fd3d0Simarom
1001418fd3d0Simarom    default:
1002418fd3d0Simarom        assert(0);
1003418fd3d0Simarom    }
100417d58dbaSimarom
1005b22e3ed1Simarom    /* update the all the relevant dp cores to move to service mode */
100617d58dbaSimarom    TrexStatelessDpServiceMode *dp_msg = new TrexStatelessDpServiceMode(m_port_id, enabled);
100717d58dbaSimarom    send_message_to_all_dp(dp_msg);
1008418fd3d0Simarom}
1009418fd3d0Simarom
10100337db2bSimarom
1011f9a0c5e2Simaromvoid
1012f9a0c5e2SimaromTrexStatelessPort::start_rx_queue(uint64_t size) {
1013051a334bSimarom    static MsgReply<bool> reply;
1014051a334bSimarom
1015051a334bSimarom    reply.reset();
1016051a334bSimarom
1017051a334bSimarom    TrexStatelessRxStartQueue *msg = new TrexStatelessRxStartQueue(m_port_id, size, reply);
1018537f5831Simarom    send_message_to_rx( (TrexStatelessCpToRxMsgBase *)msg );
1019537f5831Simarom
1020537f5831Simarom    /* we cannot return ACK to the user until the RX core has approved
1021537f5831Simarom       this might cause the user to lose some packets from the queue
1022537f5831Simarom     */
1023051a334bSimarom    reply.wait_for_reply();
1024f9a0c5e2Simarom}
1025f9a0c5e2Simarom
1026f9a0c5e2Simaromvoid
1027f9a0c5e2SimaromTrexStatelessPort::stop_rx_queue() {
1028f9a0c5e2Simarom    TrexStatelessCpToRxMsgBase *msg = new TrexStatelessRxStopQueue(m_port_id);
1029f9a0c5e2Simarom    send_message_to_rx(msg);
1030a1ade6fdSimarom}
1031a1ade6fdSimarom
1032a1ade6fdSimarom
10335257dbb8Simaromconst TrexPktBuffer *
1034d09b1239SimaromTrexStatelessPort::get_rx_queue_pkts() {
10355257dbb8Simarom    static MsgReply<const TrexPktBuffer *> reply;
1036051a334bSimarom
1037051a334bSimarom    reply.reset();
10380337db2bSimarom
1039051a334bSimarom    TrexStatelessRxQueueGetPkts *msg = new TrexStatelessRxQueueGetPkts(m_port_id, reply);
1040051a334bSimarom    send_message_to_rx( (TrexStatelessCpToRxMsgBase *)msg );
1041051a334bSimarom
1042051a334bSimarom    return reply.wait_for_reply();
1043051a334bSimarom}
1044051a334bSimarom
10450c458152Simarom
10460fdd81a9Simarom/**
10470fdd81a9Simarom * configures port in L2 mode
10480fdd81a9Simarom *
10490fdd81a9Simarom */
10500fdd81a9Simaromvoid
10510fdd81a9SimaromTrexStatelessPort::set_l2_mode(const uint8_t *dest_mac) {
10520fdd81a9Simarom
1053f51c210aSimarom    /* not valid under traffic */
1054f51c210aSimarom    verify_state(PORT_STATE_IDLE | PORT_STATE_STREAMS, "set_l2_mode");
1055f51c210aSimarom
105634cb66c9Simarom    /* configure port attributes for L2 */
105734cb66c9Simarom    getPortAttrObj()->set_l2_mode(dest_mac);
105834cb66c9Simarom
105934cb66c9Simarom    /* update RX core */
10600fdd81a9Simarom    TrexStatelessRxSetL2Mode *msg = new TrexStatelessRxSetL2Mode(m_port_id);
10610fdd81a9Simarom    send_message_to_rx( (TrexStatelessCpToRxMsgBase *)msg );
10620fdd81a9Simarom}
10630fdd81a9Simarom
10640fdd81a9Simarom/**
10650fdd81a9Simarom * configures port in L3 mode - unresolved
10660fdd81a9Simarom */
10670fdd81a9Simaromvoid
10680fdd81a9SimaromTrexStatelessPort::set_l3_mode(uint32_t src_ipv4, uint32_t dest_ipv4) {
10690fdd81a9Simarom
1070f51c210aSimarom    /* not valid under traffic */
1071f51c210aSimarom    verify_state(PORT_STATE_IDLE | PORT_STATE_STREAMS, "set_l3_mode");
1072f51c210aSimarom
107334cb66c9Simarom    /* configure port attributes with L3 */
107434cb66c9Simarom    getPortAttrObj()->set_l3_mode(src_ipv4, dest_ipv4);
107534cb66c9Simarom
10760fdd81a9Simarom    /* send RX core the relevant info */
10770fdd81a9Simarom    CManyIPInfo ip_info;
107834cb66c9Simarom    ip_info.insert(COneIPv4Info(src_ipv4, 0, getPortAttrObj()->get_layer_cfg().get_ether().get_src()));
10790fdd81a9Simarom
10800fdd81a9Simarom    TrexStatelessRxSetL3Mode *msg = new TrexStatelessRxSetL3Mode(m_port_id, ip_info, false);
10810fdd81a9Simarom    send_message_to_rx( (TrexStatelessCpToRxMsgBase *)msg );
10820fdd81a9Simarom}
10830fdd81a9Simarom
10840fdd81a9Simarom/**
10850fdd81a9Simarom * configures port in L3 mode - resolved
10860fdd81a9Simarom *
10870fdd81a9Simarom */
10880c458152Simaromvoid
10890fdd81a9SimaromTrexStatelessPort::set_l3_mode(uint32_t src_ipv4, uint32_t dest_ipv4, const uint8_t *resolved_mac) {
10900c458152Simarom
1091f51c210aSimarom    verify_state(PORT_STATE_IDLE | PORT_STATE_STREAMS, "set_l3_mode");
1092f51c210aSimarom
109334cb66c9Simarom    /* configure port attributes with L3 */
109434cb66c9Simarom    getPortAttrObj()->set_l3_mode(src_ipv4, dest_ipv4, resolved_mac);
10950c458152Simarom
10960fdd81a9Simarom    /* send RX core the relevant info */
10970fdd81a9Simarom    CManyIPInfo ip_info;
109834cb66c9Simarom    ip_info.insert(COneIPv4Info(src_ipv4, 0, getPortAttrObj()->get_layer_cfg().get_ether().get_src()));
10990fdd81a9Simarom
11000fdd81a9Simarom    bool is_grat_arp_needed = !getPortAttrObj()->is_loopback();
11010fdd81a9Simarom
11020fdd81a9Simarom    TrexStatelessRxSetL3Mode *msg = new TrexStatelessRxSetL3Mode(m_port_id, ip_info, is_grat_arp_needed);
11030c458152Simarom    send_message_to_rx( (TrexStatelessCpToRxMsgBase *)msg );
11040c458152Simarom}
11050c458152Simarom
11060fdd81a9Simarom
1107051a334bSimaromJson::Value
1108051a334bSimaromTrexStatelessPort::rx_features_to_json() {
1109051a334bSimarom    static MsgReply<Json::Value> reply;
1110051a334bSimarom
1111051a334bSimarom    reply.reset();
1112558ce764Simarom
1113051a334bSimarom    TrexStatelessRxFeaturesToJson *msg = new TrexStatelessRxFeaturesToJson(m_port_id, reply);
1114537f5831Simarom    send_message_to_rx( (TrexStatelessCpToRxMsgBase *)msg );
11150337db2bSimarom
1116051a334bSimarom    return reply.wait_for_reply();
11170337db2bSimarom}
11180337db2bSimarom
111995c2405dSimarom/************* Trex Port Owner **************/
112095c2405dSimarom
112195c2405dSimaromTrexPortOwner::TrexPortOwner() {
112295c2405dSimarom    m_is_free = true;
11237e599394Simarom    m_session_id = 0;
112495c2405dSimarom
112595c2405dSimarom    /* for handlers random generation */
112681059eb5Simarom    m_seed = time(NULL);
112795c2405dSimarom}
112895c2405dSimarom
112995c2405dSimaromconst std::string TrexPortOwner::g_unowned_name = "<FREE>";
113095c2405dSimaromconst std::string TrexPortOwner::g_unowned_handler = "";
1131