blob: 194fa3dba90a96cbb13f98d4c47a4a8a38e52e99 [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
242
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100243option pipelining
244no option pipelining
245 Enable or disable the support of pipelined exchanges between HAProxy and
246 SPOA. By default, this option is enabled.
247
248
249option send-frag-payload
250no option send-frag-payload
251 Enable or disable the sending of fragmented payload to SPOA. By default, this
252 option is enabled.
253
254
Christopher Faulet985532d2016-11-16 15:36:19 +0100255option set-on-error <var name>
256 Define the variable to set when an error occurred during an event processing.
257
258 Arguments :
259
260 <var name> is the variable name, without the scope. The name may only
261 contain characters 'a-z', 'A-Z', '0-9', '.' and '_'.
262
263 This variable will only be set when an error occurred in the scope of the
264 transaction. As for all other variables define by the SPOE, it will be
265 prefixed. So, if your variable name is "error" and your prefix is
266 "my_spoe_pfx", the variable will be "txn.my_spoe_pfx.error".
267
Christopher Fauletb067b062017-01-04 16:39:11 +0100268 When set, the variable is an integer representing the error reason. For values
269 under 256, it represents an error coming from the engine. Below 256, it
270 reports a SPOP error. In this case, to retrieve the right SPOP status code,
271 you must remove 256 to this value. Here are possible values:
272
273 * 1 a timeout occurred during the event processing.
274
275 * 2 an error was triggered during the ressources allocation.
276
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100277 * 3 the frame payload exceeds the frame size and it cannot be
278 fragmented.
279
280 * 4 the fragmentation of a payload is aborted.
281
Christopher Faulet344c4ab2017-09-22 10:20:13 +0200282 * 5 The frame processing has been interrupted by HAProxy.
283
Christopher Fauletb067b062017-01-04 16:39:11 +0100284 * 255 an unknown error occurred during the event processing.
285
286 * 256+N a SPOP error occurred during the event processing (see section
287 "Errors & timeouts").
288
289 Note that if "option continue-on-error" is set, the variable is not
290 automatically removed between events processing.
Christopher Faulet985532d2016-11-16 15:36:19 +0100291
292 See also: "option continue-on-error", "option var-prefix".
293
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200294option var-prefix <prefix>
295 Define the prefix used when variables are set by an agent.
296
297 Arguments :
298
299 <prefix> is the prefix used to limit the scope of variables set by an
300 agent.
301
302 To avoid conflict with other variables defined by HAProxy, all variables
303 names will be prefixed. By default, the "spoe-agent" name is used. This
304 option can be used to customize it.
305
306 The prefix will be added between the variable scope and its name, separated
307 by a '.'. It may only contain characters 'a-z', 'A-Z', '0-9', '.' and '_', as
308 for variables name. In HAProxy configuration, you need to use this prefix as
309 a part of the variables name. For example, if an agent define the variable
310 "myvar" in the "txn" scope, with the prefix "my_spoe_pfx", then you should
311 use "txn.my_spoe_pfx.myvar" name in your HAProxy configuration.
312
313 An agent will never set new variables at runtime. It can only set new value
314 for existing ones.
315
316
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200317timeout hello <timeout>
318 Set the maximum time to wait for an agent to receive the AGENT-HELLO frame.
Christopher Fauletf7a30922016-11-10 15:04:51 +0100319 It is applied on the stream that handle the connection with the agent.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200320
321 Arguments :
322 <timeout> is the timeout value specified in milliseconds by default, but
323 can be in any other unit if the number is suffixed by the unit,
324 as explained at the top of this document.
325
326 This timeout is an applicative timeout. It differ from "timeout connect"
327 defined on backends.
328
329
330timeout idle <timeout>
Christopher Fauletf7a30922016-11-10 15:04:51 +0100331 Set the maximum time to wait for an agent to close an idle connection. It is
332 applied on the stream that handle the connection with the agent.
333
334 Arguments :
335 <timeout> is the timeout value specified in milliseconds by default, but
336 can be in any other unit if the number is suffixed by the unit,
337 as explained at the top of this document.
338
339
340timeout processing <timeout>
341 Set the maximum time to wait for a stream to process an event, i.e to acquire
342 a stream to talk with an agent, to encode all messages, to send the NOTIFY
343 frame, to receive the corrsponding acknowledgement and to process all
344 actions. It is applied on the stream that handle the client and the server
345 sessions.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200346
347 Arguments :
348 <timeout> is the timeout value specified in milliseconds by default, but
349 can be in any other unit if the number is suffixed by the unit,
350 as explained at the top of this document.
351
352
353use-backend <backend>
354 Specify the backend to use. It must be defined.
355
356 Arguments :
357 <backend> is the name of a valid "backend" section.
358
359
3602.3. "spoe-message" section
361----------------------------
362
363To offload the stream processing, SPOE will send messages with specific
364information at a specific moment in the stream life and will wait for
365corresponding replies to know what to do.
366
367
368spoe-message <name>
369 Create a new SPOE message with the name <name>.
370
371 Arguments :
372 <name> is the name of the SPOE message.
373
374 Here you define a message that can be referenced in a "spoe-agent"
375 section. Following keywords are supported :
Christopher Faulet57583e42017-09-04 15:41:09 +0200376 - acl
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200377 - args
378 - event
379
380 See also: "spoe-agent" section.
381
382
Christopher Faulet57583e42017-09-04 15:41:09 +0200383acl <aclname> <criterion> [flags] [operator] <value> ...
384
385 Declare or complete an access list.
386
387 See section 7 about ACL usage in the HAProxy Configuration Manual.
388
389
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200390args [name=]<sample> ...
391 Define arguments passed into the SPOE message.
392
393 Arguments :
394 <sample> is a sample expression.
395
396 When the message is processed, if a sample expression is not available, it is
397 set to NULL. Arguments are processed in their declaration order and added in
398 the message in that order. It is possible to declare named arguements.
399
400 For example:
401 args frontend=fe_id src dst
402
403
Christopher Faulet57583e42017-09-04 15:41:09 +0200404event <name> [ { if | unless } <condition> ]
405 Set the event that triggers sending of the message. It may optionally be
406 followed by an ACL-based condition, in which case it will only be evaluated
407 if the condition is true.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200408
Christopher Faulet57583e42017-09-04 15:41:09 +0200409 ACL-based conditions are executed in the context of the stream that handle
410 the client and the server connections.
411
412 Arguments :
413 <name> is the event name.
414 <condition> is a standard ACL-based condition.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200415
416 Supported events are:
417 - on-client-session
Christopher Faulet1002aac2016-12-09 17:41:54 +0100418 - on-server-session
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200419 - on-frontend-tcp-request
420 - on-backend-tcp-request
421 - on-tcp-response
422 - on-frontend-http-request
423 - on-backend-http-request
424 - on-http-response
425
Christopher Faulet57583e42017-09-04 15:41:09 +0200426 See section "Events & Messages" for more details about supported events.
427 See section 7 about ACL usage in the HAProxy Configuration Manual.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200428
Christopher Faulet11610f32017-09-21 10:23:10 +02004292.4. "spoe-group" section
430--------------------------
431
432This section can be used to declare a group of SPOE messages. Unlike messages
433referenced in a "spoe-agent" section, messages inside a group are not sent on a
434specific event. The sending must be triggered by TCP or HTTP rules, from the
435HAProxy configuration.
436
437
438spoe-group <name>
439 Create a new SPOE group with the name <name>.
440
441 Arguments :
442 <name> is the name of the SPOE group.
443
444 Here you define a group of SPOE messages that can be referenced in a
445 "spoe-agent" section. Following keywords are supported :
446 - messages
447
448 See also: "spoe-agent" and "spoe-message" sections.
449
450
451messages <msg-name> ...
452 Declare the list of SPOE messages belonging to the group.
453
454 Arguments :
455 <msg-name> is the name of a SPOE message.
456
457 Messages declared here must be found in the same engine scope, else an error
458 is triggered during the configuration parsing. Furthermore, a message belongs
459 at most to a group. You can have many "messages" lines.
460
461 See also: "spoe-message" section.
462
463
4642.5. Example
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200465-------------
466
467Here is a simple but complete example that sends client-ip address to a ip
468reputation service. This service can set the variable "ip_score" which is an
469integer between 0 and 100, indicating its reputation (100 means totally safe
470and 0 a blacklisted IP with no doubt).
471
472 ###
473 ### HAProxy configuration
474 frontend www
475 mode http
476 bind *:80
477
478 filter spoe engine ip-reputation config spoe-ip-reputation.conf
479
480 # Reject connection if the IP reputation is under 20
481 tcp-request content reject if { var(sess.iprep.ip_score) -m int lt 20 }
482
483 default_backend http-servers
484
485 backend http-servers
486 mode http
487 server http A.B.C.D:80
488
489 backend iprep-servers
490 mode tcp
491 balance roundrobin
492
493 timeout connect 5s # greater than hello timeout
494 timeout server 3m # greater than idle timeout
495
496 server iprep1 A1.B1.C1.D1:12345
497 server iprep2 A2.B2.C2.D2:12345
498
499 ####
500 ### spoe-ip-reputation.conf
501 [ip-reputation]
502
503 spoe-agent iprep-agent
504 messages get-ip-reputation
505
506 option var-prefix iprep
507
Christopher Faulet03a34492016-11-19 16:47:56 +0100508 timeout hello 2s
509 timeout idle 2m
510 timeout processing 10ms
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200511
512 use-backend iprep-servers
513
514 spoe-message get-ip-reputation
515 args ip=src
Christopher Faulet57583e42017-09-04 15:41:09 +0200516 event on-client-session if ! { src -f /etc/haproxy/whitelist.lst }
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200517
518
5193. SPOP specification
520----------------------
521
5223.1. Data types
523----------------
524
525Here is the bytewise representation of typed data:
526
527 TYPED-DATA : <TYPE:4 bits><FLAGS:4 bits><DATA>
528
529Supported types and their representation are:
530
531 TYPE | ID | DESCRIPTION
532 -----------------------------+-----+----------------------------------
533 NULL | 0 | NULL : <0>
534 Boolean | 1 | BOOL : <1+FLAG>
535 32bits signed integer | 2 | INT32 : <2><VALUE:varint>
536 32bits unsigned integer | 3 | UINT32 : <3><VALUE:varint>
537 64bits signed integer | 4 | INT64 : <4><VALUE:varint>
538 32bits unsigned integer | 5 | UNIT64 : <5><VALUE:varint>
539 IPV4 | 6 | IPV4 : <6><STRUCT IN_ADDR:4 bytes>
540 IPV6 | 7 | IPV6 : <7><STRUCT IN_ADDR6:16 bytes>
541 String | 8 | STRING : <8><LENGTH:varint><BYTES>
542 Binary | 9 | BINARY : <9><LENGTH:varint><BYTES>
543 10 -> 15 unused/reserved | - | -
544 -----------------------------+-----+----------------------------------
545
546Variable-length integer (varint) are encoded using Peers encoding:
547
548
549 0 <= X < 240 : 1 byte (7.875 bits) [ XXXX XXXX ]
550 240 <= X < 2288 : 2 bytes (11 bits) [ 1111 XXXX ] [ 0XXX XXXX ]
551 2288 <= X < 264432 : 3 bytes (18 bits) [ 1111 XXXX ] [ 1XXX XXXX ] [ 0XXX XXXX ]
552 264432 <= X < 33818864 : 4 bytes (25 bits) [ 1111 XXXX ] [ 1XXX XXXX ]*2 [ 0XXX XXXX ]
553 33818864 <= X < 4328786160 : 5 bytes (32 bits) [ 1111 XXXX ] [ 1XXX XXXX ]*3 [ 0XXX XXXX ]
554 ...
555
556For booleans, the value (true or false) is the first bit in the FLAGS
557bitfield. if this bit is set to 0, then the boolean is evaluated as false,
558otherwise, the boolean is evaluated as true.
559
5603.2. Frames
561------------
562
563Exchange between HAProxy and agents are made using FRAME packets. All frames
564must be prefixed with their size encoded on 4 bytes in network byte order:
565
566 <FRAME-LENGTH:4 bytes> <FRAME>
567
568A frame always starts with its type, on one byte, followed by metadata
569containing flags, on 4 bytes and a two variable-length integer representing the
570stream identifier and the frame identifier inside the stream:
571
572 FRAME : <FRAME-TYPE:1 byte> <METADATA> <FRAME-PAYLOAD>
573 METADATA : <FLAGS:4 bytes> <STREAM-ID:varint> <FRAME-ID:varint>
574
575Then comes the frame payload. Depending on the frame type, the payload can be
576of three types: a simple key/value list, a list of messages or a list of
577actions.
578
579 FRAME-PAYLOAD : <LIST-OF-MESSAGES> | <LIST-OF-ACTIONS> | <KV-LIST>
580
581 LIST-OF-MESSAGES : [ <MESSAGE-NAME> <NB-ARGS:1 byte> <KV-LIST> ... ]
582 MESSAGE-NAME : <STRING>
583
584 LIST-OF-ACTIONS : [ <ACTION-TYPE:1 byte> <NB-ARGS:1 byte> <ACTION-ARGS> ... ]
585 ACTION-ARGS : [ <TYPED-DATA>... ]
586
587 KV-LIST : [ <KV-NAME> <KV-VALUE> ... ]
588 KV-NAME : <STRING>
589 KV-VALUE : <TYPED-DATA>
590
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100591 FLAGS : 0 1 2-31
592 +---+---+----------+
593 | | A | |
594 | F | B | |
595 | I | O | RESERVED |
596 | N | R | |
597 | | T | |
598 +---+---+----------+
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200599
600 FIN: Indicates that this is the final payload fragment. The first fragment
601 may also be the final fragment.
602
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100603 ABORT: Indicates that the processing of the current frame must be
604 cancelled. This bit should be set on frames with a fragmented
605 payload. It can be ignore for frames with an unfragemnted
606 payload. When it is set, the FIN bit must also be set.
607
608
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200609Frames cannot exceed a maximum size negociated between HAProxy and agents
610during the HELLO handshake. Most of time, payload will be small enough to send
611it in one frame. But when supported by the peer, it will be possible to
612fragment huge payload on many frames. This ability is announced during the
613HELLO handshake and it can be asynmetric (supported by agents but not by
614HAProxy or the opposite). The following rules apply to fragmentation:
615
616 * An unfragemnted payload consists of a single frame with the FIN bit set.
617
618 * A fragemented payload consists of several frames with the FIN bit clear and
619 terminated by a single frame with the FIN bit set. All these frames must
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100620 share the same STREAM-ID and FRAME-ID. The first frame must set the right
621 FRAME-TYPE (e.g, NOTIFY). The following frames must have an unset type (0).
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200622
623Beside the support of fragmented payload by a peer, some payload must not be
624fragmented. See below for details.
625
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100626IMPORTANT : The maximum size supported by peers for a frame must be greater
627than or equal to 256 bytes.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200628
6293.2.1. Frame capabilities
630--------------------------
631
632Here are the list of official capabilities that HAProxy and agents can support:
633
Christopher Fauleta1cda022016-12-21 08:58:06 +0100634 * fragmentation: This is the ability for a peer to support fragmented
635 payload in received frames. This is an asymmectical
636 capability, it only concerns the peer that announces
637 it. This is the responsibility to the other peer to use it
638 or not.
639
640 * pipelining: This is the ability for a peer to decouple NOTIFY and ACK
641 frames. This is a symmectical capability. To be used, it must
642 be supported by HAproxy and agents. Unlike HTTP pipelining, the
643 ACK frames can be send in any order, but always on the same TCP
644 connection used for the corresponding NOTIFY frame.
645
646 * async: This ability is similar to the pipelining, but here any TCP
647 connection established between HAProxy and the agent can be used to
648 send ACK frames. if an agent accepts connections from multiple
649 HAProxy, it can use the "engine-id" value to group TCP
650 connections. See details about HAPROXY-HELLO frame.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200651
652Unsupported or unknown capabilities are silently ignored, when possible.
653
6543.2.2. Frame types overview
655----------------------------
656
657Here are types of frame supported by SPOE. Frames sent by HAProxy come first,
658then frames sent by agents :
659
660 TYPE | ID | DESCRIPTION
661 -----------------------------+-----+-------------------------------------
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100662 UNSET | 0 | Used for all frames but the first when a
663 | | payload is fragmented.
664 -----------------------------+-----+-------------------------------------
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200665 HAPROXY-HELLO | 1 | Sent by HAProxy when it opens a
666 | | connection on an agent.
667 | |
668 HAPROXY-DISCONNECT | 2 | Sent by HAProxy when it want to close
669 | | the connection or in reply to an
670 | | AGENT-DISCONNECT frame
671 | |
672 NOTIFY | 3 | Sent by HAProxy to pass information
673 | | to an agent
674 -----------------------------+-----+-------------------------------------
675 AGENT-HELLO | 101 | Reply to a HAPROXY-HELLO frame, when
676 | | the connection is established
677 | |
678 AGENT-DISCONNECT | 102 | Sent by an agent just before closing
679 | | the connection
680 | |
681 ACK | 103 | Sent to acknowledge a NOTIFY frame
682 -----------------------------+-----+-------------------------------------
683
684Unknown frames may be silently skipped.
685
6863.2.3. Workflow
687----------------
688
689 * Successful HELLO handshake:
690
691 HAPROXY AGENT SRV
692 | HAPROXY-HELLO |
Christopher Fauletba7bc162016-11-07 21:07:38 +0100693 | (healthcheck: false) |
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200694 | --------------------------> |
695 | |
696 | AGENT-HELLO |
697 | <-------------------------- |
698 | |
699
Christopher Fauletba7bc162016-11-07 21:07:38 +0100700 * Successful HELLO healthcheck:
701
702 HAPROXY AGENT SRV
703 | HAPROXY-HELLO |
704 | (healthcheck: true) |
705 | --------------------------> |
706 | |
707 | AGENT-HELLO + close() |
708 | <-------------------------- |
709 | |
710
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200711
712 * Error encountered by agent during the HELLO handshake:
713
714 HAPROXY AGENT SRV
715 | HAPROXY-HELLO |
716 | --------------------------> |
717 | |
718 | DISCONNECT + close() |
719 | <-------------------------- |
720 | |
721
722 * Error encountered by HAProxy during the HELLO handshake:
723
724 HAPROXY AGENT SRV
725 | HAPROXY-HELLO |
726 | --------------------------> |
727 | |
728 | AGENT-HELLO |
729 | <-------------------------- |
730 | |
731 | DISCONNECT |
732 | --------------------------> |
733 | |
734 | DISCONNECT + close() |
735 | <-------------------------- |
736 | |
737
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100738 * Notify / Ack exchange (unfragmented payload):
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200739
740 HAPROXY AGENT SRV
741 | NOTIFY |
742 | --------------------------> |
743 | |
744 | ACK |
745 | <-------------------------- |
746 | |
747
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100748 * Notify / Ack exchange (fragmented payload):
749
750 HAPROXY AGENT SRV
751 | NOTIFY (frag 1) |
752 | --------------------------> |
753 | |
754 | UNSET (frag 2) |
755 | --------------------------> |
756 | ... |
757 | UNSET (frag N) |
758 | --------------------------> |
759 | |
760 | ACK |
761 | <-------------------------- |
762 | |
763
764 * Aborted fragmentation of a NOTIFY frame:
765
766 HAPROXY AGENT SRV
767 | ... |
768 | UNSET (frag X) |
769 | --------------------------> |
770 | |
771 | ACK/ABORT |
772 | <-------------------------- |
773 | |
774 | UNSET (frag X+1) |
775 | -----------X |
776 | |
777 | |
778
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200779 * Connection closed by haproxy:
780
781 HAPROXY AGENT SRV
782 | DISCONNECT |
783 | --------------------------> |
784 | |
785 | DISCONNECT + close() |
786 | <-------------------------- |
787 | |
788
789 * Connection closed by agent:
790
791 HAPROXY AGENT SRV
792 | DISCONNECT + close() |
793 | <-------------------------- |
794 | |
795
7963.2.4. Frame: HAPROXY-HELLO
797----------------------------
798
799This frame is the first one exchanged between HAProxy and an agent, when the
800connection is established. The payload of this frame is a KV-LIST. It cannot be
801fragmented. STREAM-ID and FRAME-ID are must be set 0.
802
803Following items are mandatory in the KV-LIST:
804
805 * "supported-versions" <STRING>
806
807 Last SPOP major versions supported by HAProxy. It is a comma-separated list
808 of versions, following the format "Major.Minor". Spaces must be ignored, if
809 any. When a major version is announced by HAProxy, it means it also support
810 all previous minor versions.
811
812 Example: "2.0, 1.5" means HAProxy supports SPOP 2.0 and 1.0 to 1.5
813
814 * "max-frame-size" <UINT32>
815
816 This is the maximum size allowed for a frame. The HAPROXY-HELLO frame must
817 be lower or equal to this value.
818
819 * "capabilities" <STRING>
820
821 This a comma-separated list of capabilities supported by HAProxy. Spaces
822 must be ignored, if any.
823
Christopher Fauletba7bc162016-11-07 21:07:38 +0100824Following optional items can be added in the KV-LIST:
825
826 * "healthcheck" <BOOLEAN>
827
828 If this item is set to TRUE, then the HAPROXY-HELLO frame is sent during a
829 SPOE health check. When set to FALSE, this item can be ignored.
830
Christopher Fauleta1cda022016-12-21 08:58:06 +0100831 * "engine-id" <STRING>
832
833 This is a uniq string that identify a SPOE engine.
834
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200835To finish the HELLO handshake, the agent must return an AGENT-HELLO frame with
836its supported SPOP version, the lower value between its maximum size allowed
837for a frame and the HAProxy one and capabilities it supports. If an error
838occurs or if an incompatibility is detected with the agent configuration, an
839AGENT-DISCONNECT frame must be returned.
840
8413.2.5. Frame: AGENT-HELLO
842--------------------------
843
844This frame is sent in reply to a HAPROXY-HELLO frame to finish a HELLO
845handshake. As for HAPROXY-HELLO frame, STREAM-ID and FRAME-ID are also set
8460. The payload of this frame is a KV-LIST and it cannot be fragmented.
847
848Following items are mandatory in the KV-LIST:
849
850 * "version" <STRING>
851
852 This is the SPOP version the agent supports. It must follow the format
853 "Major.Minor" and it must be lower or equal than one of major versions
854 announced by HAProxy.
855
856 * "max-frame-size" <UINT32>
857
858 This is the maximum size allowed for a frame. It must be lower or equal to
859 the value in the HAPROXY-HELLO frame. This value will be used for all
860 subsequent frames.
861
862 * "capabilities" <STRING>
863
864 This a comma-separated list of capabilities supported by agent. Spaces must
865 be ignored, if any.
866
867At this time, if everything is ok for HAProxy (supported version and valid
868max-frame-size value), the HELLO handshake is successfully completed. Else,
869HAProxy sends a HAPROXY-DISCONNECT frame with the corresponding error.
870
Christopher Fauletba7bc162016-11-07 21:07:38 +0100871If "healthcheck" item was set to TRUE in the HAPROXY-HELLO frame, the agent can
872safely close the connection without DISCONNECT frame. In all cases, HAProxy
873will close the connexion at the end of the health check.
874
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02008753.2.6. Frame: NOTIFY
876---------------------
877
878Information are sent to the agents inside NOTIFY frames. These frames are
879attached to a stream, so STREAM-ID and FRAME-ID must be set. The payload of
880NOTIFY frames is a LIST-OF-MESSAGES and, if supported by agents, it can be
881fragmented.
882
883NOTIFY frames must be acknowledge by agents sending an ACK frame, repeating
884right STREAM-ID and FRAME-ID.
885
8863.2.7. Frame: ACK
887------------------
888
889ACK frames must be sent by agents to reply to NOTIFY frames. STREAM-ID and
890FRAME-ID found in a NOTIFY frame must be reuse in the corresponding ACK
891frame. The payload of ACK frames is a LIST-OF-ACTIONS and, if supported by
892HAProxy, it can be fragmented.
893
8943.2.8. Frame: HAPROXY-DISCONNECT
895---------------------------------
896
897If an error occurs, at anytime, from the HAProxy side, a HAPROXY-DISCONNECT
898frame is sent with information describing the error. HAProxy will wait an
899AGENT-DISCONNECT frame in reply. All other frames will be ignored. The agent
900must then close the socket.
901
902The payload of this frame is a KV-LIST. It cannot be fragmented. STREAM-ID and
903FRAME-ID are must be set 0.
904
905Following items are mandatory in the KV-LIST:
906
907 * "status-code" <UINT32>
908
909 This is the code corresponding to the error.
910
911 * "message" <STRING>
912
913 This is a textual message describing the error.
914
915For more information about known errors, see section "Errors & timeouts"
916
9173.2.9. Frame: AGENT-DISCONNECT
918-------------------------------
919
920If an error occurs, at anytime, from the agent size, a AGENT-DISCONNECT frame
921is sent, with information desribing the error. such frame is also sent in reply
922to a HAPROXY-DISCONNECT. The agent must close the socket just after sending
923this frame.
924
925The payload of this frame is a KV-LIST. It cannot be fragmented. STREAM-ID and
926FRAME-ID are must be set 0.
927
928Following items are mandatory in the KV-LIST:
929
930 * "status-code" <UINT32>
931
932 This is the code corresponding to the error.
933
934 * "message" <STRING>
935
936 This is a textual message describing the error.
937
938For more information about known errors, see section "Errors & timeouts"
939
9403.3. Events & Messages
941-----------------------
942
943Information about streams are sent in NOTIFY frames. You can specify which kind
944of information to send by defining "spoe-message" sections in your SPOE
945configuration file. for each "spoe-message" there will be a message in a NOTIFY
946frame when the right event is triggered.
947
948A NOTIFY frame is sent for an specific event when there is at least one
949"spoe-message" attached to this event. All messages for an event will be added
950in the same NOTIFY frame.
951
952Here is the list of supported events:
953
954 * on-client-session is triggered when a new client session is created.
955 This event is only available for SPOE filters
956 declared in a frontend or a listen section.
957
958 * on-frontend-tcp-request is triggered just before the evaluation of
959 "tcp-request content" rules on the frontend side.
960 This event is only available for SPOE filters
961 declared in a frontend or a listen section.
962
963 * on-backend-tcp-request is triggered just before the evaluation of
964 "tcp-request content" rules on the backend side.
965 This event is skipped for SPOE filters declared
966 in a listen section.
967
968 * on-frontend-http-request is triggered just before the evaluation of
969 "http-request" rules on the frontend side. This
970 event is only available for SPOE filters declared
971 in a frontend or a listen section.
972
973 * on-backend-http-request is triggered just before the evaluation of
974 "http-request" rules on the backend side. This
975 event is skipped for SPOE filters declared in a
976 listen section.
977
978 * on-server-session is triggered when the session with the server is
979 established.
980
981 * on-tcp-response is triggered just before the evaluation of
982 "tcp-response content" rules.
983
984 * on-http-response is triggered just before the evaluation of
985 "http-response" rules.
986
987
988The stream processing will loop on these events, when triggered, waiting the
989agent reply.
990
9913.4. Actions
992-------------
993
994An agent must acknowledge each NOTIFY frame by sending the corresponding ACK
995frame. Actions can be added in these frames to dynamically take action on the
996processing of a stream.
997
998Here is the list of supported actions:
999
1000 * set-var set the value for an existing variable. 3 arguments must be
1001 attached to this action: the variable scope (proc, sess, txn,
1002 req or req), the variable name (a string) and its value.
1003
1004 ACTION-SET-VAR : <SET-VAR:1 byte><NB-ARGS:1 byte><VAR-SCOPE:1 byte><VAR-NAME><VAR-VALUE>
1005
1006 SET-VAR : <1>
1007 NB-ARGS : <3>
1008 VAR-SCOPE : <PROCESS> | <SESSION> | <TRANSACTION> | <REQUEST> | <RESPONSE>
1009 VAR-NAME : <STRING>
1010 VAR-VALUE : <TYPED-DATA>
1011
1012 PROCESS : <0>
1013 SESSION : <1>
1014 TRANSACTION : <2>
1015 REQUEST : <3>
Christopher Fauleta1cda022016-12-21 08:58:06 +01001016 RESPONSE : <4>
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02001017
1018 * unset-var unset the value for an existing variable. 2 arguments must be
1019 attached to this action: the variable scope (proc, sess, txn,
1020 req or req) and the variable name (a string).
1021
Christopher Faulet1002aac2016-12-09 17:41:54 +01001022 ACTION-UNSET-VAR : <UNSET-VAR:1 byte><NB-ARGS:1 byte><VAR-SCOPE:1 byte><VAR-NAME>
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02001023
Christopher Faulet1002aac2016-12-09 17:41:54 +01001024 UNSET-VAR : <2>
1025 NB-ARGS : <2>
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02001026 VAR-SCOPE : <PROCESS> | <SESSION> | <TRANSACTION> | <REQUEST> | <RESPONSE>
1027 VAR-NAME : <STRING>
1028
1029 PROCESS : <0>
1030 SESSION : <1>
1031 TRANSACTION : <2>
1032 REQUEST : <3>
Christopher Fauleta1cda022016-12-21 08:58:06 +01001033 RESPONSE : <4>
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02001034
1035
1036NOTE: Name of the variables will be automatically prefixed by HAProxy to avoid
1037 name clashes with other variables used in HAProxy. Moreover, unknown
1038 variable will be silently ignored.
1039
Christopher Fauletd1307ce2017-02-27 21:59:39 +010010403.5. Errors & timeouts
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02001041----------------------
1042
1043Here is the list of all known errors:
1044
1045 STATUS CODE | DESCRIPTION
1046 ----------------+--------------------------------------------------------
1047 0 | normal (no error occurred)
1048 1 | I/O error
1049 2 | A timeout occurred
1050 3 | frame is too big
1051 4 | invalid frame received
1052 5 | version value not found
1053 6 | max-frame-size value not found
1054 7 | capabilities value not found
1055 8 | unsupported version
1056 9 | max-frame-size too big or too small
Christopher Fauletd1307ce2017-02-27 21:59:39 +01001057 10 | payload fragmentation is not supported
1058 11 | invalid interlaced frames
1059 12 | frame-id not found (it does not match any referenced frame)
1060 13 | resource allocation error
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02001061 99 | an unknown error occurrde
1062 ----------------+--------------------------------------------------------
1063
1064An agent can define its own errors using a not yet assigned status code.
1065
Christopher Fauletea62c2a2016-11-14 10:54:21 +01001066IMPORTANT NOTE: By default, for a specific stream, when an abnormal/unexpected
1067 error occurs, the SPOE is disabled for all the transaction. So
1068 if you have several events configured, such error on an event
1069 will disabled all followings. For TCP streams, this will
1070 disable the SPOE for the whole session. For HTTP streams, this
1071 will disable it for the transaction (request and response).
1072 See 'option continue-on-error' to bypass this limitation.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02001073
1074To avoid a stream to wait infinitly, you must carefully choose the
1075acknowledgement timeout. In most of cases, it will be quiet low. But it depends
1076on the responsivness of your service.
1077
1078You must also choose idle timeout carefully. Because connection with your
1079service depends on the backend configuration used by the SPOA, it is important
1080to use a lower value for idle timeout than the server timeout. Else the
1081connection will be closed by HAProxy. The same is true for hello timeout. You
1082should choose a lower value than the connect timeout.
1083
1084
1085/*
1086 * Local variables:
1087 * fill-column: 79
1088 * End:
1089 */