blob: 0f6ed14a512c21d553c82cc9dc44221cb977ba8a [file] [log] [blame]
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02001 -----------------------------------------------
2 Stream Processing Offload Engine (SPOE)
Christopher Fauletd1307ce2017-02-27 21:59:39 +01003 Version 1.1
4 ( Last update: 2017-02-27 )
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
1432.2. "spoe-agent" section
144--------------------------
145
146For each engine, you must define one and only one "spoe-agent" section. In this
147section, you will declare SPOE messages and the backend you will use. You will
148also set timeouts and options to customize your agent's behaviour.
149
150
151spoe-agent <name>
152 Create a new SPOA with the name <name>. It must have one and only one
153 "spoe-agent" definition by SPOE scope.
154
155 Arguments :
156 <name> is the name of the agent section.
157
158 following keywords are supported :
Christopher Faulet48026722016-11-16 15:01:12 +0100159 - maxconnrate
160 - maxerrrate
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100161 - max-frame-size
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200162 - messages
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100163 - [no] option async
164 - [no] option pipelining
165 - [no] option send-frag-payload
Christopher Fauletea62c2a2016-11-14 10:54:21 +0100166 - option continue-on-error
Christopher Faulet985532d2016-11-16 15:36:19 +0100167 - option set-on-error
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200168 - option var-prefix
Christopher Faulet03a34492016-11-19 16:47:56 +0100169 - timeout hello|idle|processing
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200170 - use-backend
171
172
Christopher Faulet48026722016-11-16 15:01:12 +0100173maxconnrate <number>
174 Set the maximum number of connections per second to <number>. The SPOE will
175 stop to open new connections if the maximum is reached and will wait to
176 acquire an existing one. So it is important to set "timeout hello" to a
177 relatively small value.
178
179
180maxerrrate <number>
181 Set the maximum number of errors per second to <number>. The SPOE will stop
182 its processing if the maximum is reached.
183
184
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100185max-frame-size <number>
186 Set the maximum allowed size for frames exchanged between HAProxy and SPOA.
187 It must be in the range [256, tune.bufsize-4] (4 bytes are reserved for the
188 frame length). By default, it is set to (tune.bufsize-4).
189
190
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200191messages <msg-name> ...
192 Declare the list of SPOE messages that an agent will handle.
193
194 Arguments :
195 <msg-name> is the name of a SPOE message.
196
197 Messages declared here must be found in the same engine scope, else an error
198 is triggered during the configuration parsing. You can have many "messages"
199 lines.
200
201 See also: "spoe-message" section.
202
203
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100204option async
205no option async
206 Enable or disable the support of asynchronus exchanges between HAProxy and
207 SPOA. By default, this option is enabled.
208
209
Christopher Fauletea62c2a2016-11-14 10:54:21 +0100210option continue-on-error
211 Do not stop the events processing when an error occurred on a stream.
212
213 By default, for a specific stream, when an abnormal/unexpected error occurs,
214 the SPOE is disabled for all the transaction. So if you have several events
215 configured, such error on an event will disabled all followings. For TCP
216 streams, this will disable the SPOE for the whole session. For HTTP streams,
217 this will disable it for the transaction (request and response).
218
219 When set, this option bypass this behaviour and only the current event will
220 be ignored.
221
222
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100223option pipelining
224no option pipelining
225 Enable or disable the support of pipelined exchanges between HAProxy and
226 SPOA. By default, this option is enabled.
227
228
229option send-frag-payload
230no option send-frag-payload
231 Enable or disable the sending of fragmented payload to SPOA. By default, this
232 option is enabled.
233
234
Christopher Faulet985532d2016-11-16 15:36:19 +0100235option set-on-error <var name>
236 Define the variable to set when an error occurred during an event processing.
237
238 Arguments :
239
240 <var name> is the variable name, without the scope. The name may only
241 contain characters 'a-z', 'A-Z', '0-9', '.' and '_'.
242
243 This variable will only be set when an error occurred in the scope of the
244 transaction. As for all other variables define by the SPOE, it will be
245 prefixed. So, if your variable name is "error" and your prefix is
246 "my_spoe_pfx", the variable will be "txn.my_spoe_pfx.error".
247
Christopher Fauletb067b062017-01-04 16:39:11 +0100248 When set, the variable is an integer representing the error reason. For values
249 under 256, it represents an error coming from the engine. Below 256, it
250 reports a SPOP error. In this case, to retrieve the right SPOP status code,
251 you must remove 256 to this value. Here are possible values:
252
253 * 1 a timeout occurred during the event processing.
254
255 * 2 an error was triggered during the ressources allocation.
256
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100257 * 3 the frame payload exceeds the frame size and it cannot be
258 fragmented.
259
260 * 4 the fragmentation of a payload is aborted.
261
Christopher Fauletb067b062017-01-04 16:39:11 +0100262 * 255 an unknown error occurred during the event processing.
263
264 * 256+N a SPOP error occurred during the event processing (see section
265 "Errors & timeouts").
266
267 Note that if "option continue-on-error" is set, the variable is not
268 automatically removed between events processing.
Christopher Faulet985532d2016-11-16 15:36:19 +0100269
270 See also: "option continue-on-error", "option var-prefix".
271
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200272option var-prefix <prefix>
273 Define the prefix used when variables are set by an agent.
274
275 Arguments :
276
277 <prefix> is the prefix used to limit the scope of variables set by an
278 agent.
279
280 To avoid conflict with other variables defined by HAProxy, all variables
281 names will be prefixed. By default, the "spoe-agent" name is used. This
282 option can be used to customize it.
283
284 The prefix will be added between the variable scope and its name, separated
285 by a '.'. It may only contain characters 'a-z', 'A-Z', '0-9', '.' and '_', as
286 for variables name. In HAProxy configuration, you need to use this prefix as
287 a part of the variables name. For example, if an agent define the variable
288 "myvar" in the "txn" scope, with the prefix "my_spoe_pfx", then you should
289 use "txn.my_spoe_pfx.myvar" name in your HAProxy configuration.
290
291 An agent will never set new variables at runtime. It can only set new value
292 for existing ones.
293
294
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200295timeout hello <timeout>
296 Set the maximum time to wait for an agent to receive the AGENT-HELLO frame.
Christopher Fauletf7a30922016-11-10 15:04:51 +0100297 It is applied on the stream that handle the connection with the agent.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200298
299 Arguments :
300 <timeout> is the timeout value specified in milliseconds by default, but
301 can be in any other unit if the number is suffixed by the unit,
302 as explained at the top of this document.
303
304 This timeout is an applicative timeout. It differ from "timeout connect"
305 defined on backends.
306
307
308timeout idle <timeout>
Christopher Fauletf7a30922016-11-10 15:04:51 +0100309 Set the maximum time to wait for an agent to close an idle connection. It is
310 applied on the stream that handle the connection with the agent.
311
312 Arguments :
313 <timeout> is the timeout value specified in milliseconds by default, but
314 can be in any other unit if the number is suffixed by the unit,
315 as explained at the top of this document.
316
317
318timeout processing <timeout>
319 Set the maximum time to wait for a stream to process an event, i.e to acquire
320 a stream to talk with an agent, to encode all messages, to send the NOTIFY
321 frame, to receive the corrsponding acknowledgement and to process all
322 actions. It is applied on the stream that handle the client and the server
323 sessions.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200324
325 Arguments :
326 <timeout> is the timeout value specified in milliseconds by default, but
327 can be in any other unit if the number is suffixed by the unit,
328 as explained at the top of this document.
329
330
331use-backend <backend>
332 Specify the backend to use. It must be defined.
333
334 Arguments :
335 <backend> is the name of a valid "backend" section.
336
337
3382.3. "spoe-message" section
339----------------------------
340
341To offload the stream processing, SPOE will send messages with specific
342information at a specific moment in the stream life and will wait for
343corresponding replies to know what to do.
344
345
346spoe-message <name>
347 Create a new SPOE message with the name <name>.
348
349 Arguments :
350 <name> is the name of the SPOE message.
351
352 Here you define a message that can be referenced in a "spoe-agent"
353 section. Following keywords are supported :
354 - args
355 - event
356
357 See also: "spoe-agent" section.
358
359
360args [name=]<sample> ...
361 Define arguments passed into the SPOE message.
362
363 Arguments :
364 <sample> is a sample expression.
365
366 When the message is processed, if a sample expression is not available, it is
367 set to NULL. Arguments are processed in their declaration order and added in
368 the message in that order. It is possible to declare named arguements.
369
370 For example:
371 args frontend=fe_id src dst
372
373
374event <name>
375 Set the event that triggers sending of the message.
376
377 Argument :
378 <name> is the event name.
379
380 Supported events are:
381 - on-client-session
Christopher Faulet1002aac2016-12-09 17:41:54 +0100382 - on-server-session
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200383 - on-frontend-tcp-request
384 - on-backend-tcp-request
385 - on-tcp-response
386 - on-frontend-http-request
387 - on-backend-http-request
388 - on-http-response
389
Christopher Fauletb067b062017-01-04 16:39:11 +0100390 See section "Events & Messages".
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200391
3922.4. Example
393-------------
394
395Here is a simple but complete example that sends client-ip address to a ip
396reputation service. This service can set the variable "ip_score" which is an
397integer between 0 and 100, indicating its reputation (100 means totally safe
398and 0 a blacklisted IP with no doubt).
399
400 ###
401 ### HAProxy configuration
402 frontend www
403 mode http
404 bind *:80
405
406 filter spoe engine ip-reputation config spoe-ip-reputation.conf
407
408 # Reject connection if the IP reputation is under 20
409 tcp-request content reject if { var(sess.iprep.ip_score) -m int lt 20 }
410
411 default_backend http-servers
412
413 backend http-servers
414 mode http
415 server http A.B.C.D:80
416
417 backend iprep-servers
418 mode tcp
419 balance roundrobin
420
421 timeout connect 5s # greater than hello timeout
422 timeout server 3m # greater than idle timeout
423
424 server iprep1 A1.B1.C1.D1:12345
425 server iprep2 A2.B2.C2.D2:12345
426
427 ####
428 ### spoe-ip-reputation.conf
429 [ip-reputation]
430
431 spoe-agent iprep-agent
432 messages get-ip-reputation
433
434 option var-prefix iprep
435
Christopher Faulet03a34492016-11-19 16:47:56 +0100436 timeout hello 2s
437 timeout idle 2m
438 timeout processing 10ms
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200439
440 use-backend iprep-servers
441
442 spoe-message get-ip-reputation
443 args ip=src
444 event on-client-session
445
446
4473. SPOP specification
448----------------------
449
4503.1. Data types
451----------------
452
453Here is the bytewise representation of typed data:
454
455 TYPED-DATA : <TYPE:4 bits><FLAGS:4 bits><DATA>
456
457Supported types and their representation are:
458
459 TYPE | ID | DESCRIPTION
460 -----------------------------+-----+----------------------------------
461 NULL | 0 | NULL : <0>
462 Boolean | 1 | BOOL : <1+FLAG>
463 32bits signed integer | 2 | INT32 : <2><VALUE:varint>
464 32bits unsigned integer | 3 | UINT32 : <3><VALUE:varint>
465 64bits signed integer | 4 | INT64 : <4><VALUE:varint>
466 32bits unsigned integer | 5 | UNIT64 : <5><VALUE:varint>
467 IPV4 | 6 | IPV4 : <6><STRUCT IN_ADDR:4 bytes>
468 IPV6 | 7 | IPV6 : <7><STRUCT IN_ADDR6:16 bytes>
469 String | 8 | STRING : <8><LENGTH:varint><BYTES>
470 Binary | 9 | BINARY : <9><LENGTH:varint><BYTES>
471 10 -> 15 unused/reserved | - | -
472 -----------------------------+-----+----------------------------------
473
474Variable-length integer (varint) are encoded using Peers encoding:
475
476
477 0 <= X < 240 : 1 byte (7.875 bits) [ XXXX XXXX ]
478 240 <= X < 2288 : 2 bytes (11 bits) [ 1111 XXXX ] [ 0XXX XXXX ]
479 2288 <= X < 264432 : 3 bytes (18 bits) [ 1111 XXXX ] [ 1XXX XXXX ] [ 0XXX XXXX ]
480 264432 <= X < 33818864 : 4 bytes (25 bits) [ 1111 XXXX ] [ 1XXX XXXX ]*2 [ 0XXX XXXX ]
481 33818864 <= X < 4328786160 : 5 bytes (32 bits) [ 1111 XXXX ] [ 1XXX XXXX ]*3 [ 0XXX XXXX ]
482 ...
483
484For booleans, the value (true or false) is the first bit in the FLAGS
485bitfield. if this bit is set to 0, then the boolean is evaluated as false,
486otherwise, the boolean is evaluated as true.
487
4883.2. Frames
489------------
490
491Exchange between HAProxy and agents are made using FRAME packets. All frames
492must be prefixed with their size encoded on 4 bytes in network byte order:
493
494 <FRAME-LENGTH:4 bytes> <FRAME>
495
496A frame always starts with its type, on one byte, followed by metadata
497containing flags, on 4 bytes and a two variable-length integer representing the
498stream identifier and the frame identifier inside the stream:
499
500 FRAME : <FRAME-TYPE:1 byte> <METADATA> <FRAME-PAYLOAD>
501 METADATA : <FLAGS:4 bytes> <STREAM-ID:varint> <FRAME-ID:varint>
502
503Then comes the frame payload. Depending on the frame type, the payload can be
504of three types: a simple key/value list, a list of messages or a list of
505actions.
506
507 FRAME-PAYLOAD : <LIST-OF-MESSAGES> | <LIST-OF-ACTIONS> | <KV-LIST>
508
509 LIST-OF-MESSAGES : [ <MESSAGE-NAME> <NB-ARGS:1 byte> <KV-LIST> ... ]
510 MESSAGE-NAME : <STRING>
511
512 LIST-OF-ACTIONS : [ <ACTION-TYPE:1 byte> <NB-ARGS:1 byte> <ACTION-ARGS> ... ]
513 ACTION-ARGS : [ <TYPED-DATA>... ]
514
515 KV-LIST : [ <KV-NAME> <KV-VALUE> ... ]
516 KV-NAME : <STRING>
517 KV-VALUE : <TYPED-DATA>
518
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100519 FLAGS : 0 1 2-31
520 +---+---+----------+
521 | | A | |
522 | F | B | |
523 | I | O | RESERVED |
524 | N | R | |
525 | | T | |
526 +---+---+----------+
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200527
528 FIN: Indicates that this is the final payload fragment. The first fragment
529 may also be the final fragment.
530
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100531 ABORT: Indicates that the processing of the current frame must be
532 cancelled. This bit should be set on frames with a fragmented
533 payload. It can be ignore for frames with an unfragemnted
534 payload. When it is set, the FIN bit must also be set.
535
536
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200537Frames cannot exceed a maximum size negociated between HAProxy and agents
538during the HELLO handshake. Most of time, payload will be small enough to send
539it in one frame. But when supported by the peer, it will be possible to
540fragment huge payload on many frames. This ability is announced during the
541HELLO handshake and it can be asynmetric (supported by agents but not by
542HAProxy or the opposite). The following rules apply to fragmentation:
543
544 * An unfragemnted payload consists of a single frame with the FIN bit set.
545
546 * A fragemented payload consists of several frames with the FIN bit clear and
547 terminated by a single frame with the FIN bit set. All these frames must
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100548 share the same STREAM-ID and FRAME-ID. The first frame must set the right
549 FRAME-TYPE (e.g, NOTIFY). The following frames must have an unset type (0).
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200550
551Beside the support of fragmented payload by a peer, some payload must not be
552fragmented. See below for details.
553
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100554IMPORTANT : The maximum size supported by peers for a frame must be greater
555than or equal to 256 bytes.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200556
5573.2.1. Frame capabilities
558--------------------------
559
560Here are the list of official capabilities that HAProxy and agents can support:
561
Christopher Fauleta1cda022016-12-21 08:58:06 +0100562 * fragmentation: This is the ability for a peer to support fragmented
563 payload in received frames. This is an asymmectical
564 capability, it only concerns the peer that announces
565 it. This is the responsibility to the other peer to use it
566 or not.
567
568 * pipelining: This is the ability for a peer to decouple NOTIFY and ACK
569 frames. This is a symmectical capability. To be used, it must
570 be supported by HAproxy and agents. Unlike HTTP pipelining, the
571 ACK frames can be send in any order, but always on the same TCP
572 connection used for the corresponding NOTIFY frame.
573
574 * async: This ability is similar to the pipelining, but here any TCP
575 connection established between HAProxy and the agent can be used to
576 send ACK frames. if an agent accepts connections from multiple
577 HAProxy, it can use the "engine-id" value to group TCP
578 connections. See details about HAPROXY-HELLO frame.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200579
580Unsupported or unknown capabilities are silently ignored, when possible.
581
5823.2.2. Frame types overview
583----------------------------
584
585Here are types of frame supported by SPOE. Frames sent by HAProxy come first,
586then frames sent by agents :
587
588 TYPE | ID | DESCRIPTION
589 -----------------------------+-----+-------------------------------------
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100590 UNSET | 0 | Used for all frames but the first when a
591 | | payload is fragmented.
592 -----------------------------+-----+-------------------------------------
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200593 HAPROXY-HELLO | 1 | Sent by HAProxy when it opens a
594 | | connection on an agent.
595 | |
596 HAPROXY-DISCONNECT | 2 | Sent by HAProxy when it want to close
597 | | the connection or in reply to an
598 | | AGENT-DISCONNECT frame
599 | |
600 NOTIFY | 3 | Sent by HAProxy to pass information
601 | | to an agent
602 -----------------------------+-----+-------------------------------------
603 AGENT-HELLO | 101 | Reply to a HAPROXY-HELLO frame, when
604 | | the connection is established
605 | |
606 AGENT-DISCONNECT | 102 | Sent by an agent just before closing
607 | | the connection
608 | |
609 ACK | 103 | Sent to acknowledge a NOTIFY frame
610 -----------------------------+-----+-------------------------------------
611
612Unknown frames may be silently skipped.
613
6143.2.3. Workflow
615----------------
616
617 * Successful HELLO handshake:
618
619 HAPROXY AGENT SRV
620 | HAPROXY-HELLO |
Christopher Fauletba7bc162016-11-07 21:07:38 +0100621 | (healthcheck: false) |
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200622 | --------------------------> |
623 | |
624 | AGENT-HELLO |
625 | <-------------------------- |
626 | |
627
Christopher Fauletba7bc162016-11-07 21:07:38 +0100628 * Successful HELLO healthcheck:
629
630 HAPROXY AGENT SRV
631 | HAPROXY-HELLO |
632 | (healthcheck: true) |
633 | --------------------------> |
634 | |
635 | AGENT-HELLO + close() |
636 | <-------------------------- |
637 | |
638
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200639
640 * Error encountered by agent during the HELLO handshake:
641
642 HAPROXY AGENT SRV
643 | HAPROXY-HELLO |
644 | --------------------------> |
645 | |
646 | DISCONNECT + close() |
647 | <-------------------------- |
648 | |
649
650 * Error encountered by HAProxy during the HELLO handshake:
651
652 HAPROXY AGENT SRV
653 | HAPROXY-HELLO |
654 | --------------------------> |
655 | |
656 | AGENT-HELLO |
657 | <-------------------------- |
658 | |
659 | DISCONNECT |
660 | --------------------------> |
661 | |
662 | DISCONNECT + close() |
663 | <-------------------------- |
664 | |
665
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100666 * Notify / Ack exchange (unfragmented payload):
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200667
668 HAPROXY AGENT SRV
669 | NOTIFY |
670 | --------------------------> |
671 | |
672 | ACK |
673 | <-------------------------- |
674 | |
675
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100676 * Notify / Ack exchange (fragmented payload):
677
678 HAPROXY AGENT SRV
679 | NOTIFY (frag 1) |
680 | --------------------------> |
681 | |
682 | UNSET (frag 2) |
683 | --------------------------> |
684 | ... |
685 | UNSET (frag N) |
686 | --------------------------> |
687 | |
688 | ACK |
689 | <-------------------------- |
690 | |
691
692 * Aborted fragmentation of a NOTIFY frame:
693
694 HAPROXY AGENT SRV
695 | ... |
696 | UNSET (frag X) |
697 | --------------------------> |
698 | |
699 | ACK/ABORT |
700 | <-------------------------- |
701 | |
702 | UNSET (frag X+1) |
703 | -----------X |
704 | |
705 | |
706
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200707 * Connection closed by haproxy:
708
709 HAPROXY AGENT SRV
710 | DISCONNECT |
711 | --------------------------> |
712 | |
713 | DISCONNECT + close() |
714 | <-------------------------- |
715 | |
716
717 * Connection closed by agent:
718
719 HAPROXY AGENT SRV
720 | DISCONNECT + close() |
721 | <-------------------------- |
722 | |
723
7243.2.4. Frame: HAPROXY-HELLO
725----------------------------
726
727This frame is the first one exchanged between HAProxy and an agent, when the
728connection is established. The payload of this frame is a KV-LIST. It cannot be
729fragmented. STREAM-ID and FRAME-ID are must be set 0.
730
731Following items are mandatory in the KV-LIST:
732
733 * "supported-versions" <STRING>
734
735 Last SPOP major versions supported by HAProxy. It is a comma-separated list
736 of versions, following the format "Major.Minor". Spaces must be ignored, if
737 any. When a major version is announced by HAProxy, it means it also support
738 all previous minor versions.
739
740 Example: "2.0, 1.5" means HAProxy supports SPOP 2.0 and 1.0 to 1.5
741
742 * "max-frame-size" <UINT32>
743
744 This is the maximum size allowed for a frame. The HAPROXY-HELLO frame must
745 be lower or equal to this value.
746
747 * "capabilities" <STRING>
748
749 This a comma-separated list of capabilities supported by HAProxy. Spaces
750 must be ignored, if any.
751
Christopher Fauletba7bc162016-11-07 21:07:38 +0100752Following optional items can be added in the KV-LIST:
753
754 * "healthcheck" <BOOLEAN>
755
756 If this item is set to TRUE, then the HAPROXY-HELLO frame is sent during a
757 SPOE health check. When set to FALSE, this item can be ignored.
758
Christopher Fauleta1cda022016-12-21 08:58:06 +0100759 * "engine-id" <STRING>
760
761 This is a uniq string that identify a SPOE engine.
762
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200763To finish the HELLO handshake, the agent must return an AGENT-HELLO frame with
764its supported SPOP version, the lower value between its maximum size allowed
765for a frame and the HAProxy one and capabilities it supports. If an error
766occurs or if an incompatibility is detected with the agent configuration, an
767AGENT-DISCONNECT frame must be returned.
768
7693.2.5. Frame: AGENT-HELLO
770--------------------------
771
772This frame is sent in reply to a HAPROXY-HELLO frame to finish a HELLO
773handshake. As for HAPROXY-HELLO frame, STREAM-ID and FRAME-ID are also set
7740. The payload of this frame is a KV-LIST and it cannot be fragmented.
775
776Following items are mandatory in the KV-LIST:
777
778 * "version" <STRING>
779
780 This is the SPOP version the agent supports. It must follow the format
781 "Major.Minor" and it must be lower or equal than one of major versions
782 announced by HAProxy.
783
784 * "max-frame-size" <UINT32>
785
786 This is the maximum size allowed for a frame. It must be lower or equal to
787 the value in the HAPROXY-HELLO frame. This value will be used for all
788 subsequent frames.
789
790 * "capabilities" <STRING>
791
792 This a comma-separated list of capabilities supported by agent. Spaces must
793 be ignored, if any.
794
795At this time, if everything is ok for HAProxy (supported version and valid
796max-frame-size value), the HELLO handshake is successfully completed. Else,
797HAProxy sends a HAPROXY-DISCONNECT frame with the corresponding error.
798
Christopher Fauletba7bc162016-11-07 21:07:38 +0100799If "healthcheck" item was set to TRUE in the HAPROXY-HELLO frame, the agent can
800safely close the connection without DISCONNECT frame. In all cases, HAProxy
801will close the connexion at the end of the health check.
802
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02008033.2.6. Frame: NOTIFY
804---------------------
805
806Information are sent to the agents inside NOTIFY frames. These frames are
807attached to a stream, so STREAM-ID and FRAME-ID must be set. The payload of
808NOTIFY frames is a LIST-OF-MESSAGES and, if supported by agents, it can be
809fragmented.
810
811NOTIFY frames must be acknowledge by agents sending an ACK frame, repeating
812right STREAM-ID and FRAME-ID.
813
8143.2.7. Frame: ACK
815------------------
816
817ACK frames must be sent by agents to reply to NOTIFY frames. STREAM-ID and
818FRAME-ID found in a NOTIFY frame must be reuse in the corresponding ACK
819frame. The payload of ACK frames is a LIST-OF-ACTIONS and, if supported by
820HAProxy, it can be fragmented.
821
8223.2.8. Frame: HAPROXY-DISCONNECT
823---------------------------------
824
825If an error occurs, at anytime, from the HAProxy side, a HAPROXY-DISCONNECT
826frame is sent with information describing the error. HAProxy will wait an
827AGENT-DISCONNECT frame in reply. All other frames will be ignored. The agent
828must then close the socket.
829
830The payload of this frame is a KV-LIST. It cannot be fragmented. STREAM-ID and
831FRAME-ID are must be set 0.
832
833Following items are mandatory in the KV-LIST:
834
835 * "status-code" <UINT32>
836
837 This is the code corresponding to the error.
838
839 * "message" <STRING>
840
841 This is a textual message describing the error.
842
843For more information about known errors, see section "Errors & timeouts"
844
8453.2.9. Frame: AGENT-DISCONNECT
846-------------------------------
847
848If an error occurs, at anytime, from the agent size, a AGENT-DISCONNECT frame
849is sent, with information desribing the error. such frame is also sent in reply
850to a HAPROXY-DISCONNECT. The agent must close the socket just after sending
851this frame.
852
853The payload of this frame is a KV-LIST. It cannot be fragmented. STREAM-ID and
854FRAME-ID are must be set 0.
855
856Following items are mandatory in the KV-LIST:
857
858 * "status-code" <UINT32>
859
860 This is the code corresponding to the error.
861
862 * "message" <STRING>
863
864 This is a textual message describing the error.
865
866For more information about known errors, see section "Errors & timeouts"
867
8683.3. Events & Messages
869-----------------------
870
871Information about streams are sent in NOTIFY frames. You can specify which kind
872of information to send by defining "spoe-message" sections in your SPOE
873configuration file. for each "spoe-message" there will be a message in a NOTIFY
874frame when the right event is triggered.
875
876A NOTIFY frame is sent for an specific event when there is at least one
877"spoe-message" attached to this event. All messages for an event will be added
878in the same NOTIFY frame.
879
880Here is the list of supported events:
881
882 * on-client-session is triggered when a new client session is created.
883 This event is only available for SPOE filters
884 declared in a frontend or a listen section.
885
886 * on-frontend-tcp-request is triggered just before the evaluation of
887 "tcp-request content" rules on the frontend side.
888 This event is only available for SPOE filters
889 declared in a frontend or a listen section.
890
891 * on-backend-tcp-request is triggered just before the evaluation of
892 "tcp-request content" rules on the backend side.
893 This event is skipped for SPOE filters declared
894 in a listen section.
895
896 * on-frontend-http-request is triggered just before the evaluation of
897 "http-request" rules on the frontend side. This
898 event is only available for SPOE filters declared
899 in a frontend or a listen section.
900
901 * on-backend-http-request is triggered just before the evaluation of
902 "http-request" rules on the backend side. This
903 event is skipped for SPOE filters declared in a
904 listen section.
905
906 * on-server-session is triggered when the session with the server is
907 established.
908
909 * on-tcp-response is triggered just before the evaluation of
910 "tcp-response content" rules.
911
912 * on-http-response is triggered just before the evaluation of
913 "http-response" rules.
914
915
916The stream processing will loop on these events, when triggered, waiting the
917agent reply.
918
9193.4. Actions
920-------------
921
922An agent must acknowledge each NOTIFY frame by sending the corresponding ACK
923frame. Actions can be added in these frames to dynamically take action on the
924processing of a stream.
925
926Here is the list of supported actions:
927
928 * set-var set the value for an existing variable. 3 arguments must be
929 attached to this action: the variable scope (proc, sess, txn,
930 req or req), the variable name (a string) and its value.
931
932 ACTION-SET-VAR : <SET-VAR:1 byte><NB-ARGS:1 byte><VAR-SCOPE:1 byte><VAR-NAME><VAR-VALUE>
933
934 SET-VAR : <1>
935 NB-ARGS : <3>
936 VAR-SCOPE : <PROCESS> | <SESSION> | <TRANSACTION> | <REQUEST> | <RESPONSE>
937 VAR-NAME : <STRING>
938 VAR-VALUE : <TYPED-DATA>
939
940 PROCESS : <0>
941 SESSION : <1>
942 TRANSACTION : <2>
943 REQUEST : <3>
Christopher Fauleta1cda022016-12-21 08:58:06 +0100944 RESPONSE : <4>
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200945
946 * unset-var unset the value for an existing variable. 2 arguments must be
947 attached to this action: the variable scope (proc, sess, txn,
948 req or req) and the variable name (a string).
949
Christopher Faulet1002aac2016-12-09 17:41:54 +0100950 ACTION-UNSET-VAR : <UNSET-VAR:1 byte><NB-ARGS:1 byte><VAR-SCOPE:1 byte><VAR-NAME>
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200951
Christopher Faulet1002aac2016-12-09 17:41:54 +0100952 UNSET-VAR : <2>
953 NB-ARGS : <2>
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200954 VAR-SCOPE : <PROCESS> | <SESSION> | <TRANSACTION> | <REQUEST> | <RESPONSE>
955 VAR-NAME : <STRING>
956
957 PROCESS : <0>
958 SESSION : <1>
959 TRANSACTION : <2>
960 REQUEST : <3>
Christopher Fauleta1cda022016-12-21 08:58:06 +0100961 RESPONSE : <4>
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200962
963
964NOTE: Name of the variables will be automatically prefixed by HAProxy to avoid
965 name clashes with other variables used in HAProxy. Moreover, unknown
966 variable will be silently ignored.
967
Christopher Fauletd1307ce2017-02-27 21:59:39 +01009683.5. Errors & timeouts
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200969----------------------
970
971Here is the list of all known errors:
972
973 STATUS CODE | DESCRIPTION
974 ----------------+--------------------------------------------------------
975 0 | normal (no error occurred)
976 1 | I/O error
977 2 | A timeout occurred
978 3 | frame is too big
979 4 | invalid frame received
980 5 | version value not found
981 6 | max-frame-size value not found
982 7 | capabilities value not found
983 8 | unsupported version
984 9 | max-frame-size too big or too small
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100985 10 | payload fragmentation is not supported
986 11 | invalid interlaced frames
987 12 | frame-id not found (it does not match any referenced frame)
988 13 | resource allocation error
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200989 99 | an unknown error occurrde
990 ----------------+--------------------------------------------------------
991
992An agent can define its own errors using a not yet assigned status code.
993
Christopher Fauletea62c2a2016-11-14 10:54:21 +0100994IMPORTANT NOTE: By default, for a specific stream, when an abnormal/unexpected
995 error occurs, the SPOE is disabled for all the transaction. So
996 if you have several events configured, such error on an event
997 will disabled all followings. For TCP streams, this will
998 disable the SPOE for the whole session. For HTTP streams, this
999 will disable it for the transaction (request and response).
1000 See 'option continue-on-error' to bypass this limitation.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02001001
1002To avoid a stream to wait infinitly, you must carefully choose the
1003acknowledgement timeout. In most of cases, it will be quiet low. But it depends
1004on the responsivness of your service.
1005
1006You must also choose idle timeout carefully. Because connection with your
1007service depends on the backend configuration used by the SPOA, it is important
1008to use a lower value for idle timeout than the server timeout. Else the
1009connection will be closed by HAProxy. The same is true for hello timeout. You
1010should choose a lower value than the connect timeout.
1011
1012
1013/*
1014 * Local variables:
1015 * fill-column: 79
1016 * End:
1017 */