Ensō 0.4.6
Software API reference
Loading...
Searching...
No Matches
socket.cpp
Go to the documentation of this file.
1/*
2 * Copyright (c) 2022, Carnegie Mellon University
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted (subject to the limitations in the disclaimer
6 * below) provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * * Neither the name of the copyright holder nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY
20 * THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
21 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
22 * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
30 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
41#include "enso/socket.h"
42
43#include <enso/config.h>
44#include <enso/helpers.h>
45
46#include <cstring>
47#include <iostream>
48
49#include "../pcie.h"
50
51namespace enso {
52
53static struct NotificationBufPair notification_buf_pair[MAX_NB_CORES];
54
55// TODO(sadok) replace with hash table?
56static struct SocketInternal open_sockets[MAX_NB_SOCKETS];
57static unsigned int nb_open_sockets = 0;
58static uint16_t bdf = 0;
59
60// HACK(sadok): We need a better way to specify the BDF.
61void set_bdf(uint16_t bdf_) { bdf = bdf_; }
62
63int socket([[maybe_unused]] int domain, [[maybe_unused]] int type,
64 [[maybe_unused]] int protocol, bool fallback) noexcept {
65 if (unlikely(nb_open_sockets >= MAX_NB_SOCKETS)) {
66 std::cerr << "Maximum number of sockets reached" << std::endl;
67 return -1;
68 }
69
70 struct SocketInternal socket_entry;
71
72 struct NotificationBufPair* nb_pair = &notification_buf_pair[sched_getcpu()];
73 socket_entry.notification_buf_pair = nb_pair;
74
75 struct RxEnsoPipeInternal* enso_pipe = &socket_entry.enso_pipe;
76
77 int bar = -1;
78 int socket_id = dma_init(nb_pair, enso_pipe, bdf, bar,
79 std::string(kHugePageDefaultPrefix), fallback);
80 if (unlikely(socket_id < 0)) {
81 std::cerr << "Problem initializing DMA" << std::endl;
82 return -1;
83 }
84
85 open_sockets[socket_id] = socket_entry;
86
87 // FIXME(sadok): Use __sync_fetch_and_add to update atomically.
88 ++nb_open_sockets;
89
90 return socket_id;
91}
92
93int bind(int sockfd, const struct sockaddr* addr, socklen_t addrlen) noexcept {
94 (void)addrlen; // Avoid unused warnings.
95 struct SocketInternal* socket = &open_sockets[sockfd];
96 sockaddr_in* addr_in = (sockaddr_in*)addr;
97
98 uint32_t enso_pipe_id = get_enso_pipe_id_from_socket(socket);
99
100 // TODO(sadok): insert flow entry from kernel.
101 insert_flow_entry(socket->notification_buf_pair, ntohs(addr_in->sin_port), 0,
102 ntohl(addr_in->sin_addr.s_addr), 0,
103 0x11, // TODO(sadok): support protocols other than UDP.
104 enso_pipe_id);
105
106 return 0;
107}
108
109/*
110 * Return physical address of the buffer associated with the socket.
111 */
112uint64_t get_socket_phys_addr(int sockfd) {
113 return open_sockets[sockfd].enso_pipe.buf_phys_addr;
114}
115
116/*
117 * Return virtual address of the buffer associated with the socket.
118 */
119void* get_socket_virt_addr(int sockfd) {
120 return (void*)open_sockets[sockfd].enso_pipe.buf;
121}
122
123/*
124 * Convert a socket buffer virtual address to physical address.
125 */
126uint64_t convert_buf_addr_to_phys(int sockfd, void* addr) {
127 return (uint64_t)addr + open_sockets[sockfd].enso_pipe.phys_buf_offset;
128}
129
130ssize_t recv(int sockfd, void* buf, size_t len, int flags) {
131 (void)len;
132 (void)flags;
133
134 void* ring_buf;
135 struct SocketInternal* socket = &open_sockets[sockfd];
136 struct RxEnsoPipeInternal* enso_pipe = &socket->enso_pipe;
137 struct NotificationBufPair* notification_buf_pair =
138 socket->notification_buf_pair;
139
140 get_new_tails(notification_buf_pair);
141
142 ssize_t bytes_received =
143 get_next_batch_from_queue(enso_pipe, notification_buf_pair, &ring_buf);
144
145 if (unlikely(bytes_received <= 0)) {
146 return bytes_received;
147 }
148
149 memcpy(buf, ring_buf, bytes_received);
150
151 advance_pipe(enso_pipe, bytes_received);
152
153 return bytes_received;
154}
155
156ssize_t recv_zc(int sockfd, void** buf, size_t len, int flags) {
157 (void)len;
158 (void)flags;
159
160 struct SocketInternal* socket = &open_sockets[sockfd];
161 struct RxEnsoPipeInternal* enso_pipe = &socket->enso_pipe;
162 struct NotificationBufPair* notification_buf_pair =
163 socket->notification_buf_pair;
164
165 get_new_tails(notification_buf_pair);
166
167 return get_next_batch_from_queue(enso_pipe, notification_buf_pair, buf);
168}
169
170ssize_t recv_select(int ref_sockfd, int* sockfd, void** buf, size_t len,
171 int flags) {
172 (void)len;
173 (void)flags;
174
175 struct NotificationBufPair* notification_buf_pair =
176 open_sockets[ref_sockfd].notification_buf_pair;
177 return get_next_batch(notification_buf_pair, open_sockets, sockfd, buf);
178}
179
180ssize_t send(int sockfd, uint64_t phys_addr, size_t len, int flags) {
181 (void)flags;
182 return send_to_queue(open_sockets[sockfd].notification_buf_pair, phys_addr,
183 len);
184}
185
186uint32_t get_completions(int ref_sockfd) {
187 struct NotificationBufPair* notification_buf_pair =
188 open_sockets[ref_sockfd].notification_buf_pair;
189 return get_unreported_completions(notification_buf_pair);
190}
191
192void free_enso_pipe(int sockfd, size_t len) {
193 advance_pipe(&(open_sockets[sockfd].enso_pipe), len);
194}
195
196int enable_device_timestamp(int ref_sockfd, uint8_t offset) {
197 if (nb_open_sockets == 0) {
198 return -2;
199 }
200 return enable_timestamp(open_sockets[ref_sockfd].notification_buf_pair,
201 offset);
202}
203
204int disable_device_timestamp(int ref_sockfd) {
205 if (nb_open_sockets == 0) {
206 return -2;
207 }
208 return disable_timestamp(open_sockets[ref_sockfd].notification_buf_pair);
209}
210
211int enable_device_rate_limit(int ref_sockfd, uint16_t num, uint16_t den) {
212 if (nb_open_sockets == 0) {
213 return -2;
214 }
215 return enable_rate_limit(open_sockets[ref_sockfd].notification_buf_pair, num,
216 den);
217}
218
219int disable_device_rate_limit(int ref_sockfd) {
220 if (nb_open_sockets == 0) {
221 return -2;
222 }
223 return disable_rate_limit(open_sockets[ref_sockfd].notification_buf_pair);
224}
225
226int enable_device_round_robin(int ref_sockfd) {
227 if (nb_open_sockets == 0) {
228 return -2;
229 }
230 return enable_round_robin(open_sockets[ref_sockfd].notification_buf_pair);
231}
232
233int disable_device_round_robin(int ref_sockfd) {
234 if (nb_open_sockets == 0) {
235 return -2;
236 }
237 return disable_round_robin(open_sockets[ref_sockfd].notification_buf_pair);
238}
239
240int shutdown(int sockfd, int how __attribute__((unused))) noexcept {
241 dma_finish(&open_sockets[sockfd]);
242
243 // TODO(sadok): Remove entry from the NIC flow table.
244
245 --nb_open_sockets;
246
247 return 0;
248}
249
250void print_sock_stats(int sockfd) {
251 struct SocketInternal* socket = &open_sockets[sockfd];
252 print_stats(socket, socket->enso_pipe.id == 0);
253}
254
255} // namespace enso
Functions to configure the data plane.
int enable_timestamp(struct NotificationBufPair *notification_buf_pair, uint8_t offset=kDefaultRttOffset)
Enables hardware timestamping.
Definition: config.cpp:123
int enable_round_robin(struct NotificationBufPair *notification_buf_pair)
Enables packet round robin for the fallback pipes.
Definition: config.cpp:208
int disable_timestamp(struct NotificationBufPair *notification_buf_pair)
Disables hardware timestamping.
Definition: config.cpp:139
int enable_rate_limit(struct NotificationBufPair *notification_buf_pair, uint16_t num, uint16_t den)
Enables hardware rate limit.
Definition: config.cpp:149
int disable_rate_limit(struct NotificationBufPair *notification_buf_pair)
Disables hardware rate limit.
Definition: config.cpp:162
int insert_flow_entry(struct NotificationBufPair *notification_buf_pair, uint16_t dst_port, uint16_t src_port, uint32_t dst_ip, uint32_t src_ip, uint32_t protocol, uint32_t enso_pipe_id)
Inserts flow entry in the data plane flow table that will direct all packets matching the flow entry ...
Definition: config.cpp:97
int disable_round_robin(struct NotificationBufPair *notification_buf_pair)
Disables packet round robin for the fallback pipes. Using a hash of the packet's five tuple to select...
Definition: config.cpp:212
Miscellaneous helper functions.
uint16_t get_new_tails(struct NotificationBufPair *notification_buf_pair)
Gets latest tails for the pipes associated with the given notification buffer.
Definition: pcie.cpp:353
void print_stats(struct SocketInternal *socket_entry, bool print_global)
Prints statistics for a given socket.
Definition: pcie.cpp:711
uint32_t get_next_batch(struct NotificationBufPair *notification_buf_pair, struct SocketInternal *socket_entries, int *enso_pipe_id, void **buf)
Get next batch of data from the next available Enso Pipe.
Definition: pcie.cpp:429
uint32_t get_next_batch_from_queue(struct RxEnsoPipeInternal *enso_pipe, struct NotificationBufPair *notification_buf_pair, void **buf)
Gets the next batch of data from the given Enso Pipe.
Definition: pcie.cpp:385
uint32_t send_to_queue(struct NotificationBufPair *notification_buf_pair, uint64_t phys_addr, uint32_t len)
Sends data through a given queue.
Definition: pcie.cpp:515
uint32_t get_unreported_completions(struct NotificationBufPair *notification_buf_pair)
Returns the number of transmission requests that were completed since the last call to this function.
Definition: pcie.cpp:520
int dma_init(struct NotificationBufPair *notification_buf_pair, struct RxEnsoPipeInternal *enso_pipe, uint32_t bdf, int32_t bar, const std::string &huge_page_prefix, bool fallback)
Initializes an enso pipe and the notification buffer if needed.
Definition: pcie.cpp:285
void advance_pipe(struct RxEnsoPipeInternal *enso_pipe, size_t len)
Frees the next len bytes in the buffer associated with the socket_entry socket. If len is greater tha...
Definition: pcie.cpp:446
int dma_finish(struct SocketInternal *socket_entry)
Frees the notification buffer and all pipes.
Definition: pcie.cpp:684
uint32_t get_enso_pipe_id_from_socket(struct SocketInternal *socket_entry)
Gets the Enso Pipe ID associated with a given socket.
Definition: pcie.cpp:707
Socket-like API.