-
Notifications
You must be signed in to change notification settings - Fork 4
/
ccp.h
246 lines (210 loc) · 7.12 KB
/
ccp.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
#ifndef CCP_H
#define CCP_H
#ifdef __KERNEL__
#include <linux/types.h>
#include <linux/module.h>
#else
#include <stdbool.h>
#include <pthread.h> // for mutex
#endif
#include "types.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Datapaths must support these measurement primitives.
* Each value is reported *per invocation*.
*
* n.b. Ideally, an invocation is every packet, but datapaths might choose to call
* ccp_invoke() less often.
*/
struct ccp_primitives {
// newly acked, in-order bytes
u32 bytes_acked;
// newly acked, in-order packets
u32 packets_acked;
// out-of-order bytes
u32 bytes_misordered;
// out-of-order packets
u32 packets_misordered;
// bytes corresponding to ecn-marked packets
u32 ecn_bytes;
// ecn-marked packets
u32 ecn_packets;
// an estimate of the number of packets lost
u32 lost_pkts_sample;
// whether a timeout was observed
bool was_timeout;
// a recent sample of the round-trip time
u64 rtt_sample_us;
// sample of the sending rate, bytes / s
u64 rate_outgoing;
// sample of the receiving rate, bytes / s
u64 rate_incoming;
// the number of actual bytes in flight
u32 bytes_in_flight;
// the number of actual packets in flight
u32 packets_in_flight;
// the target congestion window to maintain, in bytes
u32 snd_cwnd;
// target rate to maintain, in bytes/s
u64 snd_rate;
// amount of data available to be sent
// NOT per-packet - an absolute measurement
u32 bytes_pending;
};
// maximum string length for congAlg
#define MAX_CONG_ALG_SIZE 64
/* Datapaths provide connection information to ccp_connection_start
*/
struct ccp_datapath_info {
u32 init_cwnd;
u32 mss;
u32 src_ip;
u32 src_port;
u32 dst_ip;
u32 dst_port;
char congAlg[MAX_CONG_ALG_SIZE];
};
/*
* CCP state per connection.
* impl is datapath-specific, the rest are internal to libccp
* for example, the linux kernel datapath uses impl to store a pointer to struct sock
*/
struct ccp_connection {
// the index of this array element
u16 index;
u64 last_create_msg_sent;
// struct ccp_primitives is large; as a result, we store it inside ccp_connection to avoid
// potential limitations in the datapath
// datapath should update this before calling ccp_invoke()
struct ccp_primitives prims;
// constant flow-level information
struct ccp_datapath_info flow_info;
// private libccp state for the send machine and measurement machine
void *state;
// datapath-specific per-connection state
void *impl;
// pointer back to parent datapath that owns this connection
struct ccp_datapath *datapath;
};
enum ccp_log_level {
TRACE,
DEBUG,
INFO,
WARN,
ERROR,
};
/*
* Global CCP state provided by the datapath
*
* Callbacks:
* 1. set_cwnd(): set the congestion window
* 2. set_rate_abs(): set the rate
*
* Time functions
* 3. now(): return a notion of time.
* 4. since_usecs(u32 then): elapsed microseconds since <then>.
* 5. after_usecs(u32 usecs): return a time <usecs> microseconds in the future.
*
* Utility functions
* 6. send_msg(): send a message from datapath -> userspace CCP.
* 7. log(): (optional)
*/
struct ccp_datapath {
// control primitives
void (*set_cwnd)(struct ccp_connection *conn, u32 cwnd);
void (*set_rate_abs)(struct ccp_connection *conn, u32 rate);
// IPC communication
int (*send_msg)(struct ccp_datapath *dp, char *msg, int msg_size);
// logging
void (*log)(struct ccp_datapath *dp, enum ccp_log_level level, const char* msg, int msg_size);
// time management
u64 time_zero;
u64 (*now)(void); // the current time in datapath time units
u64 (*since_usecs)(u64 then); // elapsed microseconds since <then>
u64 (*after_usecs)(u64 usecs); // <usecs> microseconds from now in datapath time units
size_t max_connections;
// list of active connections this datapath is handling
struct ccp_connection* ccp_active_connections;
u64 fto_us;
u64 last_msg_sent;
bool _in_fallback;
size_t max_programs;
// list of datapath programs
void *programs;
// datapath-specific global state
void *impl;
};
/* Initialize CCP.
*
* This function should be called before any other libccp functions and ensures (as much as possible)
* that the datapath structure has been initialized correctly.
*
* A valid ccp_datapath must contain:
* 1. 6 callback functions: set_cwnd, set_rate_abs, send_msg, now, since_users, after_usecs
* 2. an optional callback function for logging
* 3. a pointer to memory allocated for a list of ccp_connection objects
* (as well as the number of connections it can hold)
* 4. a fallback timeout value in microseconds (must be > 0)
*
* The id argument uniquely identifies this datapath.
*
* IMPORTANT: caller must allocate..
* 1. ccp_datapath
* 2. ccp_datapath.ccp_active_connections with enough space for `max_connections` `ccp_connections`
* ccp_init has no way of checking if enough space has been allocated, so any memory oob errors are
* likely a result not allocating enough space.
*
* If the userspace CCP process isn't listening, this function will have the same failure behavior and return value as send_msg.
* In this case, initialization is considered to not be complete, and the caller is expected to try again.
*
* This function returns 0 if the structure has been initialized correctly and a negative value
* with an error code otherwise.
*/
int ccp_init(struct ccp_datapath *dp, u32 id);
/* Free the global struct and map for ccp connections upon module unload.
*/
void ccp_free(struct ccp_datapath *datapath);
/* Upon a new flow starting,
* put a new connection into the active connections list
*
* returns the index at which the connection was placed; this index shall be used as the CCP socket id
* return 0 on error
*/
struct ccp_connection *ccp_connection_start(struct ccp_datapath *datapath, void *impl, struct ccp_datapath_info *flow_info);
/* Upon a connection ending,
* free its slot in the connection map.
*/
void ccp_connection_free(struct ccp_datapath *datapath, u16 sid);
/* While a flow is active, look up its CCP connection information.
*/
struct ccp_connection *ccp_connection_lookup(struct ccp_datapath *datapath, u16 sid);
/* Get the implementation-specific state of the ccp_connection.
*/
void *ccp_get_impl(struct ccp_connection *conn);
void ccp_set_impl(
struct ccp_connection *conn,
void *ptr
);
/* Callback to pass to IPC for incoming messages.
* Cannot take ccp_connection as an argument, since it's a callback.
* Therefore, must look up ccp_connction from socket_id.
* buf: the received message, of size bufsize.
*/
int ccp_read_msg(
struct ccp_datapath *datapath,
char *buf,
int bufsize
);
/* Should be called along with the ACK clock.
*
* Will invoke the send and measurement machines.
*/
int ccp_invoke(struct ccp_connection *conn);
void _update_fto_timer(struct ccp_datapath *datapath);
bool _check_fto(struct ccp_datapath *datapath);
void _turn_off_fto_timer(struct ccp_datapath *datapath);
#ifdef __cplusplus
} // extern "C"
#endif
#endif