blob: 48cfa021f7e18c4685bfa9e2703c01032daee378 [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
19 2.4. Example
20 3. SPOP specification
21 3.1. Data types
22 3.2. Frames
23 3.2.1. Frame capabilities
24 3.2.2. Frame types overview
25 3.2.3. Workflow
26 3.2.4. Frame: HAPROXY-HELLO
27 3.2.5. Frame: AGENT-HELLO
28 3.2.6. Frame: NOTIFY
29 3.2.7. Frame: ACK
30 3.2.8. Frame: HAPROXY-DISCONNECT
31 3.2.9. Frame: AGENT-DISCONNECT
32 3.3. Events & messages
33 3.4. Actions
Christopher Fauletd1307ce2017-02-27 21:59:39 +010034 3.5. Errors & timeouts
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +020035
36
370. Terms
38---------
39
40* SPOE : Stream Processing Offload Engine.
41
42 A SPOE is a filter talking to servers managed ba a SPOA to offload the
43 stream processing. An engine is attached to a proxy. A proxy can have
Christopher Fauletd1307ce2017-02-27 21:59:39 +010044 several engines. Each engine is linked to an agent and only one.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +020045
46* SPOA : Stream Processing Offload Agent.
47
48 A SPOA is a service that will receive info from a SPOE to offload the
49 stream processing. An agent manages several servers. It uses a backend to
50 reference all of them. By extension, these servers can also be called
51 agents.
52
53* SPOP : Stream Processing Offload Protocol, used by SPOEs to talk to SPOA
54 servers.
55
56 This protocol is used by engines to talk to agents. It is an in-house
57 binary protocol described in this documentation.
58
59
601. Introduction
61----------------
62
63SPOE is a feature introduced in HAProxy 1.7. It makes possible the
64communication with external components to retrieve some info. The idea started
65with the problems caused by most ldap libs not working fine in event-driven
66systems (often at least the connect() is blocking). So, it is hard to properly
67implement Single Sign On solution (SSO) in HAProxy. The SPOE will ease this
68kind of processing, or we hope so.
69
70Now, the aim of SPOE is to allow any kind of offloading on the streams. First
71releases, besides being experimental, won't do lot of things. As we will see,
72there are few handled events and even less actions supported. Actually, for
73now, the SPOE can offload the processing before "tcp-request content",
74"tcp-response content", "http-request" and "http-response" rules. And it only
75supports variables definition. But, in spite of these limited features, we can
76easily imagine to implement SSO solution, ip reputation or ip geolocation
77services.
78
79
802. SPOE configuration
81----------------------
82
83Because SPOE is implemented as a filter, To use it, you must declare a "filter
84spoe" line in a proxy section (frontend/backend/listen) :
85
86 frontend my-front
87 ...
88 filter spoe [engine <name>] config <file>
89 ...
90
91The "config" parameter is mandatory. It specififies the SPOE configuration
92file. The engine name is optional. It can be set to declare the scope to use in
93the SPOE configuration. So it is possible to use the same SPOE configuration
94for several engines. If no name is provided, the SPOE configuration must not
95contain any scope directive.
96
97We use a separate configuration file on purpose. By commenting SPOE filter
98line, you completly disable the feature, including the parsing of sections
99reserved to SPOE. This is also a way to keep the HAProxy configuration clean.
100
101A SPOE configuration file must contains, at least, the SPOA configuration
102("spoe-agent" section) and SPOE messages ("spoe-message" section) attached to
103this agent. Unused messages (not reference in "spoe-agent" section) will be
104ignored.
105
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 Fauletd1307ce2017-02-27 21:59:39 +0100117"spoe-message" sections to describe messages sent to servers mananged by your
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200118SPOA.
119
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 ...
135
136 [my-second-engine]
137 ...
138
139If no engine name is provided on the SPOE filter line, no SPOE scope must be
140found in the SPOE configuration file. All the file is considered to be in the
141same anonymous and implicit scope.
142
Christopher Faulet7ee86672017-09-19 11:08:28 +0200143The engine name must be uniq for a proxy. If no engine name is provided on the
144SPOE filter line, the SPOE agent name is unsed by default.
145
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02001462.2. "spoe-agent" section
147--------------------------
148
149For each engine, you must define one and only one "spoe-agent" section. In this
150section, you will declare SPOE messages and the backend you will use. You will
151also set timeouts and options to customize your agent's behaviour.
152
153
154spoe-agent <name>
155 Create a new SPOA with the name <name>. It must have one and only one
156 "spoe-agent" definition by SPOE scope.
157
158 Arguments :
159 <name> is the name of the agent section.
160
161 following keywords are supported :
Christopher Faulet48026722016-11-16 15:01:12 +0100162 - maxconnrate
163 - maxerrrate
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100164 - max-frame-size
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200165 - messages
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100166 - [no] option async
167 - [no] option pipelining
168 - [no] option send-frag-payload
Christopher Fauletea62c2a2016-11-14 10:54:21 +0100169 - option continue-on-error
Christopher Faulet985532d2016-11-16 15:36:19 +0100170 - option set-on-error
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200171 - option var-prefix
Christopher Faulet03a34492016-11-19 16:47:56 +0100172 - timeout hello|idle|processing
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200173 - use-backend
174
175
Christopher Faulet48026722016-11-16 15:01:12 +0100176maxconnrate <number>
177 Set the maximum number of connections per second to <number>. The SPOE will
178 stop to open new connections if the maximum is reached and will wait to
179 acquire an existing one. So it is important to set "timeout hello" to a
180 relatively small value.
181
182
183maxerrrate <number>
184 Set the maximum number of errors per second to <number>. The SPOE will stop
185 its processing if the maximum is reached.
186
187
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100188max-frame-size <number>
189 Set the maximum allowed size for frames exchanged between HAProxy and SPOA.
190 It must be in the range [256, tune.bufsize-4] (4 bytes are reserved for the
191 frame length). By default, it is set to (tune.bufsize-4).
192
193
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200194messages <msg-name> ...
195 Declare the list of SPOE messages that an agent will handle.
196
197 Arguments :
198 <msg-name> is the name of a SPOE message.
199
200 Messages declared here must be found in the same engine scope, else an error
201 is triggered during the configuration parsing. You can have many "messages"
202 lines.
203
204 See also: "spoe-message" section.
205
206
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100207option async
208no option async
209 Enable or disable the support of asynchronus exchanges between HAProxy and
210 SPOA. By default, this option is enabled.
211
212
Christopher Fauletea62c2a2016-11-14 10:54:21 +0100213option continue-on-error
214 Do not stop the events processing when an error occurred on a stream.
215
216 By default, for a specific stream, when an abnormal/unexpected error occurs,
217 the SPOE is disabled for all the transaction. So if you have several events
218 configured, such error on an event will disabled all followings. For TCP
219 streams, this will disable the SPOE for the whole session. For HTTP streams,
220 this will disable it for the transaction (request and response).
221
222 When set, this option bypass this behaviour and only the current event will
223 be ignored.
224
225
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100226option pipelining
227no option pipelining
228 Enable or disable the support of pipelined exchanges between HAProxy and
229 SPOA. By default, this option is enabled.
230
231
232option send-frag-payload
233no option send-frag-payload
234 Enable or disable the sending of fragmented payload to SPOA. By default, this
235 option is enabled.
236
237
Christopher Faulet985532d2016-11-16 15:36:19 +0100238option set-on-error <var name>
239 Define the variable to set when an error occurred during an event processing.
240
241 Arguments :
242
243 <var name> is the variable name, without the scope. The name may only
244 contain characters 'a-z', 'A-Z', '0-9', '.' and '_'.
245
246 This variable will only be set when an error occurred in the scope of the
247 transaction. As for all other variables define by the SPOE, it will be
248 prefixed. So, if your variable name is "error" and your prefix is
249 "my_spoe_pfx", the variable will be "txn.my_spoe_pfx.error".
250
Christopher Fauletb067b062017-01-04 16:39:11 +0100251 When set, the variable is an integer representing the error reason. For values
252 under 256, it represents an error coming from the engine. Below 256, it
253 reports a SPOP error. In this case, to retrieve the right SPOP status code,
254 you must remove 256 to this value. Here are possible values:
255
256 * 1 a timeout occurred during the event processing.
257
258 * 2 an error was triggered during the ressources allocation.
259
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100260 * 3 the frame payload exceeds the frame size and it cannot be
261 fragmented.
262
263 * 4 the fragmentation of a payload is aborted.
264
Christopher Fauletb067b062017-01-04 16:39:11 +0100265 * 255 an unknown error occurred during the event processing.
266
267 * 256+N a SPOP error occurred during the event processing (see section
268 "Errors & timeouts").
269
270 Note that if "option continue-on-error" is set, the variable is not
271 automatically removed between events processing.
Christopher Faulet985532d2016-11-16 15:36:19 +0100272
273 See also: "option continue-on-error", "option var-prefix".
274
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200275option var-prefix <prefix>
276 Define the prefix used when variables are set by an agent.
277
278 Arguments :
279
280 <prefix> is the prefix used to limit the scope of variables set by an
281 agent.
282
283 To avoid conflict with other variables defined by HAProxy, all variables
284 names will be prefixed. By default, the "spoe-agent" name is used. This
285 option can be used to customize it.
286
287 The prefix will be added between the variable scope and its name, separated
288 by a '.'. It may only contain characters 'a-z', 'A-Z', '0-9', '.' and '_', as
289 for variables name. In HAProxy configuration, you need to use this prefix as
290 a part of the variables name. For example, if an agent define the variable
291 "myvar" in the "txn" scope, with the prefix "my_spoe_pfx", then you should
292 use "txn.my_spoe_pfx.myvar" name in your HAProxy configuration.
293
294 An agent will never set new variables at runtime. It can only set new value
295 for existing ones.
296
297
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200298timeout hello <timeout>
299 Set the maximum time to wait for an agent to receive the AGENT-HELLO frame.
Christopher Fauletf7a30922016-11-10 15:04:51 +0100300 It is applied on the stream that handle the connection with the agent.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200301
302 Arguments :
303 <timeout> is the timeout value specified in milliseconds by default, but
304 can be in any other unit if the number is suffixed by the unit,
305 as explained at the top of this document.
306
307 This timeout is an applicative timeout. It differ from "timeout connect"
308 defined on backends.
309
310
311timeout idle <timeout>
Christopher Fauletf7a30922016-11-10 15:04:51 +0100312 Set the maximum time to wait for an agent to close an idle connection. It is
313 applied on the stream that handle the connection with the agent.
314
315 Arguments :
316 <timeout> is the timeout value specified in milliseconds by default, but
317 can be in any other unit if the number is suffixed by the unit,
318 as explained at the top of this document.
319
320
321timeout processing <timeout>
322 Set the maximum time to wait for a stream to process an event, i.e to acquire
323 a stream to talk with an agent, to encode all messages, to send the NOTIFY
324 frame, to receive the corrsponding acknowledgement and to process all
325 actions. It is applied on the stream that handle the client and the server
326 sessions.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200327
328 Arguments :
329 <timeout> is the timeout value specified in milliseconds by default, but
330 can be in any other unit if the number is suffixed by the unit,
331 as explained at the top of this document.
332
333
334use-backend <backend>
335 Specify the backend to use. It must be defined.
336
337 Arguments :
338 <backend> is the name of a valid "backend" section.
339
340
3412.3. "spoe-message" section
342----------------------------
343
344To offload the stream processing, SPOE will send messages with specific
345information at a specific moment in the stream life and will wait for
346corresponding replies to know what to do.
347
348
349spoe-message <name>
350 Create a new SPOE message with the name <name>.
351
352 Arguments :
353 <name> is the name of the SPOE message.
354
355 Here you define a message that can be referenced in a "spoe-agent"
356 section. Following keywords are supported :
Christopher Faulet57583e42017-09-04 15:41:09 +0200357 - acl
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200358 - args
359 - event
360
361 See also: "spoe-agent" section.
362
363
Christopher Faulet57583e42017-09-04 15:41:09 +0200364acl <aclname> <criterion> [flags] [operator] <value> ...
365
366 Declare or complete an access list.
367
368 See section 7 about ACL usage in the HAProxy Configuration Manual.
369
370
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200371args [name=]<sample> ...
372 Define arguments passed into the SPOE message.
373
374 Arguments :
375 <sample> is a sample expression.
376
377 When the message is processed, if a sample expression is not available, it is
378 set to NULL. Arguments are processed in their declaration order and added in
379 the message in that order. It is possible to declare named arguements.
380
381 For example:
382 args frontend=fe_id src dst
383
384
Christopher Faulet57583e42017-09-04 15:41:09 +0200385event <name> [ { if | unless } <condition> ]
386 Set the event that triggers sending of the message. It may optionally be
387 followed by an ACL-based condition, in which case it will only be evaluated
388 if the condition is true.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200389
Christopher Faulet57583e42017-09-04 15:41:09 +0200390 ACL-based conditions are executed in the context of the stream that handle
391 the client and the server connections.
392
393 Arguments :
394 <name> is the event name.
395 <condition> is a standard ACL-based condition.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200396
397 Supported events are:
398 - on-client-session
Christopher Faulet1002aac2016-12-09 17:41:54 +0100399 - on-server-session
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200400 - on-frontend-tcp-request
401 - on-backend-tcp-request
402 - on-tcp-response
403 - on-frontend-http-request
404 - on-backend-http-request
405 - on-http-response
406
Christopher Faulet57583e42017-09-04 15:41:09 +0200407 See section "Events & Messages" for more details about supported events.
408 See section 7 about ACL usage in the HAProxy Configuration Manual.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200409
4102.4. Example
411-------------
412
413Here is a simple but complete example that sends client-ip address to a ip
414reputation service. This service can set the variable "ip_score" which is an
415integer between 0 and 100, indicating its reputation (100 means totally safe
416and 0 a blacklisted IP with no doubt).
417
418 ###
419 ### HAProxy configuration
420 frontend www
421 mode http
422 bind *:80
423
424 filter spoe engine ip-reputation config spoe-ip-reputation.conf
425
426 # Reject connection if the IP reputation is under 20
427 tcp-request content reject if { var(sess.iprep.ip_score) -m int lt 20 }
428
429 default_backend http-servers
430
431 backend http-servers
432 mode http
433 server http A.B.C.D:80
434
435 backend iprep-servers
436 mode tcp
437 balance roundrobin
438
439 timeout connect 5s # greater than hello timeout
440 timeout server 3m # greater than idle timeout
441
442 server iprep1 A1.B1.C1.D1:12345
443 server iprep2 A2.B2.C2.D2:12345
444
445 ####
446 ### spoe-ip-reputation.conf
447 [ip-reputation]
448
449 spoe-agent iprep-agent
450 messages get-ip-reputation
451
452 option var-prefix iprep
453
Christopher Faulet03a34492016-11-19 16:47:56 +0100454 timeout hello 2s
455 timeout idle 2m
456 timeout processing 10ms
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200457
458 use-backend iprep-servers
459
460 spoe-message get-ip-reputation
461 args ip=src
Christopher Faulet57583e42017-09-04 15:41:09 +0200462 event on-client-session if ! { src -f /etc/haproxy/whitelist.lst }
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200463
464
4653. SPOP specification
466----------------------
467
4683.1. Data types
469----------------
470
471Here is the bytewise representation of typed data:
472
473 TYPED-DATA : <TYPE:4 bits><FLAGS:4 bits><DATA>
474
475Supported types and their representation are:
476
477 TYPE | ID | DESCRIPTION
478 -----------------------------+-----+----------------------------------
479 NULL | 0 | NULL : <0>
480 Boolean | 1 | BOOL : <1+FLAG>
481 32bits signed integer | 2 | INT32 : <2><VALUE:varint>
482 32bits unsigned integer | 3 | UINT32 : <3><VALUE:varint>
483 64bits signed integer | 4 | INT64 : <4><VALUE:varint>
484 32bits unsigned integer | 5 | UNIT64 : <5><VALUE:varint>
485 IPV4 | 6 | IPV4 : <6><STRUCT IN_ADDR:4 bytes>
486 IPV6 | 7 | IPV6 : <7><STRUCT IN_ADDR6:16 bytes>
487 String | 8 | STRING : <8><LENGTH:varint><BYTES>
488 Binary | 9 | BINARY : <9><LENGTH:varint><BYTES>
489 10 -> 15 unused/reserved | - | -
490 -----------------------------+-----+----------------------------------
491
492Variable-length integer (varint) are encoded using Peers encoding:
493
494
495 0 <= X < 240 : 1 byte (7.875 bits) [ XXXX XXXX ]
496 240 <= X < 2288 : 2 bytes (11 bits) [ 1111 XXXX ] [ 0XXX XXXX ]
497 2288 <= X < 264432 : 3 bytes (18 bits) [ 1111 XXXX ] [ 1XXX XXXX ] [ 0XXX XXXX ]
498 264432 <= X < 33818864 : 4 bytes (25 bits) [ 1111 XXXX ] [ 1XXX XXXX ]*2 [ 0XXX XXXX ]
499 33818864 <= X < 4328786160 : 5 bytes (32 bits) [ 1111 XXXX ] [ 1XXX XXXX ]*3 [ 0XXX XXXX ]
500 ...
501
502For booleans, the value (true or false) is the first bit in the FLAGS
503bitfield. if this bit is set to 0, then the boolean is evaluated as false,
504otherwise, the boolean is evaluated as true.
505
5063.2. Frames
507------------
508
509Exchange between HAProxy and agents are made using FRAME packets. All frames
510must be prefixed with their size encoded on 4 bytes in network byte order:
511
512 <FRAME-LENGTH:4 bytes> <FRAME>
513
514A frame always starts with its type, on one byte, followed by metadata
515containing flags, on 4 bytes and a two variable-length integer representing the
516stream identifier and the frame identifier inside the stream:
517
518 FRAME : <FRAME-TYPE:1 byte> <METADATA> <FRAME-PAYLOAD>
519 METADATA : <FLAGS:4 bytes> <STREAM-ID:varint> <FRAME-ID:varint>
520
521Then comes the frame payload. Depending on the frame type, the payload can be
522of three types: a simple key/value list, a list of messages or a list of
523actions.
524
525 FRAME-PAYLOAD : <LIST-OF-MESSAGES> | <LIST-OF-ACTIONS> | <KV-LIST>
526
527 LIST-OF-MESSAGES : [ <MESSAGE-NAME> <NB-ARGS:1 byte> <KV-LIST> ... ]
528 MESSAGE-NAME : <STRING>
529
530 LIST-OF-ACTIONS : [ <ACTION-TYPE:1 byte> <NB-ARGS:1 byte> <ACTION-ARGS> ... ]
531 ACTION-ARGS : [ <TYPED-DATA>... ]
532
533 KV-LIST : [ <KV-NAME> <KV-VALUE> ... ]
534 KV-NAME : <STRING>
535 KV-VALUE : <TYPED-DATA>
536
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100537 FLAGS : 0 1 2-31
538 +---+---+----------+
539 | | A | |
540 | F | B | |
541 | I | O | RESERVED |
542 | N | R | |
543 | | T | |
544 +---+---+----------+
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200545
546 FIN: Indicates that this is the final payload fragment. The first fragment
547 may also be the final fragment.
548
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100549 ABORT: Indicates that the processing of the current frame must be
550 cancelled. This bit should be set on frames with a fragmented
551 payload. It can be ignore for frames with an unfragemnted
552 payload. When it is set, the FIN bit must also be set.
553
554
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200555Frames cannot exceed a maximum size negociated between HAProxy and agents
556during the HELLO handshake. Most of time, payload will be small enough to send
557it in one frame. But when supported by the peer, it will be possible to
558fragment huge payload on many frames. This ability is announced during the
559HELLO handshake and it can be asynmetric (supported by agents but not by
560HAProxy or the opposite). The following rules apply to fragmentation:
561
562 * An unfragemnted payload consists of a single frame with the FIN bit set.
563
564 * A fragemented payload consists of several frames with the FIN bit clear and
565 terminated by a single frame with the FIN bit set. All these frames must
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100566 share the same STREAM-ID and FRAME-ID. The first frame must set the right
567 FRAME-TYPE (e.g, NOTIFY). The following frames must have an unset type (0).
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200568
569Beside the support of fragmented payload by a peer, some payload must not be
570fragmented. See below for details.
571
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100572IMPORTANT : The maximum size supported by peers for a frame must be greater
573than or equal to 256 bytes.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200574
5753.2.1. Frame capabilities
576--------------------------
577
578Here are the list of official capabilities that HAProxy and agents can support:
579
Christopher Fauleta1cda022016-12-21 08:58:06 +0100580 * fragmentation: This is the ability for a peer to support fragmented
581 payload in received frames. This is an asymmectical
582 capability, it only concerns the peer that announces
583 it. This is the responsibility to the other peer to use it
584 or not.
585
586 * pipelining: This is the ability for a peer to decouple NOTIFY and ACK
587 frames. This is a symmectical capability. To be used, it must
588 be supported by HAproxy and agents. Unlike HTTP pipelining, the
589 ACK frames can be send in any order, but always on the same TCP
590 connection used for the corresponding NOTIFY frame.
591
592 * async: This ability is similar to the pipelining, but here any TCP
593 connection established between HAProxy and the agent can be used to
594 send ACK frames. if an agent accepts connections from multiple
595 HAProxy, it can use the "engine-id" value to group TCP
596 connections. See details about HAPROXY-HELLO frame.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200597
598Unsupported or unknown capabilities are silently ignored, when possible.
599
6003.2.2. Frame types overview
601----------------------------
602
603Here are types of frame supported by SPOE. Frames sent by HAProxy come first,
604then frames sent by agents :
605
606 TYPE | ID | DESCRIPTION
607 -----------------------------+-----+-------------------------------------
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100608 UNSET | 0 | Used for all frames but the first when a
609 | | payload is fragmented.
610 -----------------------------+-----+-------------------------------------
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200611 HAPROXY-HELLO | 1 | Sent by HAProxy when it opens a
612 | | connection on an agent.
613 | |
614 HAPROXY-DISCONNECT | 2 | Sent by HAProxy when it want to close
615 | | the connection or in reply to an
616 | | AGENT-DISCONNECT frame
617 | |
618 NOTIFY | 3 | Sent by HAProxy to pass information
619 | | to an agent
620 -----------------------------+-----+-------------------------------------
621 AGENT-HELLO | 101 | Reply to a HAPROXY-HELLO frame, when
622 | | the connection is established
623 | |
624 AGENT-DISCONNECT | 102 | Sent by an agent just before closing
625 | | the connection
626 | |
627 ACK | 103 | Sent to acknowledge a NOTIFY frame
628 -----------------------------+-----+-------------------------------------
629
630Unknown frames may be silently skipped.
631
6323.2.3. Workflow
633----------------
634
635 * Successful HELLO handshake:
636
637 HAPROXY AGENT SRV
638 | HAPROXY-HELLO |
Christopher Fauletba7bc162016-11-07 21:07:38 +0100639 | (healthcheck: false) |
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200640 | --------------------------> |
641 | |
642 | AGENT-HELLO |
643 | <-------------------------- |
644 | |
645
Christopher Fauletba7bc162016-11-07 21:07:38 +0100646 * Successful HELLO healthcheck:
647
648 HAPROXY AGENT SRV
649 | HAPROXY-HELLO |
650 | (healthcheck: true) |
651 | --------------------------> |
652 | |
653 | AGENT-HELLO + close() |
654 | <-------------------------- |
655 | |
656
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200657
658 * Error encountered by agent during the HELLO handshake:
659
660 HAPROXY AGENT SRV
661 | HAPROXY-HELLO |
662 | --------------------------> |
663 | |
664 | DISCONNECT + close() |
665 | <-------------------------- |
666 | |
667
668 * Error encountered by HAProxy during the HELLO handshake:
669
670 HAPROXY AGENT SRV
671 | HAPROXY-HELLO |
672 | --------------------------> |
673 | |
674 | AGENT-HELLO |
675 | <-------------------------- |
676 | |
677 | DISCONNECT |
678 | --------------------------> |
679 | |
680 | DISCONNECT + close() |
681 | <-------------------------- |
682 | |
683
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100684 * Notify / Ack exchange (unfragmented payload):
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200685
686 HAPROXY AGENT SRV
687 | NOTIFY |
688 | --------------------------> |
689 | |
690 | ACK |
691 | <-------------------------- |
692 | |
693
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100694 * Notify / Ack exchange (fragmented payload):
695
696 HAPROXY AGENT SRV
697 | NOTIFY (frag 1) |
698 | --------------------------> |
699 | |
700 | UNSET (frag 2) |
701 | --------------------------> |
702 | ... |
703 | UNSET (frag N) |
704 | --------------------------> |
705 | |
706 | ACK |
707 | <-------------------------- |
708 | |
709
710 * Aborted fragmentation of a NOTIFY frame:
711
712 HAPROXY AGENT SRV
713 | ... |
714 | UNSET (frag X) |
715 | --------------------------> |
716 | |
717 | ACK/ABORT |
718 | <-------------------------- |
719 | |
720 | UNSET (frag X+1) |
721 | -----------X |
722 | |
723 | |
724
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200725 * Connection closed by haproxy:
726
727 HAPROXY AGENT SRV
728 | DISCONNECT |
729 | --------------------------> |
730 | |
731 | DISCONNECT + close() |
732 | <-------------------------- |
733 | |
734
735 * Connection closed by agent:
736
737 HAPROXY AGENT SRV
738 | DISCONNECT + close() |
739 | <-------------------------- |
740 | |
741
7423.2.4. Frame: HAPROXY-HELLO
743----------------------------
744
745This frame is the first one exchanged between HAProxy and an agent, when the
746connection is established. The payload of this frame is a KV-LIST. It cannot be
747fragmented. STREAM-ID and FRAME-ID are must be set 0.
748
749Following items are mandatory in the KV-LIST:
750
751 * "supported-versions" <STRING>
752
753 Last SPOP major versions supported by HAProxy. It is a comma-separated list
754 of versions, following the format "Major.Minor". Spaces must be ignored, if
755 any. When a major version is announced by HAProxy, it means it also support
756 all previous minor versions.
757
758 Example: "2.0, 1.5" means HAProxy supports SPOP 2.0 and 1.0 to 1.5
759
760 * "max-frame-size" <UINT32>
761
762 This is the maximum size allowed for a frame. The HAPROXY-HELLO frame must
763 be lower or equal to this value.
764
765 * "capabilities" <STRING>
766
767 This a comma-separated list of capabilities supported by HAProxy. Spaces
768 must be ignored, if any.
769
Christopher Fauletba7bc162016-11-07 21:07:38 +0100770Following optional items can be added in the KV-LIST:
771
772 * "healthcheck" <BOOLEAN>
773
774 If this item is set to TRUE, then the HAPROXY-HELLO frame is sent during a
775 SPOE health check. When set to FALSE, this item can be ignored.
776
Christopher Fauleta1cda022016-12-21 08:58:06 +0100777 * "engine-id" <STRING>
778
779 This is a uniq string that identify a SPOE engine.
780
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200781To finish the HELLO handshake, the agent must return an AGENT-HELLO frame with
782its supported SPOP version, the lower value between its maximum size allowed
783for a frame and the HAProxy one and capabilities it supports. If an error
784occurs or if an incompatibility is detected with the agent configuration, an
785AGENT-DISCONNECT frame must be returned.
786
7873.2.5. Frame: AGENT-HELLO
788--------------------------
789
790This frame is sent in reply to a HAPROXY-HELLO frame to finish a HELLO
791handshake. As for HAPROXY-HELLO frame, STREAM-ID and FRAME-ID are also set
7920. The payload of this frame is a KV-LIST and it cannot be fragmented.
793
794Following items are mandatory in the KV-LIST:
795
796 * "version" <STRING>
797
798 This is the SPOP version the agent supports. It must follow the format
799 "Major.Minor" and it must be lower or equal than one of major versions
800 announced by HAProxy.
801
802 * "max-frame-size" <UINT32>
803
804 This is the maximum size allowed for a frame. It must be lower or equal to
805 the value in the HAPROXY-HELLO frame. This value will be used for all
806 subsequent frames.
807
808 * "capabilities" <STRING>
809
810 This a comma-separated list of capabilities supported by agent. Spaces must
811 be ignored, if any.
812
813At this time, if everything is ok for HAProxy (supported version and valid
814max-frame-size value), the HELLO handshake is successfully completed. Else,
815HAProxy sends a HAPROXY-DISCONNECT frame with the corresponding error.
816
Christopher Fauletba7bc162016-11-07 21:07:38 +0100817If "healthcheck" item was set to TRUE in the HAPROXY-HELLO frame, the agent can
818safely close the connection without DISCONNECT frame. In all cases, HAProxy
819will close the connexion at the end of the health check.
820
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02008213.2.6. Frame: NOTIFY
822---------------------
823
824Information are sent to the agents inside NOTIFY frames. These frames are
825attached to a stream, so STREAM-ID and FRAME-ID must be set. The payload of
826NOTIFY frames is a LIST-OF-MESSAGES and, if supported by agents, it can be
827fragmented.
828
829NOTIFY frames must be acknowledge by agents sending an ACK frame, repeating
830right STREAM-ID and FRAME-ID.
831
8323.2.7. Frame: ACK
833------------------
834
835ACK frames must be sent by agents to reply to NOTIFY frames. STREAM-ID and
836FRAME-ID found in a NOTIFY frame must be reuse in the corresponding ACK
837frame. The payload of ACK frames is a LIST-OF-ACTIONS and, if supported by
838HAProxy, it can be fragmented.
839
8403.2.8. Frame: HAPROXY-DISCONNECT
841---------------------------------
842
843If an error occurs, at anytime, from the HAProxy side, a HAPROXY-DISCONNECT
844frame is sent with information describing the error. HAProxy will wait an
845AGENT-DISCONNECT frame in reply. All other frames will be ignored. The agent
846must then close the socket.
847
848The payload of this frame is a KV-LIST. It cannot be fragmented. STREAM-ID and
849FRAME-ID are must be set 0.
850
851Following items are mandatory in the KV-LIST:
852
853 * "status-code" <UINT32>
854
855 This is the code corresponding to the error.
856
857 * "message" <STRING>
858
859 This is a textual message describing the error.
860
861For more information about known errors, see section "Errors & timeouts"
862
8633.2.9. Frame: AGENT-DISCONNECT
864-------------------------------
865
866If an error occurs, at anytime, from the agent size, a AGENT-DISCONNECT frame
867is sent, with information desribing the error. such frame is also sent in reply
868to a HAPROXY-DISCONNECT. The agent must close the socket just after sending
869this frame.
870
871The payload of this frame is a KV-LIST. It cannot be fragmented. STREAM-ID and
872FRAME-ID are must be set 0.
873
874Following items are mandatory in the KV-LIST:
875
876 * "status-code" <UINT32>
877
878 This is the code corresponding to the error.
879
880 * "message" <STRING>
881
882 This is a textual message describing the error.
883
884For more information about known errors, see section "Errors & timeouts"
885
8863.3. Events & Messages
887-----------------------
888
889Information about streams are sent in NOTIFY frames. You can specify which kind
890of information to send by defining "spoe-message" sections in your SPOE
891configuration file. for each "spoe-message" there will be a message in a NOTIFY
892frame when the right event is triggered.
893
894A NOTIFY frame is sent for an specific event when there is at least one
895"spoe-message" attached to this event. All messages for an event will be added
896in the same NOTIFY frame.
897
898Here is the list of supported events:
899
900 * on-client-session is triggered when a new client session is created.
901 This event is only available for SPOE filters
902 declared in a frontend or a listen section.
903
904 * on-frontend-tcp-request is triggered just before the evaluation of
905 "tcp-request content" rules on the frontend side.
906 This event is only available for SPOE filters
907 declared in a frontend or a listen section.
908
909 * on-backend-tcp-request is triggered just before the evaluation of
910 "tcp-request content" rules on the backend side.
911 This event is skipped for SPOE filters declared
912 in a listen section.
913
914 * on-frontend-http-request is triggered just before the evaluation of
915 "http-request" rules on the frontend side. This
916 event is only available for SPOE filters declared
917 in a frontend or a listen section.
918
919 * on-backend-http-request is triggered just before the evaluation of
920 "http-request" rules on the backend side. This
921 event is skipped for SPOE filters declared in a
922 listen section.
923
924 * on-server-session is triggered when the session with the server is
925 established.
926
927 * on-tcp-response is triggered just before the evaluation of
928 "tcp-response content" rules.
929
930 * on-http-response is triggered just before the evaluation of
931 "http-response" rules.
932
933
934The stream processing will loop on these events, when triggered, waiting the
935agent reply.
936
9373.4. Actions
938-------------
939
940An agent must acknowledge each NOTIFY frame by sending the corresponding ACK
941frame. Actions can be added in these frames to dynamically take action on the
942processing of a stream.
943
944Here is the list of supported actions:
945
946 * set-var set the value for an existing variable. 3 arguments must be
947 attached to this action: the variable scope (proc, sess, txn,
948 req or req), the variable name (a string) and its value.
949
950 ACTION-SET-VAR : <SET-VAR:1 byte><NB-ARGS:1 byte><VAR-SCOPE:1 byte><VAR-NAME><VAR-VALUE>
951
952 SET-VAR : <1>
953 NB-ARGS : <3>
954 VAR-SCOPE : <PROCESS> | <SESSION> | <TRANSACTION> | <REQUEST> | <RESPONSE>
955 VAR-NAME : <STRING>
956 VAR-VALUE : <TYPED-DATA>
957
958 PROCESS : <0>
959 SESSION : <1>
960 TRANSACTION : <2>
961 REQUEST : <3>
Christopher Fauleta1cda022016-12-21 08:58:06 +0100962 RESPONSE : <4>
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200963
964 * unset-var unset the value for an existing variable. 2 arguments must be
965 attached to this action: the variable scope (proc, sess, txn,
966 req or req) and the variable name (a string).
967
Christopher Faulet1002aac2016-12-09 17:41:54 +0100968 ACTION-UNSET-VAR : <UNSET-VAR:1 byte><NB-ARGS:1 byte><VAR-SCOPE:1 byte><VAR-NAME>
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200969
Christopher Faulet1002aac2016-12-09 17:41:54 +0100970 UNSET-VAR : <2>
971 NB-ARGS : <2>
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200972 VAR-SCOPE : <PROCESS> | <SESSION> | <TRANSACTION> | <REQUEST> | <RESPONSE>
973 VAR-NAME : <STRING>
974
975 PROCESS : <0>
976 SESSION : <1>
977 TRANSACTION : <2>
978 REQUEST : <3>
Christopher Fauleta1cda022016-12-21 08:58:06 +0100979 RESPONSE : <4>
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200980
981
982NOTE: Name of the variables will be automatically prefixed by HAProxy to avoid
983 name clashes with other variables used in HAProxy. Moreover, unknown
984 variable will be silently ignored.
985
Christopher Fauletd1307ce2017-02-27 21:59:39 +01009863.5. Errors & timeouts
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200987----------------------
988
989Here is the list of all known errors:
990
991 STATUS CODE | DESCRIPTION
992 ----------------+--------------------------------------------------------
993 0 | normal (no error occurred)
994 1 | I/O error
995 2 | A timeout occurred
996 3 | frame is too big
997 4 | invalid frame received
998 5 | version value not found
999 6 | max-frame-size value not found
1000 7 | capabilities value not found
1001 8 | unsupported version
1002 9 | max-frame-size too big or too small
Christopher Fauletd1307ce2017-02-27 21:59:39 +01001003 10 | payload fragmentation is not supported
1004 11 | invalid interlaced frames
1005 12 | frame-id not found (it does not match any referenced frame)
1006 13 | resource allocation error
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02001007 99 | an unknown error occurrde
1008 ----------------+--------------------------------------------------------
1009
1010An agent can define its own errors using a not yet assigned status code.
1011
Christopher Fauletea62c2a2016-11-14 10:54:21 +01001012IMPORTANT NOTE: By default, for a specific stream, when an abnormal/unexpected
1013 error occurs, the SPOE is disabled for all the transaction. So
1014 if you have several events configured, such error on an event
1015 will disabled all followings. For TCP streams, this will
1016 disable the SPOE for the whole session. For HTTP streams, this
1017 will disable it for the transaction (request and response).
1018 See 'option continue-on-error' to bypass this limitation.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02001019
1020To avoid a stream to wait infinitly, you must carefully choose the
1021acknowledgement timeout. In most of cases, it will be quiet low. But it depends
1022on the responsivness of your service.
1023
1024You must also choose idle timeout carefully. Because connection with your
1025service depends on the backend configuration used by the SPOA, it is important
1026to use a lower value for idle timeout than the server timeout. Else the
1027connection will be closed by HAProxy. The same is true for hello timeout. You
1028should choose a lower value than the connect timeout.
1029
1030
1031/*
1032 * Local variables:
1033 * fill-column: 79
1034 * End:
1035 */