blob: 7ce2bef842d021f492bdb447e3f8db9ea0c4939e [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 Faulet336d3ef2017-12-22 10:00:55 +0100175 - option force-set-var
Christopher Faulet985532d2016-11-16 15:36:19 +0100176 - option set-on-error
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200177 - option var-prefix
Christopher Faulet336d3ef2017-12-22 10:00:55 +0100178 - register-var-names
Christopher Faulet03a34492016-11-19 16:47:56 +0100179 - timeout hello|idle|processing
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200180 - use-backend
181
182
Christopher Faulet11610f32017-09-21 10:23:10 +0200183groups <grp-name> ...
184 Declare the list of SPOE groups that an agent will handle.
185
186 Arguments :
187 <grp-name> is the name of a SPOE group.
188
189 Groups delcared here must be found in the same engine scope, else an error is
190 triggered during the configuration parsing. You can have many "groups" lines.
191
192 See also: "spoe-group" section.
193
194
Christopher Faulet48026722016-11-16 15:01:12 +0100195maxconnrate <number>
196 Set the maximum number of connections per second to <number>. The SPOE will
197 stop to open new connections if the maximum is reached and will wait to
198 acquire an existing one. So it is important to set "timeout hello" to a
199 relatively small value.
200
201
202maxerrrate <number>
203 Set the maximum number of errors per second to <number>. The SPOE will stop
204 its processing if the maximum is reached.
205
206
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100207max-frame-size <number>
208 Set the maximum allowed size for frames exchanged between HAProxy and SPOA.
209 It must be in the range [256, tune.bufsize-4] (4 bytes are reserved for the
210 frame length). By default, it is set to (tune.bufsize-4).
211
212
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200213messages <msg-name> ...
214 Declare the list of SPOE messages that an agent will handle.
215
216 Arguments :
217 <msg-name> is the name of a SPOE message.
218
219 Messages declared here must be found in the same engine scope, else an error
220 is triggered during the configuration parsing. You can have many "messages"
221 lines.
222
223 See also: "spoe-message" section.
224
225
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100226option async
227no option async
228 Enable or disable the support of asynchronus exchanges between HAProxy and
229 SPOA. By default, this option is enabled.
230
231
Christopher Fauletea62c2a2016-11-14 10:54:21 +0100232option continue-on-error
233 Do not stop the events processing when an error occurred on a stream.
234
235 By default, for a specific stream, when an abnormal/unexpected error occurs,
236 the SPOE is disabled for all the transaction. So if you have several events
237 configured, such error on an event will disabled all followings. For TCP
238 streams, this will disable the SPOE for the whole session. For HTTP streams,
239 this will disable it for the transaction (request and response).
240
241 When set, this option bypass this behaviour and only the current event will
242 be ignored.
243
Etienne Carriereaec89892017-12-14 09:36:40 +0000244option force-set-var
245 By default, SPOE filter only register already known variables (mainly from
246 parsing of the configuration). If you want that haproxy trusts the agent and
247 registers all variables (ex: can be useful for LUA workload), activate this
248 option.
249
250 Caution : this option opens to a variety of attacks such as a rogue SPOA that
251 asks to register too many variables.
252
Christopher Fauletea62c2a2016-11-14 10:54:21 +0100253
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100254option pipelining
255no option pipelining
256 Enable or disable the support of pipelined exchanges between HAProxy and
257 SPOA. By default, this option is enabled.
258
259
260option send-frag-payload
261no option send-frag-payload
262 Enable or disable the sending of fragmented payload to SPOA. By default, this
263 option is enabled.
264
265
Christopher Faulet985532d2016-11-16 15:36:19 +0100266option set-on-error <var name>
267 Define the variable to set when an error occurred during an event processing.
268
269 Arguments :
270
271 <var name> is the variable name, without the scope. The name may only
272 contain characters 'a-z', 'A-Z', '0-9', '.' and '_'.
273
274 This variable will only be set when an error occurred in the scope of the
275 transaction. As for all other variables define by the SPOE, it will be
276 prefixed. So, if your variable name is "error" and your prefix is
277 "my_spoe_pfx", the variable will be "txn.my_spoe_pfx.error".
278
Christopher Fauletb067b062017-01-04 16:39:11 +0100279 When set, the variable is an integer representing the error reason. For values
280 under 256, it represents an error coming from the engine. Below 256, it
281 reports a SPOP error. In this case, to retrieve the right SPOP status code,
282 you must remove 256 to this value. Here are possible values:
283
284 * 1 a timeout occurred during the event processing.
285
286 * 2 an error was triggered during the ressources allocation.
287
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100288 * 3 the frame payload exceeds the frame size and it cannot be
289 fragmented.
290
291 * 4 the fragmentation of a payload is aborted.
292
Christopher Faulet344c4ab2017-09-22 10:20:13 +0200293 * 5 The frame processing has been interrupted by HAProxy.
294
Christopher Fauletb067b062017-01-04 16:39:11 +0100295 * 255 an unknown error occurred during the event processing.
296
297 * 256+N a SPOP error occurred during the event processing (see section
298 "Errors & timeouts").
299
300 Note that if "option continue-on-error" is set, the variable is not
301 automatically removed between events processing.
Christopher Faulet985532d2016-11-16 15:36:19 +0100302
303 See also: "option continue-on-error", "option var-prefix".
304
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200305option var-prefix <prefix>
306 Define the prefix used when variables are set by an agent.
307
308 Arguments :
309
310 <prefix> is the prefix used to limit the scope of variables set by an
311 agent.
312
313 To avoid conflict with other variables defined by HAProxy, all variables
314 names will be prefixed. By default, the "spoe-agent" name is used. This
315 option can be used to customize it.
316
317 The prefix will be added between the variable scope and its name, separated
318 by a '.'. It may only contain characters 'a-z', 'A-Z', '0-9', '.' and '_', as
319 for variables name. In HAProxy configuration, you need to use this prefix as
320 a part of the variables name. For example, if an agent define the variable
321 "myvar" in the "txn" scope, with the prefix "my_spoe_pfx", then you should
322 use "txn.my_spoe_pfx.myvar" name in your HAProxy configuration.
323
Etienne Carriereaec89892017-12-14 09:36:40 +0000324 By default, an agent will never set new variables at runtime: It can only set
325 new value for existing ones. If you want a different behaviour, see
Christopher Faulet336d3ef2017-12-22 10:00:55 +0100326 force-set-var option and register-var-names directive.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200327
Christopher Faulet336d3ef2017-12-22 10:00:55 +0100328register-var-names <var name> ...
329 Register some variable names. By default, an agent will not be allowed to set
330 new variables at runtime. This rule can be totally relaxed by setting the
331 option "force-set-var". If you know all the variables you will need, this
332 directive is a good way to register them without letting an agent doing what
333 it want. This is only required if these variables are not referenced anywhere
334 in the HAProxy configuration or the SPOE one.
335
336 Arguments:
337 <var name> is a variable name without the scope. The name may only
338 contain characters 'a-z', 'A-Z', '0-9', '.' and '_'.
339
340 The prefix will be automatically added during the registration. You can have
341 many "register-var-names" lines.
342
343 See also: "option force-set-var", "option var-prefix".
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200344
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200345timeout hello <timeout>
346 Set the maximum time to wait for an agent to receive the AGENT-HELLO frame.
Christopher Fauletf7a30922016-11-10 15:04:51 +0100347 It is applied on the stream that handle the connection with the agent.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200348
349 Arguments :
350 <timeout> is the timeout value specified in milliseconds by default, but
351 can be in any other unit if the number is suffixed by the unit,
352 as explained at the top of this document.
353
354 This timeout is an applicative timeout. It differ from "timeout connect"
355 defined on backends.
356
357
358timeout idle <timeout>
Christopher Fauletf7a30922016-11-10 15:04:51 +0100359 Set the maximum time to wait for an agent to close an idle connection. It is
360 applied on the stream that handle the connection with the agent.
361
362 Arguments :
363 <timeout> is the timeout value specified in milliseconds by default, but
364 can be in any other unit if the number is suffixed by the unit,
365 as explained at the top of this document.
366
367
368timeout processing <timeout>
369 Set the maximum time to wait for a stream to process an event, i.e to acquire
370 a stream to talk with an agent, to encode all messages, to send the NOTIFY
371 frame, to receive the corrsponding acknowledgement and to process all
372 actions. It is applied on the stream that handle the client and the server
373 sessions.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200374
375 Arguments :
376 <timeout> is the timeout value specified in milliseconds by default, but
377 can be in any other unit if the number is suffixed by the unit,
378 as explained at the top of this document.
379
380
381use-backend <backend>
382 Specify the backend to use. It must be defined.
383
384 Arguments :
385 <backend> is the name of a valid "backend" section.
386
387
3882.3. "spoe-message" section
389----------------------------
390
391To offload the stream processing, SPOE will send messages with specific
392information at a specific moment in the stream life and will wait for
393corresponding replies to know what to do.
394
395
396spoe-message <name>
397 Create a new SPOE message with the name <name>.
398
399 Arguments :
400 <name> is the name of the SPOE message.
401
402 Here you define a message that can be referenced in a "spoe-agent"
403 section. Following keywords are supported :
Christopher Faulet57583e42017-09-04 15:41:09 +0200404 - acl
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200405 - args
406 - event
407
408 See also: "spoe-agent" section.
409
410
Christopher Faulet57583e42017-09-04 15:41:09 +0200411acl <aclname> <criterion> [flags] [operator] <value> ...
Christopher Faulet57583e42017-09-04 15:41:09 +0200412 Declare or complete an access list.
413
414 See section 7 about ACL usage in the HAProxy Configuration Manual.
415
416
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200417args [name=]<sample> ...
418 Define arguments passed into the SPOE message.
419
420 Arguments :
421 <sample> is a sample expression.
422
423 When the message is processed, if a sample expression is not available, it is
424 set to NULL. Arguments are processed in their declaration order and added in
425 the message in that order. It is possible to declare named arguements.
426
427 For example:
428 args frontend=fe_id src dst
429
430
Christopher Faulet57583e42017-09-04 15:41:09 +0200431event <name> [ { if | unless } <condition> ]
432 Set the event that triggers sending of the message. It may optionally be
433 followed by an ACL-based condition, in which case it will only be evaluated
434 if the condition is true.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200435
Christopher Faulet57583e42017-09-04 15:41:09 +0200436 ACL-based conditions are executed in the context of the stream that handle
437 the client and the server connections.
438
439 Arguments :
440 <name> is the event name.
441 <condition> is a standard ACL-based condition.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200442
443 Supported events are:
444 - on-client-session
Christopher Faulet1002aac2016-12-09 17:41:54 +0100445 - on-server-session
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200446 - on-frontend-tcp-request
447 - on-backend-tcp-request
448 - on-tcp-response
449 - on-frontend-http-request
450 - on-backend-http-request
451 - on-http-response
452
Christopher Faulet57583e42017-09-04 15:41:09 +0200453 See section "Events & Messages" for more details about supported events.
454 See section 7 about ACL usage in the HAProxy Configuration Manual.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200455
Christopher Faulet11610f32017-09-21 10:23:10 +02004562.4. "spoe-group" section
457--------------------------
458
459This section can be used to declare a group of SPOE messages. Unlike messages
460referenced in a "spoe-agent" section, messages inside a group are not sent on a
461specific event. The sending must be triggered by TCP or HTTP rules, from the
462HAProxy configuration.
463
464
465spoe-group <name>
466 Create a new SPOE group with the name <name>.
467
468 Arguments :
469 <name> is the name of the SPOE group.
470
471 Here you define a group of SPOE messages that can be referenced in a
472 "spoe-agent" section. Following keywords are supported :
473 - messages
474
475 See also: "spoe-agent" and "spoe-message" sections.
476
477
478messages <msg-name> ...
479 Declare the list of SPOE messages belonging to the group.
480
481 Arguments :
482 <msg-name> is the name of a SPOE message.
483
484 Messages declared here must be found in the same engine scope, else an error
485 is triggered during the configuration parsing. Furthermore, a message belongs
486 at most to a group. You can have many "messages" lines.
487
488 See also: "spoe-message" section.
489
490
4912.5. Example
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200492-------------
493
494Here is a simple but complete example that sends client-ip address to a ip
495reputation service. This service can set the variable "ip_score" which is an
496integer between 0 and 100, indicating its reputation (100 means totally safe
497and 0 a blacklisted IP with no doubt).
498
499 ###
500 ### HAProxy configuration
501 frontend www
502 mode http
503 bind *:80
504
505 filter spoe engine ip-reputation config spoe-ip-reputation.conf
506
507 # Reject connection if the IP reputation is under 20
508 tcp-request content reject if { var(sess.iprep.ip_score) -m int lt 20 }
509
510 default_backend http-servers
511
512 backend http-servers
513 mode http
514 server http A.B.C.D:80
515
516 backend iprep-servers
517 mode tcp
518 balance roundrobin
519
520 timeout connect 5s # greater than hello timeout
521 timeout server 3m # greater than idle timeout
522
523 server iprep1 A1.B1.C1.D1:12345
524 server iprep2 A2.B2.C2.D2:12345
525
526 ####
527 ### spoe-ip-reputation.conf
528 [ip-reputation]
529
530 spoe-agent iprep-agent
531 messages get-ip-reputation
532
533 option var-prefix iprep
534
Christopher Faulet03a34492016-11-19 16:47:56 +0100535 timeout hello 2s
536 timeout idle 2m
537 timeout processing 10ms
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200538
539 use-backend iprep-servers
540
541 spoe-message get-ip-reputation
542 args ip=src
Christopher Faulet57583e42017-09-04 15:41:09 +0200543 event on-client-session if ! { src -f /etc/haproxy/whitelist.lst }
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200544
545
5463. SPOP specification
547----------------------
548
5493.1. Data types
550----------------
551
552Here is the bytewise representation of typed data:
553
554 TYPED-DATA : <TYPE:4 bits><FLAGS:4 bits><DATA>
555
556Supported types and their representation are:
557
558 TYPE | ID | DESCRIPTION
559 -----------------------------+-----+----------------------------------
560 NULL | 0 | NULL : <0>
561 Boolean | 1 | BOOL : <1+FLAG>
562 32bits signed integer | 2 | INT32 : <2><VALUE:varint>
563 32bits unsigned integer | 3 | UINT32 : <3><VALUE:varint>
564 64bits signed integer | 4 | INT64 : <4><VALUE:varint>
565 32bits unsigned integer | 5 | UNIT64 : <5><VALUE:varint>
566 IPV4 | 6 | IPV4 : <6><STRUCT IN_ADDR:4 bytes>
567 IPV6 | 7 | IPV6 : <7><STRUCT IN_ADDR6:16 bytes>
568 String | 8 | STRING : <8><LENGTH:varint><BYTES>
569 Binary | 9 | BINARY : <9><LENGTH:varint><BYTES>
570 10 -> 15 unused/reserved | - | -
571 -----------------------------+-----+----------------------------------
572
573Variable-length integer (varint) are encoded using Peers encoding:
574
575
576 0 <= X < 240 : 1 byte (7.875 bits) [ XXXX XXXX ]
577 240 <= X < 2288 : 2 bytes (11 bits) [ 1111 XXXX ] [ 0XXX XXXX ]
578 2288 <= X < 264432 : 3 bytes (18 bits) [ 1111 XXXX ] [ 1XXX XXXX ] [ 0XXX XXXX ]
579 264432 <= X < 33818864 : 4 bytes (25 bits) [ 1111 XXXX ] [ 1XXX XXXX ]*2 [ 0XXX XXXX ]
580 33818864 <= X < 4328786160 : 5 bytes (32 bits) [ 1111 XXXX ] [ 1XXX XXXX ]*3 [ 0XXX XXXX ]
581 ...
582
583For booleans, the value (true or false) is the first bit in the FLAGS
584bitfield. if this bit is set to 0, then the boolean is evaluated as false,
585otherwise, the boolean is evaluated as true.
586
5873.2. Frames
588------------
589
590Exchange between HAProxy and agents are made using FRAME packets. All frames
591must be prefixed with their size encoded on 4 bytes in network byte order:
592
593 <FRAME-LENGTH:4 bytes> <FRAME>
594
595A frame always starts with its type, on one byte, followed by metadata
596containing flags, on 4 bytes and a two variable-length integer representing the
597stream identifier and the frame identifier inside the stream:
598
599 FRAME : <FRAME-TYPE:1 byte> <METADATA> <FRAME-PAYLOAD>
600 METADATA : <FLAGS:4 bytes> <STREAM-ID:varint> <FRAME-ID:varint>
601
602Then comes the frame payload. Depending on the frame type, the payload can be
603of three types: a simple key/value list, a list of messages or a list of
604actions.
605
606 FRAME-PAYLOAD : <LIST-OF-MESSAGES> | <LIST-OF-ACTIONS> | <KV-LIST>
607
608 LIST-OF-MESSAGES : [ <MESSAGE-NAME> <NB-ARGS:1 byte> <KV-LIST> ... ]
609 MESSAGE-NAME : <STRING>
610
611 LIST-OF-ACTIONS : [ <ACTION-TYPE:1 byte> <NB-ARGS:1 byte> <ACTION-ARGS> ... ]
612 ACTION-ARGS : [ <TYPED-DATA>... ]
613
614 KV-LIST : [ <KV-NAME> <KV-VALUE> ... ]
615 KV-NAME : <STRING>
616 KV-VALUE : <TYPED-DATA>
617
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100618 FLAGS : 0 1 2-31
619 +---+---+----------+
620 | | A | |
621 | F | B | |
622 | I | O | RESERVED |
623 | N | R | |
624 | | T | |
625 +---+---+----------+
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200626
627 FIN: Indicates that this is the final payload fragment. The first fragment
628 may also be the final fragment.
629
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100630 ABORT: Indicates that the processing of the current frame must be
631 cancelled. This bit should be set on frames with a fragmented
632 payload. It can be ignore for frames with an unfragemnted
633 payload. When it is set, the FIN bit must also be set.
634
635
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200636Frames cannot exceed a maximum size negociated between HAProxy and agents
637during the HELLO handshake. Most of time, payload will be small enough to send
638it in one frame. But when supported by the peer, it will be possible to
639fragment huge payload on many frames. This ability is announced during the
640HELLO handshake and it can be asynmetric (supported by agents but not by
641HAProxy or the opposite). The following rules apply to fragmentation:
642
643 * An unfragemnted payload consists of a single frame with the FIN bit set.
644
645 * A fragemented payload consists of several frames with the FIN bit clear and
646 terminated by a single frame with the FIN bit set. All these frames must
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100647 share the same STREAM-ID and FRAME-ID. The first frame must set the right
648 FRAME-TYPE (e.g, NOTIFY). The following frames must have an unset type (0).
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200649
650Beside the support of fragmented payload by a peer, some payload must not be
651fragmented. See below for details.
652
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100653IMPORTANT : The maximum size supported by peers for a frame must be greater
654than or equal to 256 bytes.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200655
6563.2.1. Frame capabilities
657--------------------------
658
659Here are the list of official capabilities that HAProxy and agents can support:
660
Christopher Fauleta1cda022016-12-21 08:58:06 +0100661 * fragmentation: This is the ability for a peer to support fragmented
662 payload in received frames. This is an asymmectical
663 capability, it only concerns the peer that announces
664 it. This is the responsibility to the other peer to use it
665 or not.
666
667 * pipelining: This is the ability for a peer to decouple NOTIFY and ACK
668 frames. This is a symmectical capability. To be used, it must
669 be supported by HAproxy and agents. Unlike HTTP pipelining, the
670 ACK frames can be send in any order, but always on the same TCP
671 connection used for the corresponding NOTIFY frame.
672
673 * async: This ability is similar to the pipelining, but here any TCP
674 connection established between HAProxy and the agent can be used to
675 send ACK frames. if an agent accepts connections from multiple
676 HAProxy, it can use the "engine-id" value to group TCP
677 connections. See details about HAPROXY-HELLO frame.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200678
679Unsupported or unknown capabilities are silently ignored, when possible.
680
6813.2.2. Frame types overview
682----------------------------
683
684Here are types of frame supported by SPOE. Frames sent by HAProxy come first,
685then frames sent by agents :
686
687 TYPE | ID | DESCRIPTION
688 -----------------------------+-----+-------------------------------------
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100689 UNSET | 0 | Used for all frames but the first when a
690 | | payload is fragmented.
691 -----------------------------+-----+-------------------------------------
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200692 HAPROXY-HELLO | 1 | Sent by HAProxy when it opens a
693 | | connection on an agent.
694 | |
695 HAPROXY-DISCONNECT | 2 | Sent by HAProxy when it want to close
696 | | the connection or in reply to an
697 | | AGENT-DISCONNECT frame
698 | |
699 NOTIFY | 3 | Sent by HAProxy to pass information
700 | | to an agent
701 -----------------------------+-----+-------------------------------------
702 AGENT-HELLO | 101 | Reply to a HAPROXY-HELLO frame, when
703 | | the connection is established
704 | |
705 AGENT-DISCONNECT | 102 | Sent by an agent just before closing
706 | | the connection
707 | |
708 ACK | 103 | Sent to acknowledge a NOTIFY frame
709 -----------------------------+-----+-------------------------------------
710
711Unknown frames may be silently skipped.
712
7133.2.3. Workflow
714----------------
715
716 * Successful HELLO handshake:
717
718 HAPROXY AGENT SRV
719 | HAPROXY-HELLO |
Christopher Fauletba7bc162016-11-07 21:07:38 +0100720 | (healthcheck: false) |
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200721 | --------------------------> |
722 | |
723 | AGENT-HELLO |
724 | <-------------------------- |
725 | |
726
Christopher Fauletba7bc162016-11-07 21:07:38 +0100727 * Successful HELLO healthcheck:
728
729 HAPROXY AGENT SRV
730 | HAPROXY-HELLO |
731 | (healthcheck: true) |
732 | --------------------------> |
733 | |
734 | AGENT-HELLO + close() |
735 | <-------------------------- |
736 | |
737
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200738
739 * Error encountered by agent during the HELLO handshake:
740
741 HAPROXY AGENT SRV
742 | HAPROXY-HELLO |
743 | --------------------------> |
744 | |
745 | DISCONNECT + close() |
746 | <-------------------------- |
747 | |
748
749 * Error encountered by HAProxy during the HELLO handshake:
750
751 HAPROXY AGENT SRV
752 | HAPROXY-HELLO |
753 | --------------------------> |
754 | |
755 | AGENT-HELLO |
756 | <-------------------------- |
757 | |
758 | DISCONNECT |
759 | --------------------------> |
760 | |
761 | DISCONNECT + close() |
762 | <-------------------------- |
763 | |
764
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100765 * Notify / Ack exchange (unfragmented payload):
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200766
767 HAPROXY AGENT SRV
768 | NOTIFY |
769 | --------------------------> |
770 | |
771 | ACK |
772 | <-------------------------- |
773 | |
774
Christopher Fauletd1307ce2017-02-27 21:59:39 +0100775 * Notify / Ack exchange (fragmented payload):
776
777 HAPROXY AGENT SRV
778 | NOTIFY (frag 1) |
779 | --------------------------> |
780 | |
781 | UNSET (frag 2) |
782 | --------------------------> |
783 | ... |
784 | UNSET (frag N) |
785 | --------------------------> |
786 | |
787 | ACK |
788 | <-------------------------- |
789 | |
790
791 * Aborted fragmentation of a NOTIFY frame:
792
793 HAPROXY AGENT SRV
794 | ... |
795 | UNSET (frag X) |
796 | --------------------------> |
797 | |
798 | ACK/ABORT |
799 | <-------------------------- |
800 | |
801 | UNSET (frag X+1) |
802 | -----------X |
803 | |
804 | |
805
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200806 * Connection closed by haproxy:
807
808 HAPROXY AGENT SRV
809 | DISCONNECT |
810 | --------------------------> |
811 | |
812 | DISCONNECT + close() |
813 | <-------------------------- |
814 | |
815
816 * Connection closed by agent:
817
818 HAPROXY AGENT SRV
819 | DISCONNECT + close() |
820 | <-------------------------- |
821 | |
822
8233.2.4. Frame: HAPROXY-HELLO
824----------------------------
825
826This frame is the first one exchanged between HAProxy and an agent, when the
827connection is established. The payload of this frame is a KV-LIST. It cannot be
828fragmented. STREAM-ID and FRAME-ID are must be set 0.
829
830Following items are mandatory in the KV-LIST:
831
832 * "supported-versions" <STRING>
833
834 Last SPOP major versions supported by HAProxy. It is a comma-separated list
835 of versions, following the format "Major.Minor". Spaces must be ignored, if
836 any. When a major version is announced by HAProxy, it means it also support
837 all previous minor versions.
838
839 Example: "2.0, 1.5" means HAProxy supports SPOP 2.0 and 1.0 to 1.5
840
841 * "max-frame-size" <UINT32>
842
843 This is the maximum size allowed for a frame. The HAPROXY-HELLO frame must
844 be lower or equal to this value.
845
846 * "capabilities" <STRING>
847
848 This a comma-separated list of capabilities supported by HAProxy. Spaces
849 must be ignored, if any.
850
Christopher Fauletba7bc162016-11-07 21:07:38 +0100851Following optional items can be added in the KV-LIST:
852
853 * "healthcheck" <BOOLEAN>
854
855 If this item is set to TRUE, then the HAPROXY-HELLO frame is sent during a
856 SPOE health check. When set to FALSE, this item can be ignored.
857
Christopher Fauleta1cda022016-12-21 08:58:06 +0100858 * "engine-id" <STRING>
859
860 This is a uniq string that identify a SPOE engine.
861
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200862To finish the HELLO handshake, the agent must return an AGENT-HELLO frame with
863its supported SPOP version, the lower value between its maximum size allowed
864for a frame and the HAProxy one and capabilities it supports. If an error
865occurs or if an incompatibility is detected with the agent configuration, an
866AGENT-DISCONNECT frame must be returned.
867
8683.2.5. Frame: AGENT-HELLO
869--------------------------
870
871This frame is sent in reply to a HAPROXY-HELLO frame to finish a HELLO
872handshake. As for HAPROXY-HELLO frame, STREAM-ID and FRAME-ID are also set
8730. The payload of this frame is a KV-LIST and it cannot be fragmented.
874
875Following items are mandatory in the KV-LIST:
876
877 * "version" <STRING>
878
879 This is the SPOP version the agent supports. It must follow the format
880 "Major.Minor" and it must be lower or equal than one of major versions
881 announced by HAProxy.
882
883 * "max-frame-size" <UINT32>
884
885 This is the maximum size allowed for a frame. It must be lower or equal to
886 the value in the HAPROXY-HELLO frame. This value will be used for all
887 subsequent frames.
888
889 * "capabilities" <STRING>
890
891 This a comma-separated list of capabilities supported by agent. Spaces must
892 be ignored, if any.
893
894At this time, if everything is ok for HAProxy (supported version and valid
895max-frame-size value), the HELLO handshake is successfully completed. Else,
896HAProxy sends a HAPROXY-DISCONNECT frame with the corresponding error.
897
Christopher Fauletba7bc162016-11-07 21:07:38 +0100898If "healthcheck" item was set to TRUE in the HAPROXY-HELLO frame, the agent can
899safely close the connection without DISCONNECT frame. In all cases, HAProxy
900will close the connexion at the end of the health check.
901
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02009023.2.6. Frame: NOTIFY
903---------------------
904
905Information are sent to the agents inside NOTIFY frames. These frames are
906attached to a stream, so STREAM-ID and FRAME-ID must be set. The payload of
907NOTIFY frames is a LIST-OF-MESSAGES and, if supported by agents, it can be
908fragmented.
909
910NOTIFY frames must be acknowledge by agents sending an ACK frame, repeating
911right STREAM-ID and FRAME-ID.
912
9133.2.7. Frame: ACK
914------------------
915
916ACK frames must be sent by agents to reply to NOTIFY frames. STREAM-ID and
917FRAME-ID found in a NOTIFY frame must be reuse in the corresponding ACK
918frame. The payload of ACK frames is a LIST-OF-ACTIONS and, if supported by
919HAProxy, it can be fragmented.
920
9213.2.8. Frame: HAPROXY-DISCONNECT
922---------------------------------
923
924If an error occurs, at anytime, from the HAProxy side, a HAPROXY-DISCONNECT
925frame is sent with information describing the error. HAProxy will wait an
926AGENT-DISCONNECT frame in reply. All other frames will be ignored. The agent
927must then close the socket.
928
929The payload of this frame is a KV-LIST. It cannot be fragmented. STREAM-ID and
930FRAME-ID are must be set 0.
931
932Following items are mandatory in the KV-LIST:
933
934 * "status-code" <UINT32>
935
936 This is the code corresponding to the error.
937
938 * "message" <STRING>
939
940 This is a textual message describing the error.
941
942For more information about known errors, see section "Errors & timeouts"
943
9443.2.9. Frame: AGENT-DISCONNECT
945-------------------------------
946
947If an error occurs, at anytime, from the agent size, a AGENT-DISCONNECT frame
948is sent, with information desribing the error. such frame is also sent in reply
949to a HAPROXY-DISCONNECT. The agent must close the socket just after sending
950this frame.
951
952The payload of this frame is a KV-LIST. It cannot be fragmented. STREAM-ID and
953FRAME-ID are must be set 0.
954
955Following items are mandatory in the KV-LIST:
956
957 * "status-code" <UINT32>
958
959 This is the code corresponding to the error.
960
961 * "message" <STRING>
962
963 This is a textual message describing the error.
964
965For more information about known errors, see section "Errors & timeouts"
966
9673.3. Events & Messages
968-----------------------
969
970Information about streams are sent in NOTIFY frames. You can specify which kind
971of information to send by defining "spoe-message" sections in your SPOE
972configuration file. for each "spoe-message" there will be a message in a NOTIFY
973frame when the right event is triggered.
974
975A NOTIFY frame is sent for an specific event when there is at least one
976"spoe-message" attached to this event. All messages for an event will be added
977in the same NOTIFY frame.
978
979Here is the list of supported events:
980
981 * on-client-session is triggered when a new client session is created.
982 This event is only available for SPOE filters
983 declared in a frontend or a listen section.
984
985 * on-frontend-tcp-request is triggered just before the evaluation of
986 "tcp-request content" rules on the frontend side.
987 This event is only available for SPOE filters
988 declared in a frontend or a listen section.
989
990 * on-backend-tcp-request is triggered just before the evaluation of
991 "tcp-request content" rules on the backend side.
992 This event is skipped for SPOE filters declared
993 in a listen section.
994
995 * on-frontend-http-request is triggered just before the evaluation of
996 "http-request" rules on the frontend side. This
997 event is only available for SPOE filters declared
998 in a frontend or a listen section.
999
1000 * on-backend-http-request is triggered just before the evaluation of
1001 "http-request" rules on the backend side. This
1002 event is skipped for SPOE filters declared in a
1003 listen section.
1004
1005 * on-server-session is triggered when the session with the server is
1006 established.
1007
1008 * on-tcp-response is triggered just before the evaluation of
1009 "tcp-response content" rules.
1010
1011 * on-http-response is triggered just before the evaluation of
1012 "http-response" rules.
1013
1014
1015The stream processing will loop on these events, when triggered, waiting the
1016agent reply.
1017
10183.4. Actions
1019-------------
1020
1021An agent must acknowledge each NOTIFY frame by sending the corresponding ACK
1022frame. Actions can be added in these frames to dynamically take action on the
1023processing of a stream.
1024
1025Here is the list of supported actions:
1026
1027 * set-var set the value for an existing variable. 3 arguments must be
1028 attached to this action: the variable scope (proc, sess, txn,
1029 req or req), the variable name (a string) and its value.
1030
1031 ACTION-SET-VAR : <SET-VAR:1 byte><NB-ARGS:1 byte><VAR-SCOPE:1 byte><VAR-NAME><VAR-VALUE>
1032
1033 SET-VAR : <1>
1034 NB-ARGS : <3>
1035 VAR-SCOPE : <PROCESS> | <SESSION> | <TRANSACTION> | <REQUEST> | <RESPONSE>
1036 VAR-NAME : <STRING>
1037 VAR-VALUE : <TYPED-DATA>
1038
1039 PROCESS : <0>
1040 SESSION : <1>
1041 TRANSACTION : <2>
1042 REQUEST : <3>
Christopher Fauleta1cda022016-12-21 08:58:06 +01001043 RESPONSE : <4>
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02001044
1045 * unset-var unset the value for an existing variable. 2 arguments must be
1046 attached to this action: the variable scope (proc, sess, txn,
1047 req or req) and the variable name (a string).
1048
Christopher Faulet1002aac2016-12-09 17:41:54 +01001049 ACTION-UNSET-VAR : <UNSET-VAR:1 byte><NB-ARGS:1 byte><VAR-SCOPE:1 byte><VAR-NAME>
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02001050
Christopher Faulet1002aac2016-12-09 17:41:54 +01001051 UNSET-VAR : <2>
1052 NB-ARGS : <2>
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02001053 VAR-SCOPE : <PROCESS> | <SESSION> | <TRANSACTION> | <REQUEST> | <RESPONSE>
1054 VAR-NAME : <STRING>
1055
1056 PROCESS : <0>
1057 SESSION : <1>
1058 TRANSACTION : <2>
1059 REQUEST : <3>
Christopher Fauleta1cda022016-12-21 08:58:06 +01001060 RESPONSE : <4>
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02001061
1062
1063NOTE: Name of the variables will be automatically prefixed by HAProxy to avoid
1064 name clashes with other variables used in HAProxy. Moreover, unknown
1065 variable will be silently ignored.
1066
Christopher Fauletd1307ce2017-02-27 21:59:39 +010010673.5. Errors & timeouts
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02001068----------------------
1069
1070Here is the list of all known errors:
1071
1072 STATUS CODE | DESCRIPTION
1073 ----------------+--------------------------------------------------------
1074 0 | normal (no error occurred)
1075 1 | I/O error
1076 2 | A timeout occurred
1077 3 | frame is too big
1078 4 | invalid frame received
1079 5 | version value not found
1080 6 | max-frame-size value not found
1081 7 | capabilities value not found
1082 8 | unsupported version
1083 9 | max-frame-size too big or too small
Christopher Fauletd1307ce2017-02-27 21:59:39 +01001084 10 | payload fragmentation is not supported
1085 11 | invalid interlaced frames
1086 12 | frame-id not found (it does not match any referenced frame)
1087 13 | resource allocation error
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02001088 99 | an unknown error occurrde
1089 ----------------+--------------------------------------------------------
1090
1091An agent can define its own errors using a not yet assigned status code.
1092
Christopher Fauletea62c2a2016-11-14 10:54:21 +01001093IMPORTANT NOTE: By default, for a specific stream, when an abnormal/unexpected
1094 error occurs, the SPOE is disabled for all the transaction. So
1095 if you have several events configured, such error on an event
1096 will disabled all followings. For TCP streams, this will
1097 disable the SPOE for the whole session. For HTTP streams, this
1098 will disable it for the transaction (request and response).
1099 See 'option continue-on-error' to bypass this limitation.
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +02001100
1101To avoid a stream to wait infinitly, you must carefully choose the
1102acknowledgement timeout. In most of cases, it will be quiet low. But it depends
1103on the responsivness of your service.
1104
1105You must also choose idle timeout carefully. Because connection with your
1106service depends on the backend configuration used by the SPOA, it is important
1107to use a lower value for idle timeout than the server timeout. Else the
1108connection will be closed by HAProxy. The same is true for hello timeout. You
1109should choose a lower value than the connect timeout.
1110
1111
1112/*
1113 * Local variables:
1114 * fill-column: 79
1115 * End:
1116 */