1 // 2 // Copyright 2019 Ettus Research, a National Instruments brand 3 // 4 // SPDX-License-Identifier: GPL-3.0-or-later 5 // 6 7 #pragma once 8 9 #include <uhd/config.hpp> 10 #include <uhd/transport/buffer_pool.hpp> 11 #include <uhd/types/device_addr.hpp> 12 #include <uhdlib/transport/dpdk/common.hpp> 13 #include <uhdlib/transport/link_if.hpp> 14 #include <uhdlib/transport/links.hpp> 15 #include <rte_udp.h> 16 #include <cassert> 17 #include <string> 18 #include <vector> 19 20 namespace uhd { namespace transport { 21 22 /*! 23 * A zero copy transport interface to the dpdk DMA library. 24 */ 25 class udp_dpdk_link : public virtual recv_link_if, public virtual send_link_if 26 { 27 public: 28 using sptr = std::shared_ptr<udp_dpdk_link>; 29 30 udp_dpdk_link(const dpdk::port_id_t port_id, 31 const std::string& remote_addr, 32 const std::string& remote_port, 33 const std::string& local_port, 34 const link_params_t& params); 35 36 ~udp_dpdk_link(); 37 38 /*! 39 * Make a new dpdk link. Get port ID from routing table. 40 * 41 * \param remote_addr Remote IP address 42 * \param remote_port Remote UDP port 43 * \param params Values for frame sizes, num frames, and buffer sizes 44 * \return a shared_ptr to a new udp dpdk link 45 */ 46 static sptr make(const std::string& remote_addr, 47 const std::string& remote_port, 48 const link_params_t& params); 49 50 /*! 51 * Make a new dpdk link. User specifies DPDK port ID directly. 52 * 53 * \param port_id DPDK port ID to use for communication 54 * \param remote_addr Remote IP address 55 * \param remote_port Remote UDP port 56 * \param local_port Local UDP port 57 * \param params Values for frame sizes, num frames, and buffer sizes 58 * \return a shared_ptr to a new udp dpdk link 59 */ 60 static sptr make(const dpdk::port_id_t port_id, 61 const std::string& remote_addr, 62 const std::string& remote_port, 63 const std::string& local_port, 64 const link_params_t& params); 65 66 /*! 67 * Get the associated dpdk_port 68 * 69 * \return a pointer to the dpdk_port used by this link 70 */ get_port()71 inline dpdk::dpdk_port* get_port() 72 { 73 return _port; 74 } 75 76 /*! 77 * Get the DMA queue associated with this link 78 * 79 * \return the queue ID for this link's DMA queue 80 */ get_queue_id()81 inline dpdk::queue_id_t get_queue_id() 82 { 83 return _queue; 84 } 85 86 /*! 87 * Get the local UDP port used by this link 88 * 89 * \return the local UDP port, in network order 90 */ get_local_port()91 inline uint16_t get_local_port() 92 { 93 return _local_port; 94 } 95 96 /*! 97 * Get the remote UDP port used by this link 98 * 99 * \return the remote UDP port, in network order 100 */ get_remote_port()101 inline uint16_t get_remote_port() 102 { 103 return _remote_port; 104 } 105 106 /*! 107 * Get the remote IPv4 address used by this link 108 * 109 * \return the remote IPv4 address, in network order 110 */ get_remote_ipv4()111 inline uint32_t get_remote_ipv4() 112 { 113 return _remote_ipv4; 114 } 115 116 /*! 117 * Set the remote host's MAC address 118 * This MAC address must be filled in for the remote IPv4 address before 119 * the link can reach its destination. 120 * 121 * \param mac the remote host's MAC address 122 */ set_remote_mac(struct ether_addr & mac)123 inline void set_remote_mac(struct ether_addr& mac) 124 { 125 ether_addr_copy(&mac, &_remote_mac); 126 } 127 128 /*! 129 * Get the remote host's MAC address 130 * 131 * \param mac Where to write the MAC address 132 */ get_remote_mac(struct ether_addr & dst)133 inline void get_remote_mac(struct ether_addr& dst) 134 { 135 ether_addr_copy(&_remote_mac, &dst); 136 } 137 138 /*! 139 * Get the number of frame buffers that can be queued by this link. 140 */ get_num_send_frames() const141 size_t get_num_send_frames() const 142 { 143 return _num_send_frames; 144 } 145 146 /*! 147 * Get the maximum capacity of a frame buffer. 148 */ get_send_frame_size() const149 size_t get_send_frame_size() const 150 { 151 return _send_frame_size; 152 } 153 154 /*! 155 * Get the physical adapter ID used for this link 156 */ get_send_adapter_id() const157 inline adapter_id_t get_send_adapter_id() const 158 { 159 return _adapter_id; 160 } 161 162 /*! 163 * Get the number of frame buffers that can be queued by this link. 164 */ get_num_recv_frames() const165 size_t get_num_recv_frames() const 166 { 167 return _num_recv_frames; 168 } 169 170 /*! 171 * Get the maximum capacity of a frame buffer. 172 */ get_recv_frame_size() const173 size_t get_recv_frame_size() const 174 { 175 return _recv_frame_size; 176 } 177 178 /*! 179 * Get the physical adapter ID used for this link 180 */ get_recv_adapter_id() const181 inline adapter_id_t get_recv_adapter_id() const 182 { 183 return _adapter_id; 184 } 185 186 /*! 187 * Enqueue a received mbuf, which can be pulled via get_recv_buff() 188 */ 189 void enqueue_recv_mbuf(struct rte_mbuf* mbuf); 190 191 /*! 192 * Receive a packet and return a frame buffer containing the packet data. 193 * The timeout argument is ignored. 194 * 195 * Received buffers are pulled from the frame buffer list. No buffers can 196 * be retrieved unless the corresponding rte_mbufs were placed in the list 197 * via the enqueue_recv_mbuf() method. 198 * 199 * \return a frame buffer, or null uptr if timeout occurs 200 */ 201 frame_buff::uptr get_recv_buff(int32_t /*timeout_ms*/); 202 203 /*! 204 * Release a frame buffer, allowing the link driver to reuse it. 205 * 206 * \param buffer frame buffer to release for reuse by the link 207 */ 208 void release_recv_buff(frame_buff::uptr buff); 209 210 /*! 211 * Get an empty frame buffer in which to write packet contents. 212 * 213 * \param timeout_ms a positive timeout value specifies the maximum number 214 of ms to wait, a negative value specifies to block 215 until successful, and a value of 0 specifies no wait. 216 * \return a frame buffer, or null uptr if timeout occurs 217 */ 218 frame_buff::uptr get_send_buff(int32_t /*timeout_ms*/); 219 220 /*! 221 * Send a packet with the contents of the frame buffer and release the 222 * buffer, allowing the link driver to reuse it. If the size of the frame 223 * buffer is 0, the buffer is released with no packet being sent. 224 * 225 * Note that this function will only fill in the L2 header and send the 226 * mbuf. The L3 and L4 headers, in addition to the lengths in the rte_mbuf 227 * fields, must be set in the I/O service. 228 * 229 * \param buffer frame buffer containing packet data 230 * 231 * Throws an exception if an I/O error occurs while sending 232 */ 233 void release_send_buff(frame_buff::uptr buff); 234 235 private: 236 //! A reference to the DPDK context 237 dpdk::dpdk_ctx::sptr _ctx; 238 //! The DPDK NIC port used by this link 239 dpdk::dpdk_port* _port; 240 //! Local UDP port, in network order 241 uint16_t _local_port; 242 //! Remote UDP port, in network order 243 uint16_t _remote_port; 244 //! Remote IPv4 address, in network order 245 uint32_t _remote_ipv4; 246 //! Remote host's MAC address 247 struct ether_addr _remote_mac; 248 //! Number of recv frames is not validated 249 size_t _num_recv_frames; 250 //! Maximum bytes of UDP payload data in recv frame 251 size_t _recv_frame_size; 252 //! Number of send frames is not validated 253 size_t _num_send_frames; 254 //! Maximum bytes of UDP payload data in send frame 255 size_t _send_frame_size; 256 //! Registered adapter ID for this link's DPDK NIC port 257 adapter_id_t _adapter_id; 258 //! The RX frame buff list head 259 dpdk::dpdk_frame_buff* _recv_buff_head = nullptr; 260 // TODO: Implement ability to use multiple queues 261 dpdk::queue_id_t _queue = 0; 262 }; 263 264 }} // namespace uhd::transport 265