/* * Copyright (c) 2001-2020 Mellanox Technologies, Ltd. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU * General Public License (GPL) Version 2, available from the file * COPYING in the main directory of this source tree, or the * BSD license below: * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "utils/bullseye.h" #include "dst_entry.h" #include "vma/proto/rule_table_mgr.h" #include "vma/proto/route_table_mgr.h" #include "vma/util/utils.h" #define MODULE_NAME "dst" #define dst_logpanic __log_panic #define dst_logerr __log_err #define dst_logwarn __log_warn #define dst_loginfo __log_info #define dst_logdbg __log_info_dbg #define dst_logfunc __log_info_func #define dst_logfuncall __log_info_funcall dst_entry::dst_entry(in_addr_t dst_ip, uint16_t dst_port, uint16_t src_port, socket_data &sock_data, resource_allocation_key &ring_alloc_logic): m_dst_ip(dst_ip), m_dst_port(dst_port), m_src_port(src_port), m_bound_ip(0), m_so_bindtodevice_ip(0), m_route_src_ip(0), m_pkt_src_ip(0), m_ring_alloc_logic(sock_data.fd, ring_alloc_logic, this), m_p_tx_mem_buf_desc_list(NULL), m_b_tx_mem_buf_desc_list_pending(false), m_ttl(sock_data.ttl), m_tos(sock_data.tos), m_pcp(sock_data.pcp), m_id(0) { dst_logdbg("dst:%s:%d src: %d", m_dst_ip.to_str().c_str(), ntohs(m_dst_port), ntohs(m_src_port)); init_members(); } dst_entry::~dst_entry() { dst_logdbg("%s", to_str().c_str()); if (m_p_neigh_entry) { ip_address dst_addr = m_dst_ip; if (m_p_rt_val && m_p_rt_val->get_gw_addr() != INADDR_ANY && !dst_addr.is_mc()) { dst_addr = m_p_rt_val->get_gw_addr(); } g_p_neigh_table_mgr->unregister_observer(neigh_key(dst_addr, m_p_net_dev_val),this); } if (m_p_rt_entry) { g_p_route_table_mgr->unregister_observer(route_rule_table_key(m_dst_ip.get_in_addr(), m_route_src_ip, m_tos), this); m_p_rt_entry = NULL; } if (m_p_ring) { if (m_sge) { delete[] m_sge; m_sge = NULL; } if (m_p_tx_mem_buf_desc_list) { m_p_ring->mem_buf_tx_release(m_p_tx_mem_buf_desc_list, true); m_p_tx_mem_buf_desc_list = NULL; } m_p_net_dev_val->release_ring(m_ring_alloc_logic.get_key()); m_p_ring = NULL; } if (m_p_net_dev_entry && m_p_net_dev_val) { g_p_net_device_table_mgr->unregister_observer(m_p_net_dev_val->get_local_addr(), this); } if (m_p_send_wqe_handler) { delete m_p_send_wqe_handler; m_p_send_wqe_handler = NULL; } if (m_p_neigh_val) { delete m_p_neigh_val; m_p_neigh_val = NULL; } dst_logdbg("Done %s", to_str().c_str()); } void dst_entry::init_members() { set_state(false); m_p_rt_val = NULL; m_p_net_dev_val = NULL; m_p_ring = NULL; m_p_net_dev_entry = NULL; m_p_neigh_entry = NULL; m_p_neigh_val = NULL; m_p_rt_entry = NULL; memset(&m_inline_send_wqe, 0, sizeof(m_inline_send_wqe)); memset(&m_not_inline_send_wqe, 0, sizeof(m_not_inline_send_wqe)); memset(&m_fragmented_send_wqe, 0, sizeof(m_not_inline_send_wqe)); m_p_send_wqe_handler = NULL; m_sge = NULL; m_b_is_offloaded = true; m_b_is_initialized = false; m_p_send_wqe = NULL; m_max_inline = 0; m_max_ip_payload_size = 0; m_max_udp_payload_size = 0; m_b_force_os = false; } void dst_entry::set_src_addr() { m_pkt_src_ip = INADDR_ANY; if (m_route_src_ip) { m_pkt_src_ip = m_route_src_ip; } else if (m_p_rt_val && m_p_rt_val->get_src_addr()) { m_pkt_src_ip = m_p_rt_val->get_src_addr(); } else if (m_p_net_dev_val && m_p_net_dev_val->get_local_addr()) { m_pkt_src_ip = m_p_net_dev_val->get_local_addr(); } } bool dst_entry::update_net_dev_val() { bool ret_val = false; net_device_val* new_nd_val = m_p_net_dev_val; if (m_so_bindtodevice_ip && g_p_net_device_table_mgr) { new_nd_val = g_p_net_device_table_mgr->get_net_device_val(m_so_bindtodevice_ip); // TODO should we register to g_p_net_device_table_mgr with m_p_net_dev_entry? // what should we do with an old one? dst_logdbg("getting net_dev_val by bindtodevice ip"); } else if (m_p_rt_entry) { new_nd_val = m_p_rt_entry->get_net_dev_val(); } if (m_p_net_dev_val != new_nd_val) { dst_logdbg("updating net_device"); if (m_p_neigh_entry) { ip_address dst_addr = m_dst_ip; if (m_p_rt_val && m_p_rt_val->get_gw_addr() != INADDR_ANY && !dst_addr.is_mc()) { dst_addr = m_p_rt_val->get_gw_addr(); } g_p_neigh_table_mgr->unregister_observer(neigh_key(dst_addr, m_p_net_dev_val),this); m_p_neigh_entry = NULL; } // Change the net_device, clean old resources... release_ring(); // Save the new net_device m_p_net_dev_val = new_nd_val; if (m_p_net_dev_val) { // more resource clean and alloc... ret_val = alloc_transport_dep_res(); } else { dst_logdbg("Netdev is not offloaded fallback to OS"); } } else { if (m_p_net_dev_val) { // Only if we already had a valid net_device_val which did not change dst_logdbg("no change in net_device"); ret_val = true; } else { dst_logdbg("Netdev is not offloaded fallback to OS"); } } return ret_val; } bool dst_entry::update_rt_val() { bool ret_val = true; route_val* p_rt_val = NULL; if (m_p_rt_entry && m_p_rt_entry->get_val(p_rt_val)) { if (m_p_rt_val == p_rt_val) { dst_logdbg("no change in route_val"); } else { dst_logdbg("updating route val"); m_p_rt_val = p_rt_val; } } else { dst_logdbg("Route entry is not valid"); ret_val = false; } return ret_val; } bool dst_entry::resolve_net_dev(bool is_connect) { bool ret_val = false; cache_entry_subject* p_ces = NULL; if (ZERONET_N(m_dst_ip.get_in_addr())) { dst_logdbg("VMA does not offload zero net IP address"); return ret_val; } if (LOOPBACK_N(m_dst_ip.get_in_addr())) { dst_logdbg("VMA does not offload local loopback IP address"); return ret_val; } //When VMA will support routing with OIF, we need to check changing in outgoing interface //Source address changes is not checked since multiple bind is not allowed on the same socket if (!m_p_rt_entry) { m_route_src_ip = m_bound_ip; route_rule_table_key rtk(m_dst_ip.get_in_addr(), m_route_src_ip, m_tos); if (g_p_route_table_mgr->register_observer(rtk, this, &p_ces)) { // In case this is the first time we trying to resolve route entry, // means that register_observer was run m_p_rt_entry = dynamic_cast(p_ces); if (is_connect && !m_route_src_ip) { route_val* p_rt_val = NULL; if (m_p_rt_entry && m_p_rt_entry->get_val(p_rt_val) && p_rt_val->get_src_addr()) { g_p_route_table_mgr->unregister_observer(rtk, this); m_route_src_ip = p_rt_val->get_src_addr(); route_rule_table_key new_rtk(m_dst_ip.get_in_addr(), m_route_src_ip, m_tos); if (g_p_route_table_mgr->register_observer(new_rtk, this, &p_ces)) { m_p_rt_entry = dynamic_cast(p_ces); } else { dst_logdbg("Error in route resolving logic"); return ret_val; } } } } else { dst_logdbg("Error in registering route entry"); return ret_val; } } if (update_rt_val()) { ret_val = update_net_dev_val(); } return ret_val; } bool dst_entry::resolve_neigh() { dst_logdbg(""); bool ret_val = false; ip_address dst_addr = m_dst_ip; if (m_p_rt_val && m_p_rt_val->get_gw_addr() != INADDR_ANY && !dst_addr.is_mc()) { dst_addr = m_p_rt_val->get_gw_addr(); } cache_entry_subject* p_ces = NULL; if (m_p_neigh_entry || g_p_neigh_table_mgr->register_observer(neigh_key(dst_addr, m_p_net_dev_val), this, &p_ces)) { if(m_p_neigh_entry == NULL) m_p_neigh_entry = dynamic_cast(p_ces); if (m_p_neigh_entry) { if (m_p_neigh_entry->get_peer_info(m_p_neigh_val)) { dst_logdbg("neigh is valid"); ret_val = true; } else { dst_logdbg("neigh is not valid"); } } } return ret_val; } bool dst_entry::resolve_ring() { bool ret_val = false; if (m_p_net_dev_val) { if (!m_p_ring) { dst_logdbg("getting a ring"); m_p_ring = m_p_net_dev_val->reserve_ring(m_ring_alloc_logic.create_new_key(m_pkt_src_ip)); } if (m_p_ring) { if (m_sge) { delete[] m_sge; m_sge = NULL; } #ifdef DEFINED_TSO m_sge = new (nothrow) struct ibv_sge [m_p_ring->get_max_send_sge()]; #else m_sge = new (nothrow) struct ibv_sge [2]; #endif /* DEFINED_TSO */ if (!m_sge) { dst_logpanic("%s Failed to allocate send SGE", to_str().c_str()); } m_max_inline = m_p_ring->get_max_inline_data(); m_max_inline = std::min(m_max_inline, get_route_mtu() + (uint32_t)m_header.m_transport_header_len); ret_val = true; } } return ret_val; } bool dst_entry::release_ring() { bool ret_val = false; if (m_p_net_dev_val) { if (m_p_ring) { if (m_p_tx_mem_buf_desc_list) { m_p_ring->mem_buf_tx_release(m_p_tx_mem_buf_desc_list, true); m_p_tx_mem_buf_desc_list = NULL; } dst_logdbg("releasing a ring"); if (m_p_net_dev_val->release_ring(m_ring_alloc_logic.get_key())) { dst_logerr("Failed to release ring for allocation key %s", m_ring_alloc_logic.get_key()->to_str()); } m_p_ring = NULL; } ret_val = true; } return ret_val; } void dst_entry::notify_cb() { dst_logdbg(""); set_state(false); } void dst_entry::configure_ip_header(header *h, uint16_t packet_id) { h->configure_ip_header(get_protocol_type(), m_pkt_src_ip, m_dst_ip.get_in_addr(), m_ttl, m_tos, packet_id); } bool dst_entry::conf_l2_hdr_and_snd_wqe_eth() { bool ret_val = false; //Maybe we after invalidation so we free the wqe_handler since we are going to build it from scratch if (m_p_send_wqe_handler) { delete m_p_send_wqe_handler; m_p_send_wqe_handler = NULL; } m_p_send_wqe_handler = new wqe_send_handler(); if (!m_p_send_wqe_handler) { dst_logpanic("%s Failed to allocate send WQE handler", to_str().c_str()); } m_p_send_wqe_handler->init_inline_wqe(m_inline_send_wqe, get_sge_lst_4_inline_send(), get_inline_sge_num()); m_p_send_wqe_handler->init_not_inline_wqe(m_not_inline_send_wqe, get_sge_lst_4_not_inline_send(), 1); m_p_send_wqe_handler->init_wqe(m_fragmented_send_wqe, get_sge_lst_4_not_inline_send(), 1); net_device_val_eth *netdevice_eth = dynamic_cast(m_p_net_dev_val); BULLSEYE_EXCLUDE_BLOCK_START if (netdevice_eth) { BULLSEYE_EXCLUDE_BLOCK_END const L2_address *src = m_p_net_dev_val->get_l2_address(); const L2_address *dst = m_p_neigh_val->get_l2_address(); BULLSEYE_EXCLUDE_BLOCK_START if (src && dst) { BULLSEYE_EXCLUDE_BLOCK_END if (netdevice_eth->get_vlan()) { //vlan interface uint32_t prio = get_priority_by_tc_class(m_pcp); uint16_t vlan_tci = (prio << NET_ETH_VLAN_PCP_OFFSET) | netdevice_eth->get_vlan(); m_header.configure_vlan_eth_headers(*src, *dst, vlan_tci); } else { m_header.configure_eth_headers(*src, *dst); } init_sge(); ret_val = true; } else { dst_logerr("Can't build proper L2 header, L2 address is not available"); } } else { dst_logerr("Dynamic cast failed, can't build proper L2 header"); } return ret_val; } bool dst_entry::conf_l2_hdr_and_snd_wqe_ib() { bool ret_val = false; neigh_ib_val *neigh_ib = dynamic_cast(m_p_neigh_val); BULLSEYE_EXCLUDE_BLOCK_START if (!neigh_ib) { dst_logerr("Dynamic cast to neigh_ib failed, can't build proper ibv_send_wqe: header"); BULLSEYE_EXCLUDE_BLOCK_END } else { uint32_t qpn = neigh_ib->get_qpn(); uint32_t qkey = neigh_ib->get_qkey(); struct ibv_ah *ah = (struct ibv_ah *)neigh_ib->get_ah(); //Maybe we after invalidation so we free the wqe_handler since we are going to build it from scratch if (m_p_send_wqe_handler) { delete m_p_send_wqe_handler; m_p_send_wqe_handler = NULL; } m_p_send_wqe_handler = new wqe_send_ib_handler(); BULLSEYE_EXCLUDE_BLOCK_START if (!m_p_send_wqe_handler) { dst_logpanic("%s Failed to allocate send WQE handler", to_str().c_str()); } BULLSEYE_EXCLUDE_BLOCK_END ((wqe_send_ib_handler *)(m_p_send_wqe_handler))->init_inline_ib_wqe(m_inline_send_wqe, get_sge_lst_4_inline_send(), get_inline_sge_num(), ah, qpn, qkey); ((wqe_send_ib_handler*)(m_p_send_wqe_handler))->init_not_inline_ib_wqe(m_not_inline_send_wqe, get_sge_lst_4_not_inline_send(), 1, ah, qpn, qkey); ((wqe_send_ib_handler*)(m_p_send_wqe_handler))->init_ib_wqe(m_fragmented_send_wqe, get_sge_lst_4_not_inline_send(), 1, ah, qpn, qkey); m_header.configure_ipoib_headers(); init_sge(); ret_val = true; } return ret_val; } bool dst_entry::conf_hdrs_and_snd_wqe() { transport_type_t tranposrt = VMA_TRANSPORT_IB; bool ret_val = true; dst_logdbg("dst_entry %s configuring the header template", to_str().c_str()); configure_ip_header(&m_header); if (m_p_net_dev_val) { tranposrt = m_p_net_dev_val->get_transport_type(); } switch (tranposrt) { case VMA_TRANSPORT_ETH: ret_val = conf_l2_hdr_and_snd_wqe_eth(); break; case VMA_TRANSPORT_IB: default: ret_val = conf_l2_hdr_and_snd_wqe_ib(); break; } return ret_val; } #if _BullseyeCoverage #pragma BullseyeCoverage off #endif bool dst_entry::get_net_dev_val() { bool ret_val = false; if (m_p_rt_entry) { m_p_rt_entry->get_val(m_p_rt_val); ret_val = true; } else { dst_logdbg("%s doesn't use route table to resolve netdev", to_str().c_str()); } return ret_val; } #if _BullseyeCoverage #pragma BullseyeCoverage on #endif //Implementation of pure virtual function of neigh_observer transport_type_t dst_entry::get_obs_transport_type() const { if(m_p_net_dev_val) return(m_p_net_dev_val->get_transport_type()); return VMA_TRANSPORT_UNKNOWN; } #if _BullseyeCoverage #pragma BullseyeCoverage off #endif flow_tuple dst_entry::get_flow_tuple() const { in_addr_t dst_ip = 0; in_protocol_t protocol = PROTO_UNDEFINED; dst_ip = m_dst_ip.get_in_addr(); protocol = (in_protocol_t)get_protocol_type(); return flow_tuple(dst_ip, m_dst_port, m_pkt_src_ip, m_src_port, protocol); } #if _BullseyeCoverage #pragma BullseyeCoverage on #endif bool dst_entry::offloaded_according_to_rules() { bool ret_val = true; transport_t target_transport; sockaddr_in to; memset(&to, 0, sizeof(to)); to.sin_family = AF_INET; to.sin_addr.s_addr = m_dst_ip.get_in_addr(); to.sin_port = m_dst_port; target_transport = get_transport(to); if (target_transport == TRANS_OS) { ret_val = false; } return ret_val; } bool dst_entry::prepare_to_send(struct vma_rate_limit_t &rate_limit, bool skip_rules, bool is_connect) { bool resolved = false; m_slow_path_lock.lock(); if (!m_b_is_initialized) { if((!skip_rules) && (!offloaded_according_to_rules())) { dst_logdbg("dst_entry in BLACK LIST!"); m_b_is_offloaded = false; m_b_force_os = true; } m_b_is_initialized = true; } dst_logdbg("%s", to_str().c_str()); if (!m_b_force_os && !is_valid()) { bool is_ofloaded = false; set_state(true); if (resolve_net_dev(is_connect)) { set_src_addr(); // overwrite mtu from route if exists m_max_udp_payload_size = get_route_mtu() - sizeof(struct iphdr); m_max_ip_payload_size = m_max_udp_payload_size & ~0x7; if (resolve_ring()) { is_ofloaded = true; modify_ratelimit(rate_limit); if (resolve_neigh()) { if (get_obs_transport_type() == VMA_TRANSPORT_ETH) { dst_logdbg("local mac: %s peer mac: %s", m_p_net_dev_val->get_l2_address()->to_str().c_str(), m_p_neigh_val->get_l2_address()->to_str().c_str()); } else { dst_logdbg("peer L2 address: %s", m_p_neigh_val->get_l2_address()->to_str().c_str()); } configure_headers(); m_id = m_p_ring->generate_id(m_p_net_dev_val->get_l2_address()->get_address(), m_p_neigh_val->get_l2_address()->get_address(), ((ethhdr*)(m_header.m_actual_hdr_addr))->h_proto /* if vlan, use vlan proto */, htons(ETH_P_IP), m_pkt_src_ip, m_dst_ip.get_in_addr(), m_src_port, m_dst_port); if (m_p_tx_mem_buf_desc_list) { m_p_ring->mem_buf_tx_release(m_p_tx_mem_buf_desc_list, true); m_p_tx_mem_buf_desc_list = NULL; } resolved = true; } } } m_b_is_offloaded = is_ofloaded; if (m_b_is_offloaded) { dst_logdbg("dst_entry is offloaded!"); } else { dst_logdbg("dst_entry is NOT offloaded!"); } if (!resolved) { set_state(false); } } m_slow_path_lock.unlock(); return m_b_is_offloaded; } bool dst_entry::try_migrate_ring(lock_base& socket_lock) { bool ret = false; if (m_ring_alloc_logic.is_logic_support_migration()) { if (!m_tx_migration_lock.trylock()) { if (m_ring_alloc_logic.should_migrate_ring()) { resource_allocation_key old_key(*m_ring_alloc_logic.get_key()); do_ring_migration(socket_lock, old_key); ret = true; } m_tx_migration_lock.unlock(); } } return ret; } int dst_entry::get_route_mtu() { if (m_p_rt_val && m_p_rt_val->get_mtu() > 0 ) { return m_p_rt_val->get_mtu(); } return m_p_net_dev_val->get_mtu(); } void dst_entry::do_ring_migration(lock_base& socket_lock, resource_allocation_key &old_key) { m_slow_path_lock.lock(); if (!m_p_net_dev_val || !m_p_ring) { m_slow_path_lock.unlock(); return; } uint64_t new_calc_id = m_ring_alloc_logic.calc_res_key_by_logic(); resource_allocation_key *new_key = m_ring_alloc_logic.get_key(); // Check again if migration is needed before migration if (old_key.get_user_id_key() == new_calc_id && old_key.get_ring_alloc_logic() == new_key->get_ring_alloc_logic()) { m_slow_path_lock.unlock(); return; } // Update key to new ID new_key->set_user_id_key(new_calc_id); m_slow_path_lock.unlock(); socket_lock.unlock(); ring* new_ring = m_p_net_dev_val->reserve_ring(new_key); if (!new_ring) { socket_lock.lock(); return; } if (new_ring == m_p_ring) { if (!m_p_net_dev_val->release_ring(&old_key)) { dst_logerr("Failed to release ring for allocation key %s", old_key.to_str()); } socket_lock.lock(); return; } dst_logdbg("migrating from key=%s and ring=%p to key=%s and ring=%p", old_key.to_str(), m_p_ring, new_key->to_str(), new_ring); socket_lock.lock(); m_slow_path_lock.lock(); set_state(false); ring* old_ring = m_p_ring; m_p_ring = new_ring; if (m_sge) { delete[] m_sge; m_sge = NULL; } #ifdef DEFINED_TSO m_sge = new (nothrow) struct ibv_sge [m_p_ring->get_max_send_sge()]; #else m_sge = new (nothrow) struct ibv_sge [2]; #endif /* DEFINED_TSO */ if (!m_sge) { dst_logpanic("%s Failed to allocate send SGE", to_str().c_str()); } m_max_inline = m_p_ring->get_max_inline_data(); m_max_inline = std::min(m_max_inline, get_route_mtu() + (uint32_t)m_header.m_transport_header_len); mem_buf_desc_t* tmp_list = m_p_tx_mem_buf_desc_list; m_p_tx_mem_buf_desc_list = NULL; m_slow_path_lock.unlock(); socket_lock.unlock(); if (tmp_list) { old_ring->mem_buf_tx_release(tmp_list, true); } m_p_net_dev_val->release_ring(&old_key); socket_lock.lock(); } void dst_entry::set_bound_addr(in_addr_t addr) { dst_logdbg(""); m_bound_ip = addr; set_state(false); } void dst_entry::set_so_bindtodevice_addr(in_addr_t addr) { dst_logdbg(""); m_so_bindtodevice_ip = addr; set_state(false); } in_addr_t dst_entry::get_dst_addr() { return m_dst_ip.get_in_addr(); } uint16_t dst_entry::get_dst_port() { return m_dst_port; } ssize_t dst_entry::pass_buff_to_neigh(const iovec * p_iov, size_t sz_iov, uint16_t packet_id) { ssize_t ret_val = 0; dst_logdbg(""); configure_ip_header(&m_header_neigh, packet_id); if (m_p_neigh_entry) { neigh_send_info n_send_info(const_cast(p_iov), sz_iov, &m_header_neigh, get_protocol_type(), get_route_mtu(), m_tos); ret_val = m_p_neigh_entry->send(n_send_info); } return ret_val; } bool dst_entry::alloc_transport_dep_res() { return alloc_neigh_val(get_obs_transport_type()); } bool dst_entry::alloc_neigh_val(transport_type_t tranport) { bool ret_val = false; if (m_p_neigh_val) { delete m_p_neigh_val; m_p_neigh_val = NULL; } switch (tranport) { case VMA_TRANSPORT_IB: m_p_neigh_val = new neigh_ib_val; break; case VMA_TRANSPORT_ETH: default: m_p_neigh_val = new neigh_eth_val; break; } if (m_p_neigh_val) { ret_val = true; } return ret_val; } void dst_entry::return_buffers_pool() { if (m_p_tx_mem_buf_desc_list == NULL) { return; } if (m_b_tx_mem_buf_desc_list_pending && m_p_ring && m_p_ring->mem_buf_tx_release(m_p_tx_mem_buf_desc_list, true, true)) { m_p_tx_mem_buf_desc_list = NULL; set_tx_buff_list_pending(false); } else { set_tx_buff_list_pending(true); } } int dst_entry::modify_ratelimit(struct vma_rate_limit_t &rate_limit) { if (m_p_ring) { return m_p_ring->modify_ratelimit(rate_limit); } return 0; } int dst_entry::get_priority_by_tc_class(uint32_t pcp) { // translate class to priority if (m_p_net_dev_val) { return m_p_net_dev_val->get_priority_by_tc_class(pcp); } return VMA_DEFAULT_ENGRESS_MAP_PRIO; } bool dst_entry::update_ring_alloc_logic(int fd, lock_base& socket_lock, resource_allocation_key &ring_alloc_logic) { resource_allocation_key old_key(*m_ring_alloc_logic.get_key()); m_ring_alloc_logic = ring_allocation_logic_tx(fd, ring_alloc_logic, this); if (*m_ring_alloc_logic.get_key() != old_key) { auto_unlocker locker(m_tx_migration_lock); do_ring_migration(socket_lock, old_key); return true; } return false; }