1 /*
2  * include/haproxy/spoe-t.h
3  * Macros, variables and structures for the SPOE filter.
4  *
5  * Copyright (C) 2017 HAProxy Technologies, Christopher Faulet <cfaulet@haproxy.com>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation, version 2.1
10  * exclusively.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21 
22 #ifndef _HAPROXY_SPOE_T_H
23 #define _HAPROXY_SPOE_T_H
24 
25 #include <sys/time.h>
26 
27 #include <haproxy/buf-t.h>
28 #include <haproxy/dynbuf-t.h>
29 #include <haproxy/filters-t.h>
30 #include <haproxy/freq_ctr-t.h>
31 #include <haproxy/proxy-t.h>
32 #include <haproxy/sample-t.h>
33 #include <haproxy/stream-t.h>
34 #include <haproxy/task-t.h>
35 #include <haproxy/thread-t.h>
36 
37 /* Type of list of messages */
38 #define SPOE_MSGS_BY_EVENT 0x01
39 #define SPOE_MSGS_BY_GROUP 0x02
40 
41 /* Flags set on the SPOE agent */
42 #define SPOE_FL_CONT_ON_ERR       0x00000001 /* Do not stop events processing when an error occurred */
43 #define SPOE_FL_PIPELINING        0x00000002 /* Set when SPOE agent supports pipelining (set by default) */
44 #define SPOE_FL_ASYNC             0x00000004 /* Set when SPOE agent supports async (set by default) */
45 #define SPOE_FL_SND_FRAGMENTATION 0x00000008 /* Set when SPOE agent supports sending fragmented payload */
46 #define SPOE_FL_RCV_FRAGMENTATION 0x00000010 /* Set when SPOE agent supports receiving fragmented payload */
47 #define SPOE_FL_FORCE_SET_VAR     0x00000020 /* Set when SPOE agent will set all variables from agent (and not only known variables) */
48 
49 /* Flags set on the SPOE context */
50 #define SPOE_CTX_FL_CLI_CONNECTED 0x00000001 /* Set after that on-client-session event was processed */
51 #define SPOE_CTX_FL_SRV_CONNECTED 0x00000002 /* Set after that on-server-session event was processed */
52 #define SPOE_CTX_FL_REQ_PROCESS   0x00000004 /* Set when SPOE is processing the request */
53 #define SPOE_CTX_FL_RSP_PROCESS   0x00000008 /* Set when SPOE is processing the response */
54 #define SPOE_CTX_FL_FRAGMENTED    0x00000010 /* Set when a fragmented frame is processing */
55 
56 #define SPOE_CTX_FL_PROCESS (SPOE_CTX_FL_REQ_PROCESS|SPOE_CTX_FL_RSP_PROCESS)
57 
58 /* Flags set on the SPOE applet */
59 #define SPOE_APPCTX_FL_PIPELINING    0x00000001 /* Set if pipelining is supported */
60 #define SPOE_APPCTX_FL_ASYNC         0x00000002 /* Set if asynchronus frames is supported */
61 #define SPOE_APPCTX_FL_FRAGMENTATION 0x00000004 /* Set if fragmentation is supported */
62 
63 #define SPOE_APPCTX_ERR_NONE    0x00000000 /* no error yet, leave it to zero */
64 #define SPOE_APPCTX_ERR_TOUT    0x00000001 /* SPOE applet timeout */
65 
66 /* Flags set on the SPOE frame */
67 #define SPOE_FRM_FL_FIN         0x00000001
68 #define SPOE_FRM_FL_ABRT        0x00000002
69 
70 /* Masks to get data type or flags value */
71 #define SPOE_DATA_T_MASK  0x0F
72 #define SPOE_DATA_FL_MASK 0xF0
73 
74 /* Flags to set Boolean values */
75 #define SPOE_DATA_FL_FALSE 0x00
76 #define SPOE_DATA_FL_TRUE  0x10
77 
78 /* All possible states for a SPOE context */
79 enum spoe_ctx_state {
80 	SPOE_CTX_ST_NONE = 0,
81 	SPOE_CTX_ST_READY,
82 	SPOE_CTX_ST_ENCODING_MSGS,
83 	SPOE_CTX_ST_SENDING_MSGS,
84 	SPOE_CTX_ST_WAITING_ACK,
85 	SPOE_CTX_ST_DONE,
86 	SPOE_CTX_ST_ERROR,
87 };
88 
89 /* All possible states for a SPOE applet */
90 enum spoe_appctx_state {
91 	SPOE_APPCTX_ST_CONNECT = 0,
92 	SPOE_APPCTX_ST_CONNECTING,
93 	SPOE_APPCTX_ST_IDLE,
94 	SPOE_APPCTX_ST_PROCESSING,
95 	SPOE_APPCTX_ST_SENDING_FRAG_NOTIFY,
96 	SPOE_APPCTX_ST_WAITING_SYNC_ACK,
97 	SPOE_APPCTX_ST_DISCONNECT,
98 	SPOE_APPCTX_ST_DISCONNECTING,
99 	SPOE_APPCTX_ST_EXIT,
100 	SPOE_APPCTX_ST_END,
101 };
102 
103 /* All supported SPOE actions */
104 enum spoe_action_type {
105 	SPOE_ACT_T_SET_VAR = 1,
106 	SPOE_ACT_T_UNSET_VAR,
107 	SPOE_ACT_TYPES,
108 };
109 
110 /* All supported SPOE events */
111 enum spoe_event {
112 	SPOE_EV_NONE = 0,
113 
114 	/* Request events */
115 	SPOE_EV_ON_CLIENT_SESS = 1,
116 	SPOE_EV_ON_TCP_REQ_FE,
117 	SPOE_EV_ON_TCP_REQ_BE,
118 	SPOE_EV_ON_HTTP_REQ_FE,
119 	SPOE_EV_ON_HTTP_REQ_BE,
120 
121 	/* Response events */
122 	SPOE_EV_ON_SERVER_SESS,
123 	SPOE_EV_ON_TCP_RSP,
124 	SPOE_EV_ON_HTTP_RSP,
125 
126 	SPOE_EV_EVENTS
127 };
128 
129 /* Errors triggered by streams */
130 enum spoe_context_error {
131 	SPOE_CTX_ERR_NONE = 0,
132 	SPOE_CTX_ERR_TOUT,
133 	SPOE_CTX_ERR_RES,
134 	SPOE_CTX_ERR_TOO_BIG,
135 	SPOE_CTX_ERR_FRAG_FRAME_ABRT,
136 	SPOE_CTX_ERR_INTERRUPT,
137 	SPOE_CTX_ERR_UNKNOWN = 255,
138 	SPOE_CTX_ERRS,
139 };
140 
141 /* Errors triggered by SPOE applet */
142 enum spoe_frame_error {
143 	SPOE_FRM_ERR_NONE = 0,
144 	SPOE_FRM_ERR_IO,
145 	SPOE_FRM_ERR_TOUT,
146 	SPOE_FRM_ERR_TOO_BIG,
147 	SPOE_FRM_ERR_INVALID,
148 	SPOE_FRM_ERR_NO_VSN,
149 	SPOE_FRM_ERR_NO_FRAME_SIZE,
150 	SPOE_FRM_ERR_NO_CAP,
151 	SPOE_FRM_ERR_BAD_VSN,
152 	SPOE_FRM_ERR_BAD_FRAME_SIZE,
153 	SPOE_FRM_ERR_FRAG_NOT_SUPPORTED,
154 	SPOE_FRM_ERR_INTERLACED_FRAMES,
155 	SPOE_FRM_ERR_FRAMEID_NOTFOUND,
156 	SPOE_FRM_ERR_RES,
157 	SPOE_FRM_ERR_UNKNOWN = 99,
158 	SPOE_FRM_ERRS,
159 };
160 
161 /* Scopes used for variables set by agents. It is a way to be agnotic to vars
162  * scope. */
163 enum spoe_vars_scope {
164 	SPOE_SCOPE_PROC = 0, /* <=> SCOPE_PROC  */
165 	SPOE_SCOPE_SESS,     /* <=> SCOPE_SESS */
166 	SPOE_SCOPE_TXN,      /* <=> SCOPE_TXN  */
167 	SPOE_SCOPE_REQ,      /* <=> SCOPE_REQ  */
168 	SPOE_SCOPE_RES,      /* <=> SCOPE_RES  */
169 };
170 
171 /* Frame Types sent by HAProxy and by agents */
172 enum spoe_frame_type {
173 	SPOE_FRM_T_UNSET = 0,
174 
175 	/* Frames sent by HAProxy */
176 	SPOE_FRM_T_HAPROXY_HELLO = 1,
177 	SPOE_FRM_T_HAPROXY_DISCON,
178 	SPOE_FRM_T_HAPROXY_NOTIFY,
179 
180 	/* Frames sent by the agents */
181 	SPOE_FRM_T_AGENT_HELLO = 101,
182 	SPOE_FRM_T_AGENT_DISCON,
183 	SPOE_FRM_T_AGENT_ACK
184 };
185 
186 /* All supported data types */
187 enum spoe_data_type {
188 	SPOE_DATA_T_NULL = 0,
189 	SPOE_DATA_T_BOOL,
190 	SPOE_DATA_T_INT32,
191 	SPOE_DATA_T_UINT32,
192 	SPOE_DATA_T_INT64,
193 	SPOE_DATA_T_UINT64,
194 	SPOE_DATA_T_IPV4,
195 	SPOE_DATA_T_IPV6,
196 	SPOE_DATA_T_STR,
197 	SPOE_DATA_T_BIN,
198 	SPOE_DATA_TYPES
199 };
200 
201 
202 /* Describe an argument that will be linked to a message. It is a sample fetch,
203  * with an optional name. */
204 struct spoe_arg {
205 	char               *name;     /* Name of the argument, may be NULL */
206 	unsigned int        name_len; /* The name length, 0 if NULL */
207 	struct sample_expr *expr;     /* Sample expression */
208 	struct list         list;     /* Used to chain SPOE args */
209 };
210 
211 /* Used during the config parsing only because, when a SPOE agent section is
212  * parsed, messages/groups can be undefined. */
213 struct spoe_placeholder {
214 	char       *id;    /* SPOE placeholder id */
215 	struct list list;  /* Use to chain SPOE placeholders */
216 };
217 
218 /* Used during the config parsing, when SPOE agent section is parsed, to
219  * register some variable names. */
220 struct spoe_var_placeholder {
221 	char        *name;  /* The variable name */
222 	struct list  list;  /* Use to chain SPOE var placeholders */
223 };
224 
225 /* Describe a message that will be sent in a NOTIFY frame. A message has a name,
226  * an argument list (see above) and it is linked to a specific event. */
227 struct spoe_message {
228 	char               *id;     /* SPOE message id */
229 	unsigned int        id_len; /* The message id length */
230 	struct spoe_agent  *agent;  /* SPOE agent owning this SPOE message */
231 	struct spoe_group  *group;  /* SPOE group owning this SPOE message (can be NULL) */
232         struct {
233                 char       *file;   /* file where the SPOE message appears */
234                 int         line;   /* line where the SPOE message appears */
235         } conf;                     /* config information */
236 	unsigned int        nargs;  /* # of arguments */
237 	struct list         args;   /* Arguments added when the SPOE messages is sent */
238 	struct list         list;   /* Used to chain SPOE messages */
239 	struct list         by_evt; /* By event list */
240 	struct list         by_grp; /* By group list */
241 
242 	struct list         acls;   /* ACL declared on this message */
243 	struct acl_cond    *cond;   /* acl condition to meet */
244 	enum spoe_event     event;  /* SPOE_EV_* */
245 };
246 
247 /* Describe a group of messages that will be sent in a NOTIFY frame. A group has
248  * a name and a list of messages. It can be used by HAProxy, outside events
249  * processing, mainly in (tcp|http) rules. */
250 struct spoe_group {
251 	char              *id;      /* SPOE group id */
252 	struct spoe_agent *agent;   /* SPOE agent owning this SPOE group */
253         struct {
254                 char      *file;    /* file where the SPOE group appears */
255                 int        line;    /* line where the SPOE group appears */
256         } conf;                     /* config information */
257 
258 	struct list phs;      /* List of placeholders used during conf parsing */
259 	struct list messages; /* List of SPOE messages that will be sent by this
260 			       * group */
261 
262 	struct list list;     /* Used to chain SPOE groups */
263 };
264 
265 /* Describe a SPOE agent. */
266 struct spoe_agent {
267 	char                 *id;             /* SPOE agent id (name) */
268         struct {
269                 char         *file;           /* file where the SPOE agent appears */
270                 int           line;           /* line where the SPOE agent appears */
271         } conf;                               /* config information */
272 	union {
273 		struct proxy *be;             /* Backend used by this agent */
274 		char         *name;           /* Backend name used during conf parsing */
275 	} b;
276 	struct {
277 		unsigned int  hello;          /* Max time to receive AGENT-HELLO frame (in SPOE applet) */
278 		unsigned int  idle;           /* Max Idle timeout  (in SPOE applet) */
279 		unsigned int  processing;     /* Max time to process an event (in the main stream) */
280 	} timeout;
281 
282 	/* Config info */
283 	struct spoe_config  *spoe_conf;       /* SPOE filter config */
284 	char                 *var_pfx;        /* Prefix used for vars set by the agent */
285 	char                 *var_on_error;   /* Variable to set when an error occurred, in the TXN scope */
286 	char                 *var_t_process;  /* Variable to set to report the processing time of the last event/group, in the TXN scope */
287 	char                 *var_t_total;    /* Variable to set to report the cumulative processing time, in the TXN scope */
288 	unsigned int          flags;          /* SPOE_FL_* */
289 	unsigned int          cps_max;        /* Maximum # of connections per second */
290 	unsigned int          eps_max;        /* Maximum # of errors per second */
291 	unsigned int          max_frame_size; /* Maximum frame size for this agent, before any negotiation */
292 	unsigned int          max_fpa;        /* Maximum # of frames handled per applet at once */
293 
294 	struct list events[SPOE_EV_EVENTS];   /* List of SPOE messages that will be sent
295 					       * for each supported events */
296 
297 	struct list groups;                   /* List of available SPOE groups */
298 
299 	struct list messages;                 /* list of all messages attached to this SPOE agent */
300 
301 	/* running info */
302 	struct {
303 		char           *engine_id;      /* engine-id string */
304 		unsigned int    frame_size;     /* current maximum frame size, only used to encode messages */
305 		unsigned int    processing;
306 		struct freq_ctr processing_per_sec;
307 
308 		struct freq_ctr conn_per_sec;   /* connections per second */
309 		struct freq_ctr err_per_sec;    /* connection errors per second */
310 
311 		struct eb_root  idle_applets;   /* idle SPOE applets available to process data */
312 		struct list     applets;        /* all SPOE applets for this agent */
313 		struct list     sending_queue;  /* Queue of streams waiting to send data */
314 		struct list     waiting_queue;  /* Queue of streams waiting for a ack, in async mode */
315 		__decl_thread(HA_SPINLOCK_T lock);
316 	} *rt;
317 
318 	struct {
319 		unsigned int applets;            /* # of SPOE applets */
320 		unsigned int idles;              /* # of idle applets */
321 		unsigned int nb_sending;         /* # of streams waiting to send data */
322 		unsigned int nb_waiting;         /* # of streams waiting for a ack */
323 		unsigned long long nb_processed; /* # of frames processed by the SPOE */
324 		unsigned long long nb_errors;    /* # of errors during the processing */
325 	} counters;
326 };
327 
328 /* SPOE filter configuration */
329 struct spoe_config {
330 	char              *id;          /* The SPOE engine name. If undefined in HAProxy config,
331 					 * it will be set with the SPOE agent name */
332 	struct proxy      *proxy;       /* Proxy owning the filter */
333 	struct spoe_agent *agent;       /* Agent used by this filter */
334 	struct proxy       agent_fe;    /* Agent frontend */
335 };
336 
337 /* SPOE context attached to a stream. It is the main structure that handles the
338  * processing offload */
339 struct spoe_context {
340 	struct filter      *filter;       /* The SPOE filter */
341 	struct stream      *strm;         /* The stream that should be offloaded */
342 
343 	struct list        *events;       /* List of messages that will be sent during the stream processing */
344 	struct list        *groups;       /* List of available SPOE group */
345 
346 	struct buffer       buffer;       /* Buffer used to store a encoded messages */
347 	struct buffer_wait  buffer_wait;  /* position in the list of resources waiting for a buffer */
348 	struct list         list;
349 
350 	enum spoe_ctx_state state;        /* SPOE_CTX_ST_* */
351 	unsigned int        flags;        /* SPOE_CTX_FL_* */
352 	unsigned int        status_code;  /* SPOE_CTX_ERR_* */
353 
354 	unsigned int        stream_id;    /* stream_id and frame_id are used */
355 	unsigned int        frame_id;     /* to map NOTIFY and ACK frames */
356 	unsigned int        process_exp;  /* expiration date to process an event */
357 
358 	struct spoe_appctx *spoe_appctx; /* SPOE appctx sending the current frame */
359 	struct {
360 		struct spoe_message *curmsg;      /* SPOE message from which to resume encoding */
361 		struct spoe_arg     *curarg;      /* SPOE arg in <curmsg> from which to resume encoding */
362 		unsigned int         curoff;      /* offset in <curarg> from which to resume encoding */
363 		unsigned int         curlen;      /* length of <curarg> need to be encode, for SMP_F_MAY_CHANGE data */
364 		unsigned int         flags;       /* SPOE_FRM_FL_* */
365 	} frag_ctx; /* Info about fragmented frames, valid on if SPOE_CTX_FL_FRAGMENTED is set */
366 
367 	struct {
368 		struct timeval tv_start;    /* start date of the current event/group */
369 		struct timeval tv_request;  /* date the frame processing starts (reset for each frag) */
370 		struct timeval tv_queue;    /* date the frame is queued (reset for each frag) */
371 		struct timeval tv_wait;     /* date the stream starts waiting for a response */
372 		struct timeval tv_response; /* date the response processing starts */
373 		long           t_request;   /* delay to encode and push the frame in queue (cumulative for frags) */
374 		long           t_queue;     /* delay before the frame gets out the sending queue (cumulative for frags) */
375 		long           t_waiting;   /* delay before the response is reveived */
376 		long           t_response;  /* delay to process the response (from the stream pov) */
377 		long           t_process;   /* processing time of the last event/group */
378 		unsigned long  t_total;     /* cumulative processing time */
379 	} stats; /* Stats for this stream */
380 };
381 
382 /* SPOE context inside a appctx */
383 struct spoe_appctx {
384 	struct appctx      *owner;          /* the owner */
385 	struct task        *task;           /* task to handle applet timeouts */
386 	struct spoe_agent  *agent;          /* agent on which the applet is attached */
387 
388 	unsigned int        version;        /* the negotiated version */
389 	unsigned int        max_frame_size; /* the negotiated max-frame-size value */
390 	unsigned int        flags;          /* SPOE_APPCTX_FL_* */
391 
392 	unsigned int        status_code;    /* SPOE_FRM_ERR_* */
393 #if defined(DEBUG_SPOE) || defined(DEBUG_FULL)
394 	char               *reason;         /* Error message, used for debugging only */
395 	int                 rlen;           /* reason length */
396 #endif
397 
398 	struct buffer       buffer;         /* Buffer used to store a encoded messages */
399 	struct buffer_wait  buffer_wait;    /* position in the list of resources waiting for a buffer */
400 	struct list         waiting_queue;  /* list of streams waiting for a ACK frame, in sync and pipelining mode */
401 	struct list         list;           /* next spoe appctx for the same agent */
402 	struct eb32_node    node;           /* node used for applets tree */
403 	unsigned int        cur_fpa;
404 
405 	struct {
406 		struct spoe_context *ctx;    /* SPOE context owning the fragmented frame */
407 		unsigned int         cursid; /* stream-id of the fragmented frame. used if the processing is aborted */
408 		unsigned int         curfid; /* frame-id of the fragmented frame. used if the processing is aborted */
409 	} frag_ctx; /* Info about fragmented frames, unused for unfragmented frames */
410 };
411 
412 #endif /* _HAPROXY_SPOE_T_H */
413