/* * include/haproxy/spoe-t.h * Macros, variables and structures for the SPOE filter. * * Copyright (C) 2017 HAProxy Technologies, Christopher Faulet * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, version 2.1 * exclusively. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _HAPROXY_SPOE_T_H #define _HAPROXY_SPOE_T_H #include #include #include #include #include #include #include #include #include #include /* Type of list of messages */ #define SPOE_MSGS_BY_EVENT 0x01 #define SPOE_MSGS_BY_GROUP 0x02 /* Flags set on the SPOE agent */ #define SPOE_FL_CONT_ON_ERR 0x00000001 /* Do not stop events processing when an error occurred */ #define SPOE_FL_PIPELINING 0x00000002 /* Set when SPOE agent supports pipelining (set by default) */ #define SPOE_FL_ASYNC 0x00000004 /* Set when SPOE agent supports async (set by default) */ #define SPOE_FL_SND_FRAGMENTATION 0x00000008 /* Set when SPOE agent supports sending fragmented payload */ #define SPOE_FL_RCV_FRAGMENTATION 0x00000010 /* Set when SPOE agent supports receiving fragmented payload */ #define SPOE_FL_FORCE_SET_VAR 0x00000020 /* Set when SPOE agent will set all variables from agent (and not only known variables) */ /* Flags set on the SPOE context */ #define SPOE_CTX_FL_CLI_CONNECTED 0x00000001 /* Set after that on-client-session event was processed */ #define SPOE_CTX_FL_SRV_CONNECTED 0x00000002 /* Set after that on-server-session event was processed */ #define SPOE_CTX_FL_REQ_PROCESS 0x00000004 /* Set when SPOE is processing the request */ #define SPOE_CTX_FL_RSP_PROCESS 0x00000008 /* Set when SPOE is processing the response */ #define SPOE_CTX_FL_FRAGMENTED 0x00000010 /* Set when a fragmented frame is processing */ #define SPOE_CTX_FL_PROCESS (SPOE_CTX_FL_REQ_PROCESS|SPOE_CTX_FL_RSP_PROCESS) /* Flags set on the SPOE applet */ #define SPOE_APPCTX_FL_PIPELINING 0x00000001 /* Set if pipelining is supported */ #define SPOE_APPCTX_FL_ASYNC 0x00000002 /* Set if asynchronous frames is supported */ #define SPOE_APPCTX_FL_FRAGMENTATION 0x00000004 /* Set if fragmentation is supported */ #define SPOE_APPCTX_ERR_NONE 0x00000000 /* no error yet, leave it to zero */ #define SPOE_APPCTX_ERR_TOUT 0x00000001 /* SPOE applet timeout */ /* Flags set on the SPOE frame */ #define SPOE_FRM_FL_FIN 0x00000001 #define SPOE_FRM_FL_ABRT 0x00000002 /* Masks to get data type or flags value */ #define SPOE_DATA_T_MASK 0x0F #define SPOE_DATA_FL_MASK 0xF0 /* Flags to set Boolean values */ #define SPOE_DATA_FL_FALSE 0x00 #define SPOE_DATA_FL_TRUE 0x10 /* All possible states for a SPOE context */ enum spoe_ctx_state { SPOE_CTX_ST_NONE = 0, SPOE_CTX_ST_READY, SPOE_CTX_ST_ENCODING_MSGS, SPOE_CTX_ST_SENDING_MSGS, SPOE_CTX_ST_WAITING_ACK, SPOE_CTX_ST_DONE, SPOE_CTX_ST_ERROR, }; /* All possible states for a SPOE applet */ enum spoe_appctx_state { SPOE_APPCTX_ST_CONNECT = 0, SPOE_APPCTX_ST_CONNECTING, SPOE_APPCTX_ST_IDLE, SPOE_APPCTX_ST_PROCESSING, SPOE_APPCTX_ST_SENDING_FRAG_NOTIFY, SPOE_APPCTX_ST_WAITING_SYNC_ACK, SPOE_APPCTX_ST_DISCONNECT, SPOE_APPCTX_ST_DISCONNECTING, SPOE_APPCTX_ST_EXIT, SPOE_APPCTX_ST_END, }; /* All supported SPOE actions */ enum spoe_action_type { SPOE_ACT_T_SET_VAR = 1, SPOE_ACT_T_UNSET_VAR, SPOE_ACT_TYPES, }; /* All supported SPOE events */ enum spoe_event { SPOE_EV_NONE = 0, /* Request events */ SPOE_EV_ON_CLIENT_SESS = 1, SPOE_EV_ON_TCP_REQ_FE, SPOE_EV_ON_TCP_REQ_BE, SPOE_EV_ON_HTTP_REQ_FE, SPOE_EV_ON_HTTP_REQ_BE, /* Response events */ SPOE_EV_ON_SERVER_SESS, SPOE_EV_ON_TCP_RSP, SPOE_EV_ON_HTTP_RSP, SPOE_EV_EVENTS }; /* Errors triggered by streams */ enum spoe_context_error { SPOE_CTX_ERR_NONE = 0, SPOE_CTX_ERR_TOUT, SPOE_CTX_ERR_RES, SPOE_CTX_ERR_TOO_BIG, SPOE_CTX_ERR_FRAG_FRAME_ABRT, SPOE_CTX_ERR_INTERRUPT, SPOE_CTX_ERR_UNKNOWN = 255, SPOE_CTX_ERRS, }; /* Errors triggered by SPOE applet */ enum spoe_frame_error { SPOE_FRM_ERR_NONE = 0, SPOE_FRM_ERR_IO, SPOE_FRM_ERR_TOUT, SPOE_FRM_ERR_TOO_BIG, SPOE_FRM_ERR_INVALID, SPOE_FRM_ERR_NO_VSN, SPOE_FRM_ERR_NO_FRAME_SIZE, SPOE_FRM_ERR_NO_CAP, SPOE_FRM_ERR_BAD_VSN, SPOE_FRM_ERR_BAD_FRAME_SIZE, SPOE_FRM_ERR_FRAG_NOT_SUPPORTED, SPOE_FRM_ERR_INTERLACED_FRAMES, SPOE_FRM_ERR_FRAMEID_NOTFOUND, SPOE_FRM_ERR_RES, SPOE_FRM_ERR_UNKNOWN = 99, SPOE_FRM_ERRS, }; /* Scopes used for variables set by agents. It is a way to be agnotic to vars * scope. */ enum spoe_vars_scope { SPOE_SCOPE_PROC = 0, /* <=> SCOPE_PROC */ SPOE_SCOPE_SESS, /* <=> SCOPE_SESS */ SPOE_SCOPE_TXN, /* <=> SCOPE_TXN */ SPOE_SCOPE_REQ, /* <=> SCOPE_REQ */ SPOE_SCOPE_RES, /* <=> SCOPE_RES */ }; /* Frame Types sent by HAProxy and by agents */ enum spoe_frame_type { SPOE_FRM_T_UNSET = 0, /* Frames sent by HAProxy */ SPOE_FRM_T_HAPROXY_HELLO = 1, SPOE_FRM_T_HAPROXY_DISCON, SPOE_FRM_T_HAPROXY_NOTIFY, /* Frames sent by the agents */ SPOE_FRM_T_AGENT_HELLO = 101, SPOE_FRM_T_AGENT_DISCON, SPOE_FRM_T_AGENT_ACK }; /* All supported data types */ enum spoe_data_type { SPOE_DATA_T_NULL = 0, SPOE_DATA_T_BOOL, SPOE_DATA_T_INT32, SPOE_DATA_T_UINT32, SPOE_DATA_T_INT64, SPOE_DATA_T_UINT64, SPOE_DATA_T_IPV4, SPOE_DATA_T_IPV6, SPOE_DATA_T_STR, SPOE_DATA_T_BIN, SPOE_DATA_TYPES }; /* Describe an argument that will be linked to a message. It is a sample fetch, * with an optional name. */ struct spoe_arg { char *name; /* Name of the argument, may be NULL */ unsigned int name_len; /* The name length, 0 if NULL */ struct sample_expr *expr; /* Sample expression */ struct list list; /* Used to chain SPOE args */ }; /* Used during the config parsing only because, when a SPOE agent section is * parsed, messages/groups can be undefined. */ struct spoe_placeholder { char *id; /* SPOE placeholder id */ struct list list; /* Use to chain SPOE placeholders */ }; /* Used during the config parsing, when SPOE agent section is parsed, to * register some variable names. */ struct spoe_var_placeholder { char *name; /* The variable name */ struct list list; /* Use to chain SPOE var placeholders */ }; /* Describe a message that will be sent in a NOTIFY frame. A message has a name, * an argument list (see above) and it is linked to a specific event. */ struct spoe_message { char *id; /* SPOE message id */ unsigned int id_len; /* The message id length */ struct spoe_agent *agent; /* SPOE agent owning this SPOE message */ struct spoe_group *group; /* SPOE group owning this SPOE message (can be NULL) */ struct { char *file; /* file where the SPOE message appears */ int line; /* line where the SPOE message appears */ } conf; /* config information */ unsigned int nargs; /* # of arguments */ struct list args; /* Arguments added when the SPOE messages is sent */ struct list list; /* Used to chain SPOE messages */ struct list by_evt; /* By event list */ struct list by_grp; /* By group list */ struct list acls; /* ACL declared on this message */ struct acl_cond *cond; /* acl condition to meet */ enum spoe_event event; /* SPOE_EV_* */ }; /* Describe a group of messages that will be sent in a NOTIFY frame. A group has * a name and a list of messages. It can be used by HAProxy, outside events * processing, mainly in (tcp|http) rules. */ struct spoe_group { char *id; /* SPOE group id */ struct spoe_agent *agent; /* SPOE agent owning this SPOE group */ struct { char *file; /* file where the SPOE group appears */ int line; /* line where the SPOE group appears */ } conf; /* config information */ struct list phs; /* List of placeholders used during conf parsing */ struct list messages; /* List of SPOE messages that will be sent by this * group */ struct list list; /* Used to chain SPOE groups */ }; /* Describe a SPOE agent. */ struct spoe_agent { char *id; /* SPOE agent id (name) */ struct { char *file; /* file where the SPOE agent appears */ int line; /* line where the SPOE agent appears */ } conf; /* config information */ union { struct proxy *be; /* Backend used by this agent */ char *name; /* Backend name used during conf parsing */ } b; struct { unsigned int hello; /* Max time to receive AGENT-HELLO frame (in SPOE applet) */ unsigned int idle; /* Max Idle timeout (in SPOE applet) */ unsigned int processing; /* Max time to process an event (in the main stream) */ } timeout; /* Config info */ struct spoe_config *spoe_conf; /* SPOE filter config */ char *var_pfx; /* Prefix used for vars set by the agent */ char *var_on_error; /* Variable to set when an error occurred, in the TXN scope */ char *var_t_process; /* Variable to set to report the processing time of the last event/group, in the TXN scope */ char *var_t_total; /* Variable to set to report the cumulative processing time, in the TXN scope */ unsigned int flags; /* SPOE_FL_* */ unsigned int cps_max; /* Maximum # of connections per second */ unsigned int eps_max; /* Maximum # of errors per second */ unsigned int max_frame_size; /* Maximum frame size for this agent, before any negotiation */ unsigned int max_fpa; /* Maximum # of frames handled per applet at once */ struct list events[SPOE_EV_EVENTS]; /* List of SPOE messages that will be sent * for each supported events */ struct list groups; /* List of available SPOE groups */ struct list messages; /* list of all messages attached to this SPOE agent */ /* running info */ struct { char *engine_id; /* engine-id string */ unsigned int frame_size; /* current maximum frame size, only used to encode messages */ unsigned int processing; struct freq_ctr processing_per_sec; struct freq_ctr conn_per_sec; /* connections per second */ struct freq_ctr err_per_sec; /* connection errors per second */ unsigned int idles; /* # of idle applets */ struct eb_root idle_applets; /* idle SPOE applets available to process data */ struct list applets; /* all SPOE applets for this agent */ struct list sending_queue; /* Queue of streams waiting to send data */ struct list waiting_queue; /* Queue of streams waiting for a ack, in async mode */ __decl_thread(HA_SPINLOCK_T lock); } *rt; struct { unsigned int applets; /* # of SPOE applets */ unsigned int idles; /* # of idle applets */ unsigned int nb_sending; /* # of streams waiting to send data */ unsigned int nb_waiting; /* # of streams waiting for a ack */ unsigned long long nb_processed; /* # of frames processed by the SPOE */ unsigned long long nb_errors; /* # of errors during the processing */ } counters; }; /* SPOE filter configuration */ struct spoe_config { char *id; /* The SPOE engine name. If undefined in HAProxy config, * it will be set with the SPOE agent name */ struct proxy *proxy; /* Proxy owning the filter */ struct spoe_agent *agent; /* Agent used by this filter */ struct proxy agent_fe; /* Agent frontend */ }; /* SPOE context attached to a stream. It is the main structure that handles the * processing offload */ struct spoe_context { struct filter *filter; /* The SPOE filter */ struct stream *strm; /* The stream that should be offloaded */ struct list *events; /* List of messages that will be sent during the stream processing */ struct list *groups; /* List of available SPOE group */ struct buffer buffer; /* Buffer used to store a encoded messages */ struct buffer_wait buffer_wait; /* position in the list of resources waiting for a buffer */ struct list list; enum spoe_ctx_state state; /* SPOE_CTX_ST_* */ unsigned int flags; /* SPOE_CTX_FL_* */ unsigned int status_code; /* SPOE_CTX_ERR_* */ unsigned int stream_id; /* stream_id and frame_id are used */ unsigned int frame_id; /* to map NOTIFY and ACK frames */ unsigned int process_exp; /* expiration date to process an event */ struct spoe_appctx *spoe_appctx; /* SPOE appctx sending the current frame */ struct { struct spoe_message *curmsg; /* SPOE message from which to resume encoding */ struct spoe_arg *curarg; /* SPOE arg in from which to resume encoding */ unsigned int curoff; /* offset in from which to resume encoding */ unsigned int curlen; /* length of need to be encode, for SMP_F_MAY_CHANGE data */ unsigned int flags; /* SPOE_FRM_FL_* */ } frag_ctx; /* Info about fragmented frames, valid on if SPOE_CTX_FL_FRAGMENTED is set */ struct { ullong start_ts; /* start date of the current event/group */ ullong request_ts; /* date the frame processing starts (reset for each frag) */ ullong queue_ts; /* date the frame is queued (reset for each frag) */ ullong wait_ts; /* date the stream starts waiting for a response */ ullong response_ts; /* date the response processing starts */ long t_request; /* delay to encode and push the frame in queue (cumulative for frags) */ long t_queue; /* delay before the frame gets out the sending queue (cumulative for frags) */ long t_waiting; /* delay before the response is received */ long t_response; /* delay to process the response (from the stream pov) */ long t_process; /* processing time of the last event/group */ unsigned long t_total; /* cumulative processing time */ } stats; /* Stats for this stream */ }; /* SPOE context inside a appctx */ struct spoe_appctx { struct appctx *owner; /* the owner */ struct task *task; /* task to handle applet timeouts */ struct spoe_agent *agent; /* agent on which the applet is attached */ unsigned int version; /* the negotiated version */ unsigned int max_frame_size; /* the negotiated max-frame-size value */ unsigned int flags; /* SPOE_APPCTX_FL_* */ unsigned int status_code; /* SPOE_FRM_ERR_* */ #if defined(DEBUG_SPOE) || defined(DEBUG_FULL) char *reason; /* Error message, used for debugging only */ int rlen; /* reason length */ #endif struct buffer buffer; /* Buffer used to store a encoded messages */ struct buffer_wait buffer_wait; /* position in the list of resources waiting for a buffer */ struct list waiting_queue; /* list of streams waiting for a ACK frame, in sync and pipelining mode */ struct list list; /* next spoe appctx for the same agent */ struct eb32_node node; /* node used for applets tree */ unsigned int cur_fpa; struct { struct spoe_context *ctx; /* SPOE context owning the fragmented frame */ unsigned int cursid; /* stream-id of the fragmented frame. used if the processing is aborted */ unsigned int curfid; /* frame-id of the fragmented frame. used if the processing is aborted */ } frag_ctx; /* Info about fragmented frames, unused for unfragmented frames */ }; #endif /* _HAPROXY_SPOE_T_H */