blob: cde3b1dffe1b52cf33ab7b26acf0f7f6a7b5d423 [file] [log] [blame]
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02001 -----------------------------------------------
2 Stream Processing Offload Engine (SPOE)
Christopher Faulet57583e42017-09-04 15:41:09 +02003 Version 1.2
4 ( Last update: 2017-09-22 )
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02005 -----------------------------------------------
6 Author : Christopher Faulet
7 Contact : cfaulet at haproxy dot com
8
9
10SUMMARY
11--------
12
13 0. Terms
14 1. Introduction
15 2. SPOE configuration
16 2.1. SPOE scope
17 2.2. "spoe-agent" section
18 2.3. "spoe-message" section
Christopher Faulet11610f32017-09-21 10:23:10 +020019 2.4. "spoe-group" section
20 2.5. Example
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +020021 3. SPOP specification
22 3.1. Data types
23 3.2. Frames
24 3.2.1. Frame capabilities
25 3.2.2. Frame types overview
26 3.2.3. Workflow
27 3.2.4. Frame: HAPROXY-HELLO
28 3.2.5. Frame: AGENT-HELLO
29 3.2.6. Frame: NOTIFY
30 3.2.7. Frame: ACK
31 3.2.8. Frame: HAPROXY-DISCONNECT
32 3.2.9. Frame: AGENT-DISCONNECT
33 3.3. Events & messages
34 3.4. Actions
Christopher Fauletd1307ce2017-02-27 21:59:39 +010035 3.5. Errors & timeouts
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +020036
37
380. Terms
39---------
40
41* SPOE : Stream Processing Offload Engine.
42
43 A SPOE is a filter talking to servers managed ba a SPOA to offload the
44 stream processing. An engine is attached to a proxy. A proxy can have
Christopher Fauletd1307ce2017-02-27 21:59:39 +010045 several engines. Each engine is linked to an agent and only one.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +020046
47* SPOA : Stream Processing Offload Agent.
48
49 A SPOA is a service that will receive info from a SPOE to offload the
50 stream processing. An agent manages several servers. It uses a backend to
51 reference all of them. By extension, these servers can also be called
52 agents.
53
54* SPOP : Stream Processing Offload Protocol, used by SPOEs to talk to SPOA
55 servers.
56
57 This protocol is used by engines to talk to agents. It is an in-house
58 binary protocol described in this documentation.
59
60
611. Introduction
62----------------
63
64SPOE is a feature introduced in HAProxy 1.7. It makes possible the
65communication with external components to retrieve some info. The idea started
66with the problems caused by most ldap libs not working fine in event-driven
67systems (often at least the connect() is blocking). So, it is hard to properly
68implement Single Sign On solution (SSO) in HAProxy. The SPOE will ease this
69kind of processing, or we hope so.
70
71Now, the aim of SPOE is to allow any kind of offloading on the streams. First
72releases, besides being experimental, won't do lot of things. As we will see,
73there are few handled events and even less actions supported. Actually, for
74now, the SPOE can offload the processing before "tcp-request content",
75"tcp-response content", "http-request" and "http-response" rules. And it only
76supports variables definition. But, in spite of these limited features, we can
77easily imagine to implement SSO solution, ip reputation or ip geolocation
78services.
79
80
812. SPOE configuration
82----------------------
83
84Because SPOE is implemented as a filter, To use it, you must declare a "filter
85spoe" line in a proxy section (frontend/backend/listen) :
86
87 frontend my-front
88 ...
89 filter spoe [engine <name>] config <file>
90 ...
91
92The "config" parameter is mandatory. It specififies the SPOE configuration
93file. The engine name is optional. It can be set to declare the scope to use in
94the SPOE configuration. So it is possible to use the same SPOE configuration
95for several engines. If no name is provided, the SPOE configuration must not
96contain any scope directive.
97
98We use a separate configuration file on purpose. By commenting SPOE filter
99line, you completly disable the feature, including the parsing of sections
100reserved to SPOE. This is also a way to keep the HAProxy configuration clean.
101
102A SPOE configuration file must contains, at least, the SPOA configuration
Christopher Faulet11610f32017-09-21 10:23:10 +0200103("spoe-agent" section) and SPOE messages/groups ("spoe-message" or "spoe-group"
104sections) attached to this agent.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200105
106IMPORTANT : The configuration of a SPOE filter must be located in a dedicated
107file. But the backend used by a SPOA must be declared in HAProxy configuration
108file.
109
1102.1. SPOE scope
111-------------------------
112
113If you specify an engine name on the SPOE filter line, then you need to define
114scope in the SPOE configuration with the same name. You can have several SPOE
115scope in the same file. In each scope, you must define one and only one
116"spoe-agent" section to configure the SPOA linked to your SPOE and several
Christopher Faulet11610f32017-09-21 10:23:10 +0200117"spoe-message" and "spoe-group" sections to describe, respecively, messages and
118group of messages sent to servers mananged by your SPOA.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200119
120A SPOE scope starts with this kind of line :
121
122 [<name>]
123
124where <name> is the same engine name specified on the SPOE filter line. The
125scope ends when the file ends or when another scope is found.
126
127 Example :
128 [my-first-engine]
129 spoe-agent my-agent
130 ...
131 spoe-message msg1
132 ...
133 spoe-message msg2
134 ...
Christopher Faulet11610f32017-09-21 10:23:10 +0200135 spoe-group grp1
136 ...
137 spoe-group grp2
138 ...
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200139
140 [my-second-engine]
141 ...
142
143If no engine name is provided on the SPOE filter line, no SPOE scope must be
144found in the SPOE configuration file. All the file is considered to be in the
145same anonymous and implicit scope.
146
Christopher Faulet7ee86672017-09-19 11:08:28 +0200147The engine name must be uniq for a proxy. If no engine name is provided on the
148SPOE filter line, the SPOE agent name is unsed by default.
149
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02001502.2. "spoe-agent" section
151--------------------------
152
153For each engine, you must define one and only one "spoe-agent" section. In this
154section, you will declare SPOE messages and the backend you will use. You will
155also set timeouts and options to customize your agent's behaviour.
156
157
158spoe-agent <name>
159 Create a new SPOA with the name <name>. It must have one and only one
160 "spoe-agent" definition by SPOE scope.
161
162 Arguments :
163 <name> is the name of the agent section.
164
165 following keywords are supported :
Christopher Faulet11610f32017-09-21 10:23:10 +0200166 - groups
Christopher Faulet48026722016-11-16 15:01:12 +0100167 - maxconnrate
168 - maxerrrate
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100169 - max-frame-size
Christopher Faulete8ade382018-01-25 15:32:22 +0100170 - max-waiting-frames
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200171 - messages
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100172 - [no] option async
173 - [no] option pipelining
174 - [no] option send-frag-payload
Christopher Fauletea62c2a2016-11-14 10:54:21 +0100175 - option continue-on-error
Christopher Faulet336d3ef2017-12-22 10:00:55 +0100176 - option force-set-var
Christopher Faulet985532d2016-11-16 15:36:19 +0100177 - option set-on-error
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200178 - option var-prefix
Christopher Faulet336d3ef2017-12-22 10:00:55 +0100179 - register-var-names
Christopher Faulet03a34492016-11-19 16:47:56 +0100180 - timeout hello|idle|processing
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200181 - use-backend
182
183
Christopher Faulet11610f32017-09-21 10:23:10 +0200184groups <grp-name> ...
185 Declare the list of SPOE groups that an agent will handle.
186
187 Arguments :
188 <grp-name> is the name of a SPOE group.
189
190 Groups delcared here must be found in the same engine scope, else an error is
191 triggered during the configuration parsing. You can have many "groups" lines.
192
193 See also: "spoe-group" section.
194
195
Christopher Faulet48026722016-11-16 15:01:12 +0100196maxconnrate <number>
197 Set the maximum number of connections per second to <number>. The SPOE will
198 stop to open new connections if the maximum is reached and will wait to
199 acquire an existing one. So it is important to set "timeout hello" to a
200 relatively small value.
201
202
203maxerrrate <number>
204 Set the maximum number of errors per second to <number>. The SPOE will stop
205 its processing if the maximum is reached.
206
207
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100208max-frame-size <number>
209 Set the maximum allowed size for frames exchanged between HAProxy and SPOA.
210 It must be in the range [256, tune.bufsize-4] (4 bytes are reserved for the
211 frame length). By default, it is set to (tune.bufsize-4).
212
Christopher Faulete8ade382018-01-25 15:32:22 +0100213max-waiting-frames <number>
214 Set the maximum number of frames waiting for an acknowledgement on the same
215 connection. This value is only used when the pipelinied or asynchronus
216 exchanges between HAProxy and SPOA are enabled. By default, it is set to 20.
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100217
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200218messages <msg-name> ...
219 Declare the list of SPOE messages that an agent will handle.
220
221 Arguments :
222 <msg-name> is the name of a SPOE message.
223
224 Messages declared here must be found in the same engine scope, else an error
225 is triggered during the configuration parsing. You can have many "messages"
226 lines.
227
228 See also: "spoe-message" section.
229
230
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100231option async
232no option async
233 Enable or disable the support of asynchronus exchanges between HAProxy and
234 SPOA. By default, this option is enabled.
235
236
Christopher Fauletea62c2a2016-11-14 10:54:21 +0100237option continue-on-error
238 Do not stop the events processing when an error occurred on a stream.
239
240 By default, for a specific stream, when an abnormal/unexpected error occurs,
241 the SPOE is disabled for all the transaction. So if you have several events
242 configured, such error on an event will disabled all followings. For TCP
243 streams, this will disable the SPOE for the whole session. For HTTP streams,
244 this will disable it for the transaction (request and response).
245
246 When set, this option bypass this behaviour and only the current event will
247 be ignored.
248
Etienne Carriereaec89892017-12-14 09:36:40 +0000249option force-set-var
250 By default, SPOE filter only register already known variables (mainly from
251 parsing of the configuration). If you want that haproxy trusts the agent and
252 registers all variables (ex: can be useful for LUA workload), activate this
253 option.
254
255 Caution : this option opens to a variety of attacks such as a rogue SPOA that
256 asks to register too many variables.
257
Christopher Fauletea62c2a2016-11-14 10:54:21 +0100258
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100259option pipelining
260no option pipelining
261 Enable or disable the support of pipelined exchanges between HAProxy and
262 SPOA. By default, this option is enabled.
263
264
265option send-frag-payload
266no option send-frag-payload
267 Enable or disable the sending of fragmented payload to SPOA. By default, this
268 option is enabled.
269
270
Christopher Faulet985532d2016-11-16 15:36:19 +0100271option set-on-error <var name>
272 Define the variable to set when an error occurred during an event processing.
273
274 Arguments :
275
276 <var name> is the variable name, without the scope. The name may only
277 contain characters 'a-z', 'A-Z', '0-9', '.' and '_'.
278
279 This variable will only be set when an error occurred in the scope of the
280 transaction. As for all other variables define by the SPOE, it will be
281 prefixed. So, if your variable name is "error" and your prefix is
282 "my_spoe_pfx", the variable will be "txn.my_spoe_pfx.error".
283
Christopher Fauletb067b062017-01-04 16:39:11 +0100284 When set, the variable is an integer representing the error reason. For values
285 under 256, it represents an error coming from the engine. Below 256, it
286 reports a SPOP error. In this case, to retrieve the right SPOP status code,
287 you must remove 256 to this value. Here are possible values:
288
289 * 1 a timeout occurred during the event processing.
290
291 * 2 an error was triggered during the ressources allocation.
292
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100293 * 3 the frame payload exceeds the frame size and it cannot be
294 fragmented.
295
296 * 4 the fragmentation of a payload is aborted.
297
Christopher Faulet344c4ab2017-09-22 10:20:13 +0200298 * 5 The frame processing has been interrupted by HAProxy.
299
Christopher Fauletb067b062017-01-04 16:39:11 +0100300 * 255 an unknown error occurred during the event processing.
301
302 * 256+N a SPOP error occurred during the event processing (see section
303 "Errors & timeouts").
304
305 Note that if "option continue-on-error" is set, the variable is not
306 automatically removed between events processing.
Christopher Faulet985532d2016-11-16 15:36:19 +0100307
308 See also: "option continue-on-error", "option var-prefix".
309
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200310option var-prefix <prefix>
311 Define the prefix used when variables are set by an agent.
312
313 Arguments :
314
315 <prefix> is the prefix used to limit the scope of variables set by an
316 agent.
317
318 To avoid conflict with other variables defined by HAProxy, all variables
319 names will be prefixed. By default, the "spoe-agent" name is used. This
320 option can be used to customize it.
321
322 The prefix will be added between the variable scope and its name, separated
323 by a '.'. It may only contain characters 'a-z', 'A-Z', '0-9', '.' and '_', as
324 for variables name. In HAProxy configuration, you need to use this prefix as
325 a part of the variables name. For example, if an agent define the variable
326 "myvar" in the "txn" scope, with the prefix "my_spoe_pfx", then you should
327 use "txn.my_spoe_pfx.myvar" name in your HAProxy configuration.
328
Etienne Carriereaec89892017-12-14 09:36:40 +0000329 By default, an agent will never set new variables at runtime: It can only set
330 new value for existing ones. If you want a different behaviour, see
Christopher Faulet336d3ef2017-12-22 10:00:55 +0100331 force-set-var option and register-var-names directive.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200332
Christopher Faulet336d3ef2017-12-22 10:00:55 +0100333register-var-names <var name> ...
334 Register some variable names. By default, an agent will not be allowed to set
335 new variables at runtime. This rule can be totally relaxed by setting the
336 option "force-set-var". If you know all the variables you will need, this
337 directive is a good way to register them without letting an agent doing what
338 it want. This is only required if these variables are not referenced anywhere
339 in the HAProxy configuration or the SPOE one.
340
341 Arguments:
342 <var name> is a variable name without the scope. The name may only
343 contain characters 'a-z', 'A-Z', '0-9', '.' and '_'.
344
345 The prefix will be automatically added during the registration. You can have
346 many "register-var-names" lines.
347
348 See also: "option force-set-var", "option var-prefix".
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200349
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200350timeout hello <timeout>
351 Set the maximum time to wait for an agent to receive the AGENT-HELLO frame.
Christopher Fauletf7a30922016-11-10 15:04:51 +0100352 It is applied on the stream that handle the connection with the agent.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200353
354 Arguments :
355 <timeout> is the timeout value specified in milliseconds by default, but
356 can be in any other unit if the number is suffixed by the unit,
357 as explained at the top of this document.
358
359 This timeout is an applicative timeout. It differ from "timeout connect"
360 defined on backends.
361
362
363timeout idle <timeout>
Christopher Fauletf7a30922016-11-10 15:04:51 +0100364 Set the maximum time to wait for an agent to close an idle connection. It is
365 applied on the stream that handle the connection with the agent.
366
367 Arguments :
368 <timeout> is the timeout value specified in milliseconds by default, but
369 can be in any other unit if the number is suffixed by the unit,
370 as explained at the top of this document.
371
372
373timeout processing <timeout>
374 Set the maximum time to wait for a stream to process an event, i.e to acquire
375 a stream to talk with an agent, to encode all messages, to send the NOTIFY
376 frame, to receive the corrsponding acknowledgement and to process all
377 actions. It is applied on the stream that handle the client and the server
378 sessions.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200379
380 Arguments :
381 <timeout> is the timeout value specified in milliseconds by default, but
382 can be in any other unit if the number is suffixed by the unit,
383 as explained at the top of this document.
384
385
386use-backend <backend>
387 Specify the backend to use. It must be defined.
388
389 Arguments :
390 <backend> is the name of a valid "backend" section.
391
392
3932.3. "spoe-message" section
394----------------------------
395
396To offload the stream processing, SPOE will send messages with specific
397information at a specific moment in the stream life and will wait for
398corresponding replies to know what to do.
399
400
401spoe-message <name>
402 Create a new SPOE message with the name <name>.
403
404 Arguments :
405 <name> is the name of the SPOE message.
406
407 Here you define a message that can be referenced in a "spoe-agent"
408 section. Following keywords are supported :
Christopher Faulet57583e42017-09-04 15:41:09 +0200409 - acl
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200410 - args
411 - event
412
413 See also: "spoe-agent" section.
414
415
Christopher Faulet57583e42017-09-04 15:41:09 +0200416acl <aclname> <criterion> [flags] [operator] <value> ...
Christopher Faulet57583e42017-09-04 15:41:09 +0200417 Declare or complete an access list.
418
419 See section 7 about ACL usage in the HAProxy Configuration Manual.
420
421
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200422args [name=]<sample> ...
423 Define arguments passed into the SPOE message.
424
425 Arguments :
426 <sample> is a sample expression.
427
428 When the message is processed, if a sample expression is not available, it is
429 set to NULL. Arguments are processed in their declaration order and added in
430 the message in that order. It is possible to declare named arguements.
431
432 For example:
433 args frontend=fe_id src dst
434
435
Christopher Faulet57583e42017-09-04 15:41:09 +0200436event <name> [ { if | unless } <condition> ]
437 Set the event that triggers sending of the message. It may optionally be
438 followed by an ACL-based condition, in which case it will only be evaluated
439 if the condition is true.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200440
Christopher Faulet57583e42017-09-04 15:41:09 +0200441 ACL-based conditions are executed in the context of the stream that handle
442 the client and the server connections.
443
444 Arguments :
445 <name> is the event name.
446 <condition> is a standard ACL-based condition.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200447
448 Supported events are:
449 - on-client-session
Christopher Faulet1002aac2016-12-09 17:41:54 +0100450 - on-server-session
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200451 - on-frontend-tcp-request
452 - on-backend-tcp-request
453 - on-tcp-response
454 - on-frontend-http-request
455 - on-backend-http-request
456 - on-http-response
457
Christopher Faulet57583e42017-09-04 15:41:09 +0200458 See section "Events & Messages" for more details about supported events.
459 See section 7 about ACL usage in the HAProxy Configuration Manual.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200460
Christopher Faulet11610f32017-09-21 10:23:10 +02004612.4. "spoe-group" section
462--------------------------
463
464This section can be used to declare a group of SPOE messages. Unlike messages
465referenced in a "spoe-agent" section, messages inside a group are not sent on a
466specific event. The sending must be triggered by TCP or HTTP rules, from the
467HAProxy configuration.
468
469
470spoe-group <name>
471 Create a new SPOE group with the name <name>.
472
473 Arguments :
474 <name> is the name of the SPOE group.
475
476 Here you define a group of SPOE messages that can be referenced in a
477 "spoe-agent" section. Following keywords are supported :
478 - messages
479
480 See also: "spoe-agent" and "spoe-message" sections.
481
482
483messages <msg-name> ...
484 Declare the list of SPOE messages belonging to the group.
485
486 Arguments :
487 <msg-name> is the name of a SPOE message.
488
489 Messages declared here must be found in the same engine scope, else an error
490 is triggered during the configuration parsing. Furthermore, a message belongs
491 at most to a group. You can have many "messages" lines.
492
493 See also: "spoe-message" section.
494
495
4962.5. Example
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200497-------------
498
499Here is a simple but complete example that sends client-ip address to a ip
500reputation service. This service can set the variable "ip_score" which is an
501integer between 0 and 100, indicating its reputation (100 means totally safe
502and 0 a blacklisted IP with no doubt).
503
504 ###
505 ### HAProxy configuration
506 frontend www
507 mode http
508 bind *:80
509
510 filter spoe engine ip-reputation config spoe-ip-reputation.conf
511
512 # Reject connection if the IP reputation is under 20
513 tcp-request content reject if { var(sess.iprep.ip_score) -m int lt 20 }
514
515 default_backend http-servers
516
517 backend http-servers
518 mode http
519 server http A.B.C.D:80
520
521 backend iprep-servers
522 mode tcp
523 balance roundrobin
524
525 timeout connect 5s # greater than hello timeout
526 timeout server 3m # greater than idle timeout
527
528 server iprep1 A1.B1.C1.D1:12345
529 server iprep2 A2.B2.C2.D2:12345
530
531 ####
532 ### spoe-ip-reputation.conf
533 [ip-reputation]
534
535 spoe-agent iprep-agent
536 messages get-ip-reputation
537
538 option var-prefix iprep
539
Christopher Faulet03a34492016-11-19 16:47:56 +0100540 timeout hello 2s
541 timeout idle 2m
542 timeout processing 10ms
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200543
544 use-backend iprep-servers
545
546 spoe-message get-ip-reputation
547 args ip=src
Christopher Faulet57583e42017-09-04 15:41:09 +0200548 event on-client-session if ! { src -f /etc/haproxy/whitelist.lst }
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200549
550
5513. SPOP specification
552----------------------
553
5543.1. Data types
555----------------
556
557Here is the bytewise representation of typed data:
558
559 TYPED-DATA : <TYPE:4 bits><FLAGS:4 bits><DATA>
560
561Supported types and their representation are:
562
563 TYPE | ID | DESCRIPTION
564 -----------------------------+-----+----------------------------------
565 NULL | 0 | NULL : <0>
566 Boolean | 1 | BOOL : <1+FLAG>
567 32bits signed integer | 2 | INT32 : <2><VALUE:varint>
568 32bits unsigned integer | 3 | UINT32 : <3><VALUE:varint>
569 64bits signed integer | 4 | INT64 : <4><VALUE:varint>
570 32bits unsigned integer | 5 | UNIT64 : <5><VALUE:varint>
571 IPV4 | 6 | IPV4 : <6><STRUCT IN_ADDR:4 bytes>
572 IPV6 | 7 | IPV6 : <7><STRUCT IN_ADDR6:16 bytes>
573 String | 8 | STRING : <8><LENGTH:varint><BYTES>
574 Binary | 9 | BINARY : <9><LENGTH:varint><BYTES>
575 10 -> 15 unused/reserved | - | -
576 -----------------------------+-----+----------------------------------
577
578Variable-length integer (varint) are encoded using Peers encoding:
579
580
581 0 <= X < 240 : 1 byte (7.875 bits) [ XXXX XXXX ]
582 240 <= X < 2288 : 2 bytes (11 bits) [ 1111 XXXX ] [ 0XXX XXXX ]
583 2288 <= X < 264432 : 3 bytes (18 bits) [ 1111 XXXX ] [ 1XXX XXXX ] [ 0XXX XXXX ]
584 264432 <= X < 33818864 : 4 bytes (25 bits) [ 1111 XXXX ] [ 1XXX XXXX ]*2 [ 0XXX XXXX ]
585 33818864 <= X < 4328786160 : 5 bytes (32 bits) [ 1111 XXXX ] [ 1XXX XXXX ]*3 [ 0XXX XXXX ]
586 ...
587
588For booleans, the value (true or false) is the first bit in the FLAGS
589bitfield. if this bit is set to 0, then the boolean is evaluated as false,
590otherwise, the boolean is evaluated as true.
591
5923.2. Frames
593------------
594
595Exchange between HAProxy and agents are made using FRAME packets. All frames
596must be prefixed with their size encoded on 4 bytes in network byte order:
597
598 <FRAME-LENGTH:4 bytes> <FRAME>
599
600A frame always starts with its type, on one byte, followed by metadata
601containing flags, on 4 bytes and a two variable-length integer representing the
602stream identifier and the frame identifier inside the stream:
603
604 FRAME : <FRAME-TYPE:1 byte> <METADATA> <FRAME-PAYLOAD>
605 METADATA : <FLAGS:4 bytes> <STREAM-ID:varint> <FRAME-ID:varint>
606
607Then comes the frame payload. Depending on the frame type, the payload can be
608of three types: a simple key/value list, a list of messages or a list of
609actions.
610
611 FRAME-PAYLOAD : <LIST-OF-MESSAGES> | <LIST-OF-ACTIONS> | <KV-LIST>
612
613 LIST-OF-MESSAGES : [ <MESSAGE-NAME> <NB-ARGS:1 byte> <KV-LIST> ... ]
614 MESSAGE-NAME : <STRING>
615
616 LIST-OF-ACTIONS : [ <ACTION-TYPE:1 byte> <NB-ARGS:1 byte> <ACTION-ARGS> ... ]
617 ACTION-ARGS : [ <TYPED-DATA>... ]
618
619 KV-LIST : [ <KV-NAME> <KV-VALUE> ... ]
620 KV-NAME : <STRING>
621 KV-VALUE : <TYPED-DATA>
622
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100623 FLAGS : 0 1 2-31
624 +---+---+----------+
625 | | A | |
626 | F | B | |
627 | I | O | RESERVED |
628 | N | R | |
629 | | T | |
630 +---+---+----------+
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200631
632 FIN: Indicates that this is the final payload fragment. The first fragment
633 may also be the final fragment.
634
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100635 ABORT: Indicates that the processing of the current frame must be
636 cancelled. This bit should be set on frames with a fragmented
637 payload. It can be ignore for frames with an unfragemnted
638 payload. When it is set, the FIN bit must also be set.
639
640
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200641Frames cannot exceed a maximum size negociated between HAProxy and agents
642during the HELLO handshake. Most of time, payload will be small enough to send
643it in one frame. But when supported by the peer, it will be possible to
644fragment huge payload on many frames. This ability is announced during the
645HELLO handshake and it can be asynmetric (supported by agents but not by
646HAProxy or the opposite). The following rules apply to fragmentation:
647
648 * An unfragemnted payload consists of a single frame with the FIN bit set.
649
650 * A fragemented payload consists of several frames with the FIN bit clear and
651 terminated by a single frame with the FIN bit set. All these frames must
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100652 share the same STREAM-ID and FRAME-ID. The first frame must set the right
653 FRAME-TYPE (e.g, NOTIFY). The following frames must have an unset type (0).
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200654
655Beside the support of fragmented payload by a peer, some payload must not be
656fragmented. See below for details.
657
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100658IMPORTANT : The maximum size supported by peers for a frame must be greater
659than or equal to 256 bytes.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200660
6613.2.1. Frame capabilities
662--------------------------
663
664Here are the list of official capabilities that HAProxy and agents can support:
665
Christopher Fauleta1cda022016-12-21 08:58:06 +0100666 * fragmentation: This is the ability for a peer to support fragmented
667 payload in received frames. This is an asymmectical
668 capability, it only concerns the peer that announces
669 it. This is the responsibility to the other peer to use it
670 or not.
671
672 * pipelining: This is the ability for a peer to decouple NOTIFY and ACK
673 frames. This is a symmectical capability. To be used, it must
674 be supported by HAproxy and agents. Unlike HTTP pipelining, the
675 ACK frames can be send in any order, but always on the same TCP
676 connection used for the corresponding NOTIFY frame.
677
678 * async: This ability is similar to the pipelining, but here any TCP
679 connection established between HAProxy and the agent can be used to
680 send ACK frames. if an agent accepts connections from multiple
681 HAProxy, it can use the "engine-id" value to group TCP
682 connections. See details about HAPROXY-HELLO frame.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200683
684Unsupported or unknown capabilities are silently ignored, when possible.
685
6863.2.2. Frame types overview
687----------------------------
688
689Here are types of frame supported by SPOE. Frames sent by HAProxy come first,
690then frames sent by agents :
691
692 TYPE | ID | DESCRIPTION
693 -----------------------------+-----+-------------------------------------
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100694 UNSET | 0 | Used for all frames but the first when a
695 | | payload is fragmented.
696 -----------------------------+-----+-------------------------------------
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200697 HAPROXY-HELLO | 1 | Sent by HAProxy when it opens a
698 | | connection on an agent.
699 | |
700 HAPROXY-DISCONNECT | 2 | Sent by HAProxy when it want to close
701 | | the connection or in reply to an
702 | | AGENT-DISCONNECT frame
703 | |
704 NOTIFY | 3 | Sent by HAProxy to pass information
705 | | to an agent
706 -----------------------------+-----+-------------------------------------
707 AGENT-HELLO | 101 | Reply to a HAPROXY-HELLO frame, when
708 | | the connection is established
709 | |
710 AGENT-DISCONNECT | 102 | Sent by an agent just before closing
711 | | the connection
712 | |
713 ACK | 103 | Sent to acknowledge a NOTIFY frame
714 -----------------------------+-----+-------------------------------------
715
716Unknown frames may be silently skipped.
717
7183.2.3. Workflow
719----------------
720
721 * Successful HELLO handshake:
722
723 HAPROXY AGENT SRV
724 | HAPROXY-HELLO |
Christopher Fauletba7bc162016-11-07 21:07:38 +0100725 | (healthcheck: false) |
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200726 | --------------------------> |
727 | |
728 | AGENT-HELLO |
729 | <-------------------------- |
730 | |
731
Christopher Fauletba7bc162016-11-07 21:07:38 +0100732 * Successful HELLO healthcheck:
733
734 HAPROXY AGENT SRV
735 | HAPROXY-HELLO |
736 | (healthcheck: true) |
737 | --------------------------> |
738 | |
739 | AGENT-HELLO + close() |
740 | <-------------------------- |
741 | |
742
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200743
744 * Error encountered by agent during the HELLO handshake:
745
746 HAPROXY AGENT SRV
747 | HAPROXY-HELLO |
748 | --------------------------> |
749 | |
750 | DISCONNECT + close() |
751 | <-------------------------- |
752 | |
753
754 * Error encountered by HAProxy during the HELLO handshake:
755
756 HAPROXY AGENT SRV
757 | HAPROXY-HELLO |
758 | --------------------------> |
759 | |
760 | AGENT-HELLO |
761 | <-------------------------- |
762 | |
763 | DISCONNECT |
764 | --------------------------> |
765 | |
766 | DISCONNECT + close() |
767 | <-------------------------- |
768 | |
769
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100770 * Notify / Ack exchange (unfragmented payload):
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200771
772 HAPROXY AGENT SRV
773 | NOTIFY |
774 | --------------------------> |
775 | |
776 | ACK |
777 | <-------------------------- |
778 | |
779
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100780 * Notify / Ack exchange (fragmented payload):
781
782 HAPROXY AGENT SRV
783 | NOTIFY (frag 1) |
784 | --------------------------> |
785 | |
786 | UNSET (frag 2) |
787 | --------------------------> |
788 | ... |
789 | UNSET (frag N) |
790 | --------------------------> |
791 | |
792 | ACK |
793 | <-------------------------- |
794 | |
795
796 * Aborted fragmentation of a NOTIFY frame:
797
798 HAPROXY AGENT SRV
799 | ... |
800 | UNSET (frag X) |
801 | --------------------------> |
802 | |
803 | ACK/ABORT |
804 | <-------------------------- |
805 | |
806 | UNSET (frag X+1) |
807 | -----------X |
808 | |
809 | |
810
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200811 * Connection closed by haproxy:
812
813 HAPROXY AGENT SRV
814 | DISCONNECT |
815 | --------------------------> |
816 | |
817 | DISCONNECT + close() |
818 | <-------------------------- |
819 | |
820
821 * Connection closed by agent:
822
823 HAPROXY AGENT SRV
824 | DISCONNECT + close() |
825 | <-------------------------- |
826 | |
827
8283.2.4. Frame: HAPROXY-HELLO
829----------------------------
830
831This frame is the first one exchanged between HAProxy and an agent, when the
832connection is established. The payload of this frame is a KV-LIST. It cannot be
833fragmented. STREAM-ID and FRAME-ID are must be set 0.
834
835Following items are mandatory in the KV-LIST:
836
837 * "supported-versions" <STRING>
838
839 Last SPOP major versions supported by HAProxy. It is a comma-separated list
840 of versions, following the format "Major.Minor". Spaces must be ignored, if
841 any. When a major version is announced by HAProxy, it means it also support
842 all previous minor versions.
843
844 Example: "2.0, 1.5" means HAProxy supports SPOP 2.0 and 1.0 to 1.5
845
846 * "max-frame-size" <UINT32>
847
848 This is the maximum size allowed for a frame. The HAPROXY-HELLO frame must
849 be lower or equal to this value.
850
851 * "capabilities" <STRING>
852
853 This a comma-separated list of capabilities supported by HAProxy. Spaces
854 must be ignored, if any.
855
Christopher Fauletba7bc162016-11-07 21:07:38 +0100856Following optional items can be added in the KV-LIST:
857
858 * "healthcheck" <BOOLEAN>
859
860 If this item is set to TRUE, then the HAPROXY-HELLO frame is sent during a
861 SPOE health check. When set to FALSE, this item can be ignored.
862
Christopher Fauleta1cda022016-12-21 08:58:06 +0100863 * "engine-id" <STRING>
864
865 This is a uniq string that identify a SPOE engine.
866
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200867To finish the HELLO handshake, the agent must return an AGENT-HELLO frame with
868its supported SPOP version, the lower value between its maximum size allowed
869for a frame and the HAProxy one and capabilities it supports. If an error
870occurs or if an incompatibility is detected with the agent configuration, an
871AGENT-DISCONNECT frame must be returned.
872
8733.2.5. Frame: AGENT-HELLO
874--------------------------
875
876This frame is sent in reply to a HAPROXY-HELLO frame to finish a HELLO
877handshake. As for HAPROXY-HELLO frame, STREAM-ID and FRAME-ID are also set
8780. The payload of this frame is a KV-LIST and it cannot be fragmented.
879
880Following items are mandatory in the KV-LIST:
881
882 * "version" <STRING>
883
884 This is the SPOP version the agent supports. It must follow the format
885 "Major.Minor" and it must be lower or equal than one of major versions
886 announced by HAProxy.
887
888 * "max-frame-size" <UINT32>
889
890 This is the maximum size allowed for a frame. It must be lower or equal to
891 the value in the HAPROXY-HELLO frame. This value will be used for all
892 subsequent frames.
893
894 * "capabilities" <STRING>
895
896 This a comma-separated list of capabilities supported by agent. Spaces must
897 be ignored, if any.
898
899At this time, if everything is ok for HAProxy (supported version and valid
900max-frame-size value), the HELLO handshake is successfully completed. Else,
901HAProxy sends a HAPROXY-DISCONNECT frame with the corresponding error.
902
Christopher Fauletba7bc162016-11-07 21:07:38 +0100903If "healthcheck" item was set to TRUE in the HAPROXY-HELLO frame, the agent can
904safely close the connection without DISCONNECT frame. In all cases, HAProxy
905will close the connexion at the end of the health check.
906
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02009073.2.6. Frame: NOTIFY
908---------------------
909
910Information are sent to the agents inside NOTIFY frames. These frames are
911attached to a stream, so STREAM-ID and FRAME-ID must be set. The payload of
912NOTIFY frames is a LIST-OF-MESSAGES and, if supported by agents, it can be
913fragmented.
914
915NOTIFY frames must be acknowledge by agents sending an ACK frame, repeating
916right STREAM-ID and FRAME-ID.
917
9183.2.7. Frame: ACK
919------------------
920
921ACK frames must be sent by agents to reply to NOTIFY frames. STREAM-ID and
922FRAME-ID found in a NOTIFY frame must be reuse in the corresponding ACK
923frame. The payload of ACK frames is a LIST-OF-ACTIONS and, if supported by
924HAProxy, it can be fragmented.
925
9263.2.8. Frame: HAPROXY-DISCONNECT
927---------------------------------
928
929If an error occurs, at anytime, from the HAProxy side, a HAPROXY-DISCONNECT
930frame is sent with information describing the error. HAProxy will wait an
931AGENT-DISCONNECT frame in reply. All other frames will be ignored. The agent
932must then close the socket.
933
934The payload of this frame is a KV-LIST. It cannot be fragmented. STREAM-ID and
935FRAME-ID are must be set 0.
936
937Following items are mandatory in the KV-LIST:
938
939 * "status-code" <UINT32>
940
941 This is the code corresponding to the error.
942
943 * "message" <STRING>
944
945 This is a textual message describing the error.
946
947For more information about known errors, see section "Errors & timeouts"
948
9493.2.9. Frame: AGENT-DISCONNECT
950-------------------------------
951
952If an error occurs, at anytime, from the agent size, a AGENT-DISCONNECT frame
953is sent, with information desribing the error. such frame is also sent in reply
954to a HAPROXY-DISCONNECT. The agent must close the socket just after sending
955this frame.
956
957The payload of this frame is a KV-LIST. It cannot be fragmented. STREAM-ID and
958FRAME-ID are must be set 0.
959
960Following items are mandatory in the KV-LIST:
961
962 * "status-code" <UINT32>
963
964 This is the code corresponding to the error.
965
966 * "message" <STRING>
967
968 This is a textual message describing the error.
969
970For more information about known errors, see section "Errors & timeouts"
971
9723.3. Events & Messages
973-----------------------
974
975Information about streams are sent in NOTIFY frames. You can specify which kind
976of information to send by defining "spoe-message" sections in your SPOE
977configuration file. for each "spoe-message" there will be a message in a NOTIFY
978frame when the right event is triggered.
979
980A NOTIFY frame is sent for an specific event when there is at least one
981"spoe-message" attached to this event. All messages for an event will be added
982in the same NOTIFY frame.
983
984Here is the list of supported events:
985
986 * on-client-session is triggered when a new client session is created.
987 This event is only available for SPOE filters
988 declared in a frontend or a listen section.
989
990 * on-frontend-tcp-request is triggered just before the evaluation of
991 "tcp-request content" rules on the frontend side.
992 This event is only available for SPOE filters
993 declared in a frontend or a listen section.
994
995 * on-backend-tcp-request is triggered just before the evaluation of
996 "tcp-request content" rules on the backend side.
997 This event is skipped for SPOE filters declared
998 in a listen section.
999
1000 * on-frontend-http-request is triggered just before the evaluation of
1001 "http-request" rules on the frontend side. This
1002 event is only available for SPOE filters declared
1003 in a frontend or a listen section.
1004
1005 * on-backend-http-request is triggered just before the evaluation of
1006 "http-request" rules on the backend side. This
1007 event is skipped for SPOE filters declared in a
1008 listen section.
1009
1010 * on-server-session is triggered when the session with the server is
1011 established.
1012
1013 * on-tcp-response is triggered just before the evaluation of
1014 "tcp-response content" rules.
1015
1016 * on-http-response is triggered just before the evaluation of
1017 "http-response" rules.
1018
1019
1020The stream processing will loop on these events, when triggered, waiting the
1021agent reply.
1022
10233.4. Actions
1024-------------
1025
1026An agent must acknowledge each NOTIFY frame by sending the corresponding ACK
1027frame. Actions can be added in these frames to dynamically take action on the
1028processing of a stream.
1029
1030Here is the list of supported actions:
1031
1032 * set-var set the value for an existing variable. 3 arguments must be
1033 attached to this action: the variable scope (proc, sess, txn,
1034 req or req), the variable name (a string) and its value.
1035
1036 ACTION-SET-VAR : <SET-VAR:1 byte><NB-ARGS:1 byte><VAR-SCOPE:1 byte><VAR-NAME><VAR-VALUE>
1037
1038 SET-VAR : <1>
1039 NB-ARGS : <3>
1040 VAR-SCOPE : <PROCESS> | <SESSION> | <TRANSACTION> | <REQUEST> | <RESPONSE>
1041 VAR-NAME : <STRING>
1042 VAR-VALUE : <TYPED-DATA>
1043
1044 PROCESS : <0>
1045 SESSION : <1>
1046 TRANSACTION : <2>
1047 REQUEST : <3>
Christopher Fauleta1cda022016-12-21 08:58:06 +01001048 RESPONSE : <4>
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02001049
1050 * unset-var unset the value for an existing variable. 2 arguments must be
1051 attached to this action: the variable scope (proc, sess, txn,
1052 req or req) and the variable name (a string).
1053
Christopher Faulet1002aac2016-12-09 17:41:54 +01001054 ACTION-UNSET-VAR : <UNSET-VAR:1 byte><NB-ARGS:1 byte><VAR-SCOPE:1 byte><VAR-NAME>
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02001055
Christopher Faulet1002aac2016-12-09 17:41:54 +01001056 UNSET-VAR : <2>
1057 NB-ARGS : <2>
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02001058 VAR-SCOPE : <PROCESS> | <SESSION> | <TRANSACTION> | <REQUEST> | <RESPONSE>
1059 VAR-NAME : <STRING>
1060
1061 PROCESS : <0>
1062 SESSION : <1>
1063 TRANSACTION : <2>
1064 REQUEST : <3>
Christopher Fauleta1cda022016-12-21 08:58:06 +01001065 RESPONSE : <4>
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02001066
1067
1068NOTE: Name of the variables will be automatically prefixed by HAProxy to avoid
1069 name clashes with other variables used in HAProxy. Moreover, unknown
1070 variable will be silently ignored.
1071
Christopher Fauletd1307ce2017-02-27 21:59:39 +010010723.5. Errors & timeouts
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02001073----------------------
1074
1075Here is the list of all known errors:
1076
1077 STATUS CODE | DESCRIPTION
1078 ----------------+--------------------------------------------------------
1079 0 | normal (no error occurred)
1080 1 | I/O error
1081 2 | A timeout occurred
1082 3 | frame is too big
1083 4 | invalid frame received
1084 5 | version value not found
1085 6 | max-frame-size value not found
1086 7 | capabilities value not found
1087 8 | unsupported version
1088 9 | max-frame-size too big or too small
Christopher Fauletd1307ce2017-02-27 21:59:39 +01001089 10 | payload fragmentation is not supported
1090 11 | invalid interlaced frames
1091 12 | frame-id not found (it does not match any referenced frame)
1092 13 | resource allocation error
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02001093 99 | an unknown error occurrde
1094 ----------------+--------------------------------------------------------
1095
1096An agent can define its own errors using a not yet assigned status code.
1097
Christopher Fauletea62c2a2016-11-14 10:54:21 +01001098IMPORTANT NOTE: By default, for a specific stream, when an abnormal/unexpected
1099 error occurs, the SPOE is disabled for all the transaction. So
1100 if you have several events configured, such error on an event
1101 will disabled all followings. For TCP streams, this will
1102 disable the SPOE for the whole session. For HTTP streams, this
1103 will disable it for the transaction (request and response).
1104 See 'option continue-on-error' to bypass this limitation.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02001105
1106To avoid a stream to wait infinitly, you must carefully choose the
1107acknowledgement timeout. In most of cases, it will be quiet low. But it depends
1108on the responsivness of your service.
1109
1110You must also choose idle timeout carefully. Because connection with your
1111service depends on the backend configuration used by the SPOA, it is important
1112to use a lower value for idle timeout than the server timeout. Else the
1113connection will be closed by HAProxy. The same is true for hello timeout. You
1114should choose a lower value than the connect timeout.
1115
1116
1117/*
1118 * Local variables:
1119 * fill-column: 79
1120 * End:
1121 */