blob: 961d32a43627af6190e0e2d296b42129674ce541 [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 Fauletf7e4e7e2016-10-27 22:29:49 +0200170 - messages
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100171 - [no] option async
172 - [no] option pipelining
173 - [no] option send-frag-payload
Christopher Fauletea62c2a2016-11-14 10:54:21 +0100174 - option continue-on-error
Christopher Faulet985532d2016-11-16 15:36:19 +0100175 - option set-on-error
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200176 - option var-prefix
Christopher Faulet03a34492016-11-19 16:47:56 +0100177 - timeout hello|idle|processing
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200178 - use-backend
179
180
Christopher Faulet11610f32017-09-21 10:23:10 +0200181groups <grp-name> ...
182 Declare the list of SPOE groups that an agent will handle.
183
184 Arguments :
185 <grp-name> is the name of a SPOE group.
186
187 Groups delcared here must be found in the same engine scope, else an error is
188 triggered during the configuration parsing. You can have many "groups" lines.
189
190 See also: "spoe-group" section.
191
192
Christopher Faulet48026722016-11-16 15:01:12 +0100193maxconnrate <number>
194 Set the maximum number of connections per second to <number>. The SPOE will
195 stop to open new connections if the maximum is reached and will wait to
196 acquire an existing one. So it is important to set "timeout hello" to a
197 relatively small value.
198
199
200maxerrrate <number>
201 Set the maximum number of errors per second to <number>. The SPOE will stop
202 its processing if the maximum is reached.
203
204
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100205max-frame-size <number>
206 Set the maximum allowed size for frames exchanged between HAProxy and SPOA.
207 It must be in the range [256, tune.bufsize-4] (4 bytes are reserved for the
208 frame length). By default, it is set to (tune.bufsize-4).
209
210
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200211messages <msg-name> ...
212 Declare the list of SPOE messages that an agent will handle.
213
214 Arguments :
215 <msg-name> is the name of a SPOE message.
216
217 Messages declared here must be found in the same engine scope, else an error
218 is triggered during the configuration parsing. You can have many "messages"
219 lines.
220
221 See also: "spoe-message" section.
222
223
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100224option async
225no option async
226 Enable or disable the support of asynchronus exchanges between HAProxy and
227 SPOA. By default, this option is enabled.
228
229
Christopher Fauletea62c2a2016-11-14 10:54:21 +0100230option continue-on-error
231 Do not stop the events processing when an error occurred on a stream.
232
233 By default, for a specific stream, when an abnormal/unexpected error occurs,
234 the SPOE is disabled for all the transaction. So if you have several events
235 configured, such error on an event will disabled all followings. For TCP
236 streams, this will disable the SPOE for the whole session. For HTTP streams,
237 this will disable it for the transaction (request and response).
238
239 When set, this option bypass this behaviour and only the current event will
240 be ignored.
241
Etienne Carriereaec89892017-12-14 09:36:40 +0000242option force-set-var
243 By default, SPOE filter only register already known variables (mainly from
244 parsing of the configuration). If you want that haproxy trusts the agent and
245 registers all variables (ex: can be useful for LUA workload), activate this
246 option.
247
248 Caution : this option opens to a variety of attacks such as a rogue SPOA that
249 asks to register too many variables.
250
Christopher Fauletea62c2a2016-11-14 10:54:21 +0100251
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100252option pipelining
253no option pipelining
254 Enable or disable the support of pipelined exchanges between HAProxy and
255 SPOA. By default, this option is enabled.
256
257
258option send-frag-payload
259no option send-frag-payload
260 Enable or disable the sending of fragmented payload to SPOA. By default, this
261 option is enabled.
262
263
Christopher Faulet985532d2016-11-16 15:36:19 +0100264option set-on-error <var name>
265 Define the variable to set when an error occurred during an event processing.
266
267 Arguments :
268
269 <var name> is the variable name, without the scope. The name may only
270 contain characters 'a-z', 'A-Z', '0-9', '.' and '_'.
271
272 This variable will only be set when an error occurred in the scope of the
273 transaction. As for all other variables define by the SPOE, it will be
274 prefixed. So, if your variable name is "error" and your prefix is
275 "my_spoe_pfx", the variable will be "txn.my_spoe_pfx.error".
276
Christopher Fauletb067b062017-01-04 16:39:11 +0100277 When set, the variable is an integer representing the error reason. For values
278 under 256, it represents an error coming from the engine. Below 256, it
279 reports a SPOP error. In this case, to retrieve the right SPOP status code,
280 you must remove 256 to this value. Here are possible values:
281
282 * 1 a timeout occurred during the event processing.
283
284 * 2 an error was triggered during the ressources allocation.
285
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100286 * 3 the frame payload exceeds the frame size and it cannot be
287 fragmented.
288
289 * 4 the fragmentation of a payload is aborted.
290
Christopher Faulet344c4ab2017-09-22 10:20:13 +0200291 * 5 The frame processing has been interrupted by HAProxy.
292
Christopher Fauletb067b062017-01-04 16:39:11 +0100293 * 255 an unknown error occurred during the event processing.
294
295 * 256+N a SPOP error occurred during the event processing (see section
296 "Errors & timeouts").
297
298 Note that if "option continue-on-error" is set, the variable is not
299 automatically removed between events processing.
Christopher Faulet985532d2016-11-16 15:36:19 +0100300
301 See also: "option continue-on-error", "option var-prefix".
302
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200303option var-prefix <prefix>
304 Define the prefix used when variables are set by an agent.
305
306 Arguments :
307
308 <prefix> is the prefix used to limit the scope of variables set by an
309 agent.
310
311 To avoid conflict with other variables defined by HAProxy, all variables
312 names will be prefixed. By default, the "spoe-agent" name is used. This
313 option can be used to customize it.
314
315 The prefix will be added between the variable scope and its name, separated
316 by a '.'. It may only contain characters 'a-z', 'A-Z', '0-9', '.' and '_', as
317 for variables name. In HAProxy configuration, you need to use this prefix as
318 a part of the variables name. For example, if an agent define the variable
319 "myvar" in the "txn" scope, with the prefix "my_spoe_pfx", then you should
320 use "txn.my_spoe_pfx.myvar" name in your HAProxy configuration.
321
Etienne Carriereaec89892017-12-14 09:36:40 +0000322 By default, an agent will never set new variables at runtime: It can only set
323 new value for existing ones. If you want a different behaviour, see
324 force-set-var option
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200325
326
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200327timeout hello <timeout>
328 Set the maximum time to wait for an agent to receive the AGENT-HELLO frame.
Christopher Fauletf7a30922016-11-10 15:04:51 +0100329 It is applied on the stream that handle the connection with the agent.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200330
331 Arguments :
332 <timeout> is the timeout value specified in milliseconds by default, but
333 can be in any other unit if the number is suffixed by the unit,
334 as explained at the top of this document.
335
336 This timeout is an applicative timeout. It differ from "timeout connect"
337 defined on backends.
338
339
340timeout idle <timeout>
Christopher Fauletf7a30922016-11-10 15:04:51 +0100341 Set the maximum time to wait for an agent to close an idle connection. It is
342 applied on the stream that handle the connection with the agent.
343
344 Arguments :
345 <timeout> is the timeout value specified in milliseconds by default, but
346 can be in any other unit if the number is suffixed by the unit,
347 as explained at the top of this document.
348
349
350timeout processing <timeout>
351 Set the maximum time to wait for a stream to process an event, i.e to acquire
352 a stream to talk with an agent, to encode all messages, to send the NOTIFY
353 frame, to receive the corrsponding acknowledgement and to process all
354 actions. It is applied on the stream that handle the client and the server
355 sessions.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200356
357 Arguments :
358 <timeout> is the timeout value specified in milliseconds by default, but
359 can be in any other unit if the number is suffixed by the unit,
360 as explained at the top of this document.
361
362
363use-backend <backend>
364 Specify the backend to use. It must be defined.
365
366 Arguments :
367 <backend> is the name of a valid "backend" section.
368
369
3702.3. "spoe-message" section
371----------------------------
372
373To offload the stream processing, SPOE will send messages with specific
374information at a specific moment in the stream life and will wait for
375corresponding replies to know what to do.
376
377
378spoe-message <name>
379 Create a new SPOE message with the name <name>.
380
381 Arguments :
382 <name> is the name of the SPOE message.
383
384 Here you define a message that can be referenced in a "spoe-agent"
385 section. Following keywords are supported :
Christopher Faulet57583e42017-09-04 15:41:09 +0200386 - acl
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200387 - args
388 - event
389
390 See also: "spoe-agent" section.
391
392
Christopher Faulet57583e42017-09-04 15:41:09 +0200393acl <aclname> <criterion> [flags] [operator] <value> ...
394
395 Declare or complete an access list.
396
397 See section 7 about ACL usage in the HAProxy Configuration Manual.
398
399
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200400args [name=]<sample> ...
401 Define arguments passed into the SPOE message.
402
403 Arguments :
404 <sample> is a sample expression.
405
406 When the message is processed, if a sample expression is not available, it is
407 set to NULL. Arguments are processed in their declaration order and added in
408 the message in that order. It is possible to declare named arguements.
409
410 For example:
411 args frontend=fe_id src dst
412
413
Christopher Faulet57583e42017-09-04 15:41:09 +0200414event <name> [ { if | unless } <condition> ]
415 Set the event that triggers sending of the message. It may optionally be
416 followed by an ACL-based condition, in which case it will only be evaluated
417 if the condition is true.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200418
Christopher Faulet57583e42017-09-04 15:41:09 +0200419 ACL-based conditions are executed in the context of the stream that handle
420 the client and the server connections.
421
422 Arguments :
423 <name> is the event name.
424 <condition> is a standard ACL-based condition.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200425
426 Supported events are:
427 - on-client-session
Christopher Faulet1002aac2016-12-09 17:41:54 +0100428 - on-server-session
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200429 - on-frontend-tcp-request
430 - on-backend-tcp-request
431 - on-tcp-response
432 - on-frontend-http-request
433 - on-backend-http-request
434 - on-http-response
435
Christopher Faulet57583e42017-09-04 15:41:09 +0200436 See section "Events & Messages" for more details about supported events.
437 See section 7 about ACL usage in the HAProxy Configuration Manual.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200438
Christopher Faulet11610f32017-09-21 10:23:10 +02004392.4. "spoe-group" section
440--------------------------
441
442This section can be used to declare a group of SPOE messages. Unlike messages
443referenced in a "spoe-agent" section, messages inside a group are not sent on a
444specific event. The sending must be triggered by TCP or HTTP rules, from the
445HAProxy configuration.
446
447
448spoe-group <name>
449 Create a new SPOE group with the name <name>.
450
451 Arguments :
452 <name> is the name of the SPOE group.
453
454 Here you define a group of SPOE messages that can be referenced in a
455 "spoe-agent" section. Following keywords are supported :
456 - messages
457
458 See also: "spoe-agent" and "spoe-message" sections.
459
460
461messages <msg-name> ...
462 Declare the list of SPOE messages belonging to the group.
463
464 Arguments :
465 <msg-name> is the name of a SPOE message.
466
467 Messages declared here must be found in the same engine scope, else an error
468 is triggered during the configuration parsing. Furthermore, a message belongs
469 at most to a group. You can have many "messages" lines.
470
471 See also: "spoe-message" section.
472
473
4742.5. Example
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200475-------------
476
477Here is a simple but complete example that sends client-ip address to a ip
478reputation service. This service can set the variable "ip_score" which is an
479integer between 0 and 100, indicating its reputation (100 means totally safe
480and 0 a blacklisted IP with no doubt).
481
482 ###
483 ### HAProxy configuration
484 frontend www
485 mode http
486 bind *:80
487
488 filter spoe engine ip-reputation config spoe-ip-reputation.conf
489
490 # Reject connection if the IP reputation is under 20
491 tcp-request content reject if { var(sess.iprep.ip_score) -m int lt 20 }
492
493 default_backend http-servers
494
495 backend http-servers
496 mode http
497 server http A.B.C.D:80
498
499 backend iprep-servers
500 mode tcp
501 balance roundrobin
502
503 timeout connect 5s # greater than hello timeout
504 timeout server 3m # greater than idle timeout
505
506 server iprep1 A1.B1.C1.D1:12345
507 server iprep2 A2.B2.C2.D2:12345
508
509 ####
510 ### spoe-ip-reputation.conf
511 [ip-reputation]
512
513 spoe-agent iprep-agent
514 messages get-ip-reputation
515
516 option var-prefix iprep
517
Christopher Faulet03a34492016-11-19 16:47:56 +0100518 timeout hello 2s
519 timeout idle 2m
520 timeout processing 10ms
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200521
522 use-backend iprep-servers
523
524 spoe-message get-ip-reputation
525 args ip=src
Christopher Faulet57583e42017-09-04 15:41:09 +0200526 event on-client-session if ! { src -f /etc/haproxy/whitelist.lst }
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200527
528
5293. SPOP specification
530----------------------
531
5323.1. Data types
533----------------
534
535Here is the bytewise representation of typed data:
536
537 TYPED-DATA : <TYPE:4 bits><FLAGS:4 bits><DATA>
538
539Supported types and their representation are:
540
541 TYPE | ID | DESCRIPTION
542 -----------------------------+-----+----------------------------------
543 NULL | 0 | NULL : <0>
544 Boolean | 1 | BOOL : <1+FLAG>
545 32bits signed integer | 2 | INT32 : <2><VALUE:varint>
546 32bits unsigned integer | 3 | UINT32 : <3><VALUE:varint>
547 64bits signed integer | 4 | INT64 : <4><VALUE:varint>
548 32bits unsigned integer | 5 | UNIT64 : <5><VALUE:varint>
549 IPV4 | 6 | IPV4 : <6><STRUCT IN_ADDR:4 bytes>
550 IPV6 | 7 | IPV6 : <7><STRUCT IN_ADDR6:16 bytes>
551 String | 8 | STRING : <8><LENGTH:varint><BYTES>
552 Binary | 9 | BINARY : <9><LENGTH:varint><BYTES>
553 10 -> 15 unused/reserved | - | -
554 -----------------------------+-----+----------------------------------
555
556Variable-length integer (varint) are encoded using Peers encoding:
557
558
559 0 <= X < 240 : 1 byte (7.875 bits) [ XXXX XXXX ]
560 240 <= X < 2288 : 2 bytes (11 bits) [ 1111 XXXX ] [ 0XXX XXXX ]
561 2288 <= X < 264432 : 3 bytes (18 bits) [ 1111 XXXX ] [ 1XXX XXXX ] [ 0XXX XXXX ]
562 264432 <= X < 33818864 : 4 bytes (25 bits) [ 1111 XXXX ] [ 1XXX XXXX ]*2 [ 0XXX XXXX ]
563 33818864 <= X < 4328786160 : 5 bytes (32 bits) [ 1111 XXXX ] [ 1XXX XXXX ]*3 [ 0XXX XXXX ]
564 ...
565
566For booleans, the value (true or false) is the first bit in the FLAGS
567bitfield. if this bit is set to 0, then the boolean is evaluated as false,
568otherwise, the boolean is evaluated as true.
569
5703.2. Frames
571------------
572
573Exchange between HAProxy and agents are made using FRAME packets. All frames
574must be prefixed with their size encoded on 4 bytes in network byte order:
575
576 <FRAME-LENGTH:4 bytes> <FRAME>
577
578A frame always starts with its type, on one byte, followed by metadata
579containing flags, on 4 bytes and a two variable-length integer representing the
580stream identifier and the frame identifier inside the stream:
581
582 FRAME : <FRAME-TYPE:1 byte> <METADATA> <FRAME-PAYLOAD>
583 METADATA : <FLAGS:4 bytes> <STREAM-ID:varint> <FRAME-ID:varint>
584
585Then comes the frame payload. Depending on the frame type, the payload can be
586of three types: a simple key/value list, a list of messages or a list of
587actions.
588
589 FRAME-PAYLOAD : <LIST-OF-MESSAGES> | <LIST-OF-ACTIONS> | <KV-LIST>
590
591 LIST-OF-MESSAGES : [ <MESSAGE-NAME> <NB-ARGS:1 byte> <KV-LIST> ... ]
592 MESSAGE-NAME : <STRING>
593
594 LIST-OF-ACTIONS : [ <ACTION-TYPE:1 byte> <NB-ARGS:1 byte> <ACTION-ARGS> ... ]
595 ACTION-ARGS : [ <TYPED-DATA>... ]
596
597 KV-LIST : [ <KV-NAME> <KV-VALUE> ... ]
598 KV-NAME : <STRING>
599 KV-VALUE : <TYPED-DATA>
600
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100601 FLAGS : 0 1 2-31
602 +---+---+----------+
603 | | A | |
604 | F | B | |
605 | I | O | RESERVED |
606 | N | R | |
607 | | T | |
608 +---+---+----------+
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200609
610 FIN: Indicates that this is the final payload fragment. The first fragment
611 may also be the final fragment.
612
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100613 ABORT: Indicates that the processing of the current frame must be
614 cancelled. This bit should be set on frames with a fragmented
615 payload. It can be ignore for frames with an unfragemnted
616 payload. When it is set, the FIN bit must also be set.
617
618
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200619Frames cannot exceed a maximum size negociated between HAProxy and agents
620during the HELLO handshake. Most of time, payload will be small enough to send
621it in one frame. But when supported by the peer, it will be possible to
622fragment huge payload on many frames. This ability is announced during the
623HELLO handshake and it can be asynmetric (supported by agents but not by
624HAProxy or the opposite). The following rules apply to fragmentation:
625
626 * An unfragemnted payload consists of a single frame with the FIN bit set.
627
628 * A fragemented payload consists of several frames with the FIN bit clear and
629 terminated by a single frame with the FIN bit set. All these frames must
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100630 share the same STREAM-ID and FRAME-ID. The first frame must set the right
631 FRAME-TYPE (e.g, NOTIFY). The following frames must have an unset type (0).
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200632
633Beside the support of fragmented payload by a peer, some payload must not be
634fragmented. See below for details.
635
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100636IMPORTANT : The maximum size supported by peers for a frame must be greater
637than or equal to 256 bytes.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200638
6393.2.1. Frame capabilities
640--------------------------
641
642Here are the list of official capabilities that HAProxy and agents can support:
643
Christopher Fauleta1cda022016-12-21 08:58:06 +0100644 * fragmentation: This is the ability for a peer to support fragmented
645 payload in received frames. This is an asymmectical
646 capability, it only concerns the peer that announces
647 it. This is the responsibility to the other peer to use it
648 or not.
649
650 * pipelining: This is the ability for a peer to decouple NOTIFY and ACK
651 frames. This is a symmectical capability. To be used, it must
652 be supported by HAproxy and agents. Unlike HTTP pipelining, the
653 ACK frames can be send in any order, but always on the same TCP
654 connection used for the corresponding NOTIFY frame.
655
656 * async: This ability is similar to the pipelining, but here any TCP
657 connection established between HAProxy and the agent can be used to
658 send ACK frames. if an agent accepts connections from multiple
659 HAProxy, it can use the "engine-id" value to group TCP
660 connections. See details about HAPROXY-HELLO frame.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200661
662Unsupported or unknown capabilities are silently ignored, when possible.
663
6643.2.2. Frame types overview
665----------------------------
666
667Here are types of frame supported by SPOE. Frames sent by HAProxy come first,
668then frames sent by agents :
669
670 TYPE | ID | DESCRIPTION
671 -----------------------------+-----+-------------------------------------
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100672 UNSET | 0 | Used for all frames but the first when a
673 | | payload is fragmented.
674 -----------------------------+-----+-------------------------------------
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200675 HAPROXY-HELLO | 1 | Sent by HAProxy when it opens a
676 | | connection on an agent.
677 | |
678 HAPROXY-DISCONNECT | 2 | Sent by HAProxy when it want to close
679 | | the connection or in reply to an
680 | | AGENT-DISCONNECT frame
681 | |
682 NOTIFY | 3 | Sent by HAProxy to pass information
683 | | to an agent
684 -----------------------------+-----+-------------------------------------
685 AGENT-HELLO | 101 | Reply to a HAPROXY-HELLO frame, when
686 | | the connection is established
687 | |
688 AGENT-DISCONNECT | 102 | Sent by an agent just before closing
689 | | the connection
690 | |
691 ACK | 103 | Sent to acknowledge a NOTIFY frame
692 -----------------------------+-----+-------------------------------------
693
694Unknown frames may be silently skipped.
695
6963.2.3. Workflow
697----------------
698
699 * Successful HELLO handshake:
700
701 HAPROXY AGENT SRV
702 | HAPROXY-HELLO |
Christopher Fauletba7bc162016-11-07 21:07:38 +0100703 | (healthcheck: false) |
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200704 | --------------------------> |
705 | |
706 | AGENT-HELLO |
707 | <-------------------------- |
708 | |
709
Christopher Fauletba7bc162016-11-07 21:07:38 +0100710 * Successful HELLO healthcheck:
711
712 HAPROXY AGENT SRV
713 | HAPROXY-HELLO |
714 | (healthcheck: true) |
715 | --------------------------> |
716 | |
717 | AGENT-HELLO + close() |
718 | <-------------------------- |
719 | |
720
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200721
722 * Error encountered by agent during the HELLO handshake:
723
724 HAPROXY AGENT SRV
725 | HAPROXY-HELLO |
726 | --------------------------> |
727 | |
728 | DISCONNECT + close() |
729 | <-------------------------- |
730 | |
731
732 * Error encountered by HAProxy during the HELLO handshake:
733
734 HAPROXY AGENT SRV
735 | HAPROXY-HELLO |
736 | --------------------------> |
737 | |
738 | AGENT-HELLO |
739 | <-------------------------- |
740 | |
741 | DISCONNECT |
742 | --------------------------> |
743 | |
744 | DISCONNECT + close() |
745 | <-------------------------- |
746 | |
747
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100748 * Notify / Ack exchange (unfragmented payload):
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200749
750 HAPROXY AGENT SRV
751 | NOTIFY |
752 | --------------------------> |
753 | |
754 | ACK |
755 | <-------------------------- |
756 | |
757
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100758 * Notify / Ack exchange (fragmented payload):
759
760 HAPROXY AGENT SRV
761 | NOTIFY (frag 1) |
762 | --------------------------> |
763 | |
764 | UNSET (frag 2) |
765 | --------------------------> |
766 | ... |
767 | UNSET (frag N) |
768 | --------------------------> |
769 | |
770 | ACK |
771 | <-------------------------- |
772 | |
773
774 * Aborted fragmentation of a NOTIFY frame:
775
776 HAPROXY AGENT SRV
777 | ... |
778 | UNSET (frag X) |
779 | --------------------------> |
780 | |
781 | ACK/ABORT |
782 | <-------------------------- |
783 | |
784 | UNSET (frag X+1) |
785 | -----------X |
786 | |
787 | |
788
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200789 * Connection closed by haproxy:
790
791 HAPROXY AGENT SRV
792 | DISCONNECT |
793 | --------------------------> |
794 | |
795 | DISCONNECT + close() |
796 | <-------------------------- |
797 | |
798
799 * Connection closed by agent:
800
801 HAPROXY AGENT SRV
802 | DISCONNECT + close() |
803 | <-------------------------- |
804 | |
805
8063.2.4. Frame: HAPROXY-HELLO
807----------------------------
808
809This frame is the first one exchanged between HAProxy and an agent, when the
810connection is established. The payload of this frame is a KV-LIST. It cannot be
811fragmented. STREAM-ID and FRAME-ID are must be set 0.
812
813Following items are mandatory in the KV-LIST:
814
815 * "supported-versions" <STRING>
816
817 Last SPOP major versions supported by HAProxy. It is a comma-separated list
818 of versions, following the format "Major.Minor". Spaces must be ignored, if
819 any. When a major version is announced by HAProxy, it means it also support
820 all previous minor versions.
821
822 Example: "2.0, 1.5" means HAProxy supports SPOP 2.0 and 1.0 to 1.5
823
824 * "max-frame-size" <UINT32>
825
826 This is the maximum size allowed for a frame. The HAPROXY-HELLO frame must
827 be lower or equal to this value.
828
829 * "capabilities" <STRING>
830
831 This a comma-separated list of capabilities supported by HAProxy. Spaces
832 must be ignored, if any.
833
Christopher Fauletba7bc162016-11-07 21:07:38 +0100834Following optional items can be added in the KV-LIST:
835
836 * "healthcheck" <BOOLEAN>
837
838 If this item is set to TRUE, then the HAPROXY-HELLO frame is sent during a
839 SPOE health check. When set to FALSE, this item can be ignored.
840
Christopher Fauleta1cda022016-12-21 08:58:06 +0100841 * "engine-id" <STRING>
842
843 This is a uniq string that identify a SPOE engine.
844
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200845To finish the HELLO handshake, the agent must return an AGENT-HELLO frame with
846its supported SPOP version, the lower value between its maximum size allowed
847for a frame and the HAProxy one and capabilities it supports. If an error
848occurs or if an incompatibility is detected with the agent configuration, an
849AGENT-DISCONNECT frame must be returned.
850
8513.2.5. Frame: AGENT-HELLO
852--------------------------
853
854This frame is sent in reply to a HAPROXY-HELLO frame to finish a HELLO
855handshake. As for HAPROXY-HELLO frame, STREAM-ID and FRAME-ID are also set
8560. The payload of this frame is a KV-LIST and it cannot be fragmented.
857
858Following items are mandatory in the KV-LIST:
859
860 * "version" <STRING>
861
862 This is the SPOP version the agent supports. It must follow the format
863 "Major.Minor" and it must be lower or equal than one of major versions
864 announced by HAProxy.
865
866 * "max-frame-size" <UINT32>
867
868 This is the maximum size allowed for a frame. It must be lower or equal to
869 the value in the HAPROXY-HELLO frame. This value will be used for all
870 subsequent frames.
871
872 * "capabilities" <STRING>
873
874 This a comma-separated list of capabilities supported by agent. Spaces must
875 be ignored, if any.
876
877At this time, if everything is ok for HAProxy (supported version and valid
878max-frame-size value), the HELLO handshake is successfully completed. Else,
879HAProxy sends a HAPROXY-DISCONNECT frame with the corresponding error.
880
Christopher Fauletba7bc162016-11-07 21:07:38 +0100881If "healthcheck" item was set to TRUE in the HAPROXY-HELLO frame, the agent can
882safely close the connection without DISCONNECT frame. In all cases, HAProxy
883will close the connexion at the end of the health check.
884
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02008853.2.6. Frame: NOTIFY
886---------------------
887
888Information are sent to the agents inside NOTIFY frames. These frames are
889attached to a stream, so STREAM-ID and FRAME-ID must be set. The payload of
890NOTIFY frames is a LIST-OF-MESSAGES and, if supported by agents, it can be
891fragmented.
892
893NOTIFY frames must be acknowledge by agents sending an ACK frame, repeating
894right STREAM-ID and FRAME-ID.
895
8963.2.7. Frame: ACK
897------------------
898
899ACK frames must be sent by agents to reply to NOTIFY frames. STREAM-ID and
900FRAME-ID found in a NOTIFY frame must be reuse in the corresponding ACK
901frame. The payload of ACK frames is a LIST-OF-ACTIONS and, if supported by
902HAProxy, it can be fragmented.
903
9043.2.8. Frame: HAPROXY-DISCONNECT
905---------------------------------
906
907If an error occurs, at anytime, from the HAProxy side, a HAPROXY-DISCONNECT
908frame is sent with information describing the error. HAProxy will wait an
909AGENT-DISCONNECT frame in reply. All other frames will be ignored. The agent
910must then close the socket.
911
912The payload of this frame is a KV-LIST. It cannot be fragmented. STREAM-ID and
913FRAME-ID are must be set 0.
914
915Following items are mandatory in the KV-LIST:
916
917 * "status-code" <UINT32>
918
919 This is the code corresponding to the error.
920
921 * "message" <STRING>
922
923 This is a textual message describing the error.
924
925For more information about known errors, see section "Errors & timeouts"
926
9273.2.9. Frame: AGENT-DISCONNECT
928-------------------------------
929
930If an error occurs, at anytime, from the agent size, a AGENT-DISCONNECT frame
931is sent, with information desribing the error. such frame is also sent in reply
932to a HAPROXY-DISCONNECT. The agent must close the socket just after sending
933this frame.
934
935The payload of this frame is a KV-LIST. It cannot be fragmented. STREAM-ID and
936FRAME-ID are must be set 0.
937
938Following items are mandatory in the KV-LIST:
939
940 * "status-code" <UINT32>
941
942 This is the code corresponding to the error.
943
944 * "message" <STRING>
945
946 This is a textual message describing the error.
947
948For more information about known errors, see section "Errors & timeouts"
949
9503.3. Events & Messages
951-----------------------
952
953Information about streams are sent in NOTIFY frames. You can specify which kind
954of information to send by defining "spoe-message" sections in your SPOE
955configuration file. for each "spoe-message" there will be a message in a NOTIFY
956frame when the right event is triggered.
957
958A NOTIFY frame is sent for an specific event when there is at least one
959"spoe-message" attached to this event. All messages for an event will be added
960in the same NOTIFY frame.
961
962Here is the list of supported events:
963
964 * on-client-session is triggered when a new client session is created.
965 This event is only available for SPOE filters
966 declared in a frontend or a listen section.
967
968 * on-frontend-tcp-request is triggered just before the evaluation of
969 "tcp-request content" rules on the frontend side.
970 This event is only available for SPOE filters
971 declared in a frontend or a listen section.
972
973 * on-backend-tcp-request is triggered just before the evaluation of
974 "tcp-request content" rules on the backend side.
975 This event is skipped for SPOE filters declared
976 in a listen section.
977
978 * on-frontend-http-request is triggered just before the evaluation of
979 "http-request" rules on the frontend side. This
980 event is only available for SPOE filters declared
981 in a frontend or a listen section.
982
983 * on-backend-http-request is triggered just before the evaluation of
984 "http-request" rules on the backend side. This
985 event is skipped for SPOE filters declared in a
986 listen section.
987
988 * on-server-session is triggered when the session with the server is
989 established.
990
991 * on-tcp-response is triggered just before the evaluation of
992 "tcp-response content" rules.
993
994 * on-http-response is triggered just before the evaluation of
995 "http-response" rules.
996
997
998The stream processing will loop on these events, when triggered, waiting the
999agent reply.
1000
10013.4. Actions
1002-------------
1003
1004An agent must acknowledge each NOTIFY frame by sending the corresponding ACK
1005frame. Actions can be added in these frames to dynamically take action on the
1006processing of a stream.
1007
1008Here is the list of supported actions:
1009
1010 * set-var set the value for an existing variable. 3 arguments must be
1011 attached to this action: the variable scope (proc, sess, txn,
1012 req or req), the variable name (a string) and its value.
1013
1014 ACTION-SET-VAR : <SET-VAR:1 byte><NB-ARGS:1 byte><VAR-SCOPE:1 byte><VAR-NAME><VAR-VALUE>
1015
1016 SET-VAR : <1>
1017 NB-ARGS : <3>
1018 VAR-SCOPE : <PROCESS> | <SESSION> | <TRANSACTION> | <REQUEST> | <RESPONSE>
1019 VAR-NAME : <STRING>
1020 VAR-VALUE : <TYPED-DATA>
1021
1022 PROCESS : <0>
1023 SESSION : <1>
1024 TRANSACTION : <2>
1025 REQUEST : <3>
Christopher Fauleta1cda022016-12-21 08:58:06 +01001026 RESPONSE : <4>
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02001027
1028 * unset-var unset the value for an existing variable. 2 arguments must be
1029 attached to this action: the variable scope (proc, sess, txn,
1030 req or req) and the variable name (a string).
1031
Christopher Faulet1002aac2016-12-09 17:41:54 +01001032 ACTION-UNSET-VAR : <UNSET-VAR:1 byte><NB-ARGS:1 byte><VAR-SCOPE:1 byte><VAR-NAME>
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02001033
Christopher Faulet1002aac2016-12-09 17:41:54 +01001034 UNSET-VAR : <2>
1035 NB-ARGS : <2>
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02001036 VAR-SCOPE : <PROCESS> | <SESSION> | <TRANSACTION> | <REQUEST> | <RESPONSE>
1037 VAR-NAME : <STRING>
1038
1039 PROCESS : <0>
1040 SESSION : <1>
1041 TRANSACTION : <2>
1042 REQUEST : <3>
Christopher Fauleta1cda022016-12-21 08:58:06 +01001043 RESPONSE : <4>
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02001044
1045
1046NOTE: Name of the variables will be automatically prefixed by HAProxy to avoid
1047 name clashes with other variables used in HAProxy. Moreover, unknown
1048 variable will be silently ignored.
1049
Christopher Fauletd1307ce2017-02-27 21:59:39 +010010503.5. Errors & timeouts
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02001051----------------------
1052
1053Here is the list of all known errors:
1054
1055 STATUS CODE | DESCRIPTION
1056 ----------------+--------------------------------------------------------
1057 0 | normal (no error occurred)
1058 1 | I/O error
1059 2 | A timeout occurred
1060 3 | frame is too big
1061 4 | invalid frame received
1062 5 | version value not found
1063 6 | max-frame-size value not found
1064 7 | capabilities value not found
1065 8 | unsupported version
1066 9 | max-frame-size too big or too small
Christopher Fauletd1307ce2017-02-27 21:59:39 +01001067 10 | payload fragmentation is not supported
1068 11 | invalid interlaced frames
1069 12 | frame-id not found (it does not match any referenced frame)
1070 13 | resource allocation error
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02001071 99 | an unknown error occurrde
1072 ----------------+--------------------------------------------------------
1073
1074An agent can define its own errors using a not yet assigned status code.
1075
Christopher Fauletea62c2a2016-11-14 10:54:21 +01001076IMPORTANT NOTE: By default, for a specific stream, when an abnormal/unexpected
1077 error occurs, the SPOE is disabled for all the transaction. So
1078 if you have several events configured, such error on an event
1079 will disabled all followings. For TCP streams, this will
1080 disable the SPOE for the whole session. For HTTP streams, this
1081 will disable it for the transaction (request and response).
1082 See 'option continue-on-error' to bypass this limitation.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02001083
1084To avoid a stream to wait infinitly, you must carefully choose the
1085acknowledgement timeout. In most of cases, it will be quiet low. But it depends
1086on the responsivness of your service.
1087
1088You must also choose idle timeout carefully. Because connection with your
1089service depends on the backend configuration used by the SPOA, it is important
1090to use a lower value for idle timeout than the server timeout. Else the
1091connection will be closed by HAProxy. The same is true for hello timeout. You
1092should choose a lower value than the connect timeout.
1093
1094
1095/*
1096 * Local variables:
1097 * fill-column: 79
1098 * End:
1099 */