/* * 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. */ #ifndef RFS_H #define RFS_H #include #include "vma/ib/base/verbs_extra.h" #include "vma/util/vtypes.h" #include "vma/dev/ring_simple.h" #include "vma/proto/mem_buf_desc.h" #include "vma/proto/flow_tuple.h" #define rfs_logpanic __log_info_panic #define rfs_logerr __log_info_err #define rfs_logwarn __log_info_warn #define rfs_loginfo __log_info_info #define rfs_logdbg __log_info_dbg #define rfs_logfunc __log_info_func #define rfs_logfuncall __log_info_funcall #define RFS_SINKS_LIST_DEFAULT_LEN 32 class qp_mgr; class pkt_rcvr_sink; /* ETHERNET */ typedef struct attach_flow_data_eth_ipv4_tcp_udp_t { struct ibv_flow * ibv_flow; qp_mgr* p_qp_mgr; struct ibv_flow_attr_eth_ipv4_tcp_udp { vma_ibv_flow_attr attr; vma_ibv_flow_spec_eth eth; vma_ibv_flow_spec_ipv4 ipv4; vma_ibv_flow_spec_tcp_udp tcp_udp; vma_ibv_flow_spec_action_tag flow_tag; // must be the last as struct can be used without it ibv_flow_attr_eth_ipv4_tcp_udp(uint8_t port) { memset(this, 0, sizeof(*this)); attr.size = sizeof(struct ibv_flow_attr_eth_ipv4_tcp_udp) - sizeof(flow_tag); attr.num_of_specs = 3; attr.type = VMA_IBV_FLOW_ATTR_NORMAL; attr.priority = 1; // almost highest priority, 0 is used for 5-tuple later attr.port = port; } inline void add_flow_tag_spec(void) { attr.num_of_specs++; attr.size += sizeof(flow_tag); } } ibv_flow_attr; attach_flow_data_eth_ipv4_tcp_udp_t(qp_mgr* qp_mgr) : ibv_flow(NULL), p_qp_mgr(qp_mgr), ibv_flow_attr(qp_mgr->get_port_num()) {} } attach_flow_data_eth_ipv4_tcp_udp_t; /* IPOIB (MC) */ typedef struct attach_flow_data_ib_v2_t { struct ibv_flow * ibv_flow; qp_mgr* p_qp_mgr; struct ibv_flow_attr_ib_v2 { vma_ibv_flow_attr attr; vma_ibv_flow_spec_ipv4 ipv4; vma_ibv_flow_spec_tcp_udp tcp_udp; ibv_flow_attr_ib_v2(uint8_t port) { memset(this, 0, sizeof(*this)); attr.size = sizeof(struct ibv_flow_attr_ib_v2); attr.num_of_specs = 2; attr.type = VMA_IBV_FLOW_ATTR_NORMAL; attr.priority = 1; // almost highest priority, 0 is used for 5-tuple later attr.port = port; } } ibv_flow_attr; attach_flow_data_ib_v2_t(qp_mgr* qp_mgr) : ibv_flow(NULL), p_qp_mgr(qp_mgr), ibv_flow_attr(qp_mgr->get_port_num()) {} } attach_flow_data_ib_v2_t; #ifdef DEFINED_IBV_FLOW_SPEC_IB typedef struct attach_flow_data_ib_v1_t { struct ibv_flow * ibv_flow; qp_mgr* p_qp_mgr; struct ibv_flow_attr_ib_v1 { vma_ibv_flow_attr attr; vma_ibv_flow_spec_ib ib; ibv_flow_attr_ib_v1(uint8_t port) { memset(this, 0, sizeof(*this)); attr.size = sizeof(struct ibv_flow_attr_ib_v1); attr.num_of_specs = 1; attr.type = VMA_IBV_FLOW_ATTR_NORMAL; attr.priority = 1; // almost highest priority, 0 is used for 5-tuple later attr.port = port; } } ibv_flow_attr; attach_flow_data_ib_v1_t(qp_mgr* qp_mgr) : ibv_flow(NULL), p_qp_mgr(qp_mgr), ibv_flow_attr(qp_mgr->get_port_num()) {} } attach_flow_data_ib_v1_t; #endif /* IPOIB (UC) */ typedef struct attach_flow_data_ib_ipv4_tcp_udp_v2_t { struct ibv_flow * ibv_flow; qp_mgr* p_qp_mgr; struct ibv_flow_attr_ib_ipv4_tcp_udp_v2 { vma_ibv_flow_attr attr; vma_ibv_flow_spec_ipv4 ipv4; vma_ibv_flow_spec_tcp_udp tcp_udp; ibv_flow_attr_ib_ipv4_tcp_udp_v2(uint8_t port) { memset(this, 0, sizeof(*this)); attr.size = sizeof(struct ibv_flow_attr_ib_ipv4_tcp_udp_v2); attr.num_of_specs = 2; attr.type = VMA_IBV_FLOW_ATTR_NORMAL; attr.priority = 1; // almost highest priority, 0 is used for 5-tuple later attr.port = port; } } ibv_flow_attr; attach_flow_data_ib_ipv4_tcp_udp_v2_t(qp_mgr* qp_mgr) : ibv_flow(NULL), p_qp_mgr(qp_mgr), ibv_flow_attr(qp_mgr->get_port_num()) {} } attach_flow_data_ib_ipv4_tcp_udp_v2_t; #ifdef DEFINED_IBV_FLOW_SPEC_IB typedef struct attach_flow_data_ib_ipv4_tcp_udp_v1_t { struct ibv_flow * ibv_flow; qp_mgr* p_qp_mgr; struct ibv_flow_attr_ib_ipv4_tcp_udp_v1 { vma_ibv_flow_attr attr; vma_ibv_flow_spec_ib ib; vma_ibv_flow_spec_ipv4 ipv4; vma_ibv_flow_spec_tcp_udp tcp_udp; ibv_flow_attr_ib_ipv4_tcp_udp_v1(uint8_t port) { memset(this, 0, sizeof(*this)); attr.size = sizeof(struct ibv_flow_attr_ib_ipv4_tcp_udp_v1); attr.num_of_specs = 3; attr.type = VMA_IBV_FLOW_ATTR_NORMAL; attr.priority = 1; // almost highest priority, 0 is used for 5-tuple later attr.port = port; } } ibv_flow_attr; attach_flow_data_ib_ipv4_tcp_udp_v1_t(qp_mgr* qp_mgr) : ibv_flow(NULL), p_qp_mgr(qp_mgr), ibv_flow_attr(qp_mgr->get_port_num()) {} } attach_flow_data_ib_ipv4_tcp_udp_v1_t; #endif /* DEFINED_IBV_FLOW_SPEC_IB */ typedef struct attach_flow_data_t { vma_ibv_flow * ibv_flow; qp_mgr* p_qp_mgr; vma_ibv_flow_attr ibv_flow_attr; } attach_flow_data_t; typedef std::vector attach_flow_data_vector_t; class rfs_rule_filter { public: rfs_rule_filter(rule_filter_map_t& map, uint64_t key, flow_tuple& flow_tuple) : m_map(map), m_key(key), m_flow_tuple(flow_tuple) {} rule_filter_map_t& m_map; uint64_t m_key; flow_tuple m_flow_tuple; }; /** * @class rfs * * Object to manages the sink list * This object is used for maintaining the sink list and dispatching packets * */ class rfs { public: rfs(flow_tuple *flow_spec_5t, ring_slave *p_ring, rfs_rule_filter* rule_filter = NULL, uint32_t flow_tag_id = 0); virtual ~rfs(); /** * Register/Unregister a sink with this rfs object * Get notifications about incoming packets using the pkt_rcvr_sink callback api * The rfs will call ibv_attach on the QP once when at least one receiver sink is registered * An ibv_detach is called when the last receiver sink is deleted from the registered list * */ bool attach_flow(pkt_rcvr_sink *sink); // Add a sink. If this is the first sink --> map the sink and attach flow to QP bool detach_flow(pkt_rcvr_sink *sink); // Delete a sink. If this is the last sink --> delete it and detach flow from QP uint32_t get_num_of_sinks() const { return m_n_sinks_list_entries; } virtual bool rx_dispatch_packet(mem_buf_desc_t* p_rx_wc_buf_desc, void* pv_fd_ready_array) = 0; protected: flow_tuple m_flow_tuple; ring_slave* m_p_ring; rfs_rule_filter* m_p_rule_filter; attach_flow_data_vector_t m_attach_flow_data_vector; pkt_rcvr_sink** m_sinks_list; uint32_t m_n_sinks_list_entries; // Number of actual sinks in the array (we shrink the array if a sink is removed) uint32_t m_n_sinks_list_max_length; uint32_t m_flow_tag_id; // Associated with this rule, set by attach_flow() bool m_b_tmp_is_attached; // Only temporary, while ibcm calls attach_flow with no sinks... bool create_ibv_flow(); // Attach flow to all qps bool destroy_ibv_flow(); // Detach flow from all qps bool add_sink(pkt_rcvr_sink* p_sink); bool del_sink(pkt_rcvr_sink* p_sink); virtual bool prepare_flow_spec() = 0; private: rfs(); // I don't want anyone to use the default constructor inline void prepare_filter_attach(int& filter_counter, rule_filter_map_t::iterator& filter_iter); inline void filter_keep_attached(rule_filter_map_t::iterator& filter_iter); inline void prepare_filter_detach(int& filter_counter, bool decrease_counter); }; #endif /* RFS_H */