From: Christopher Faulet Date: Tue, 9 Jul 2024 09:01:59 +0000 (+0200) Subject: MEDIUM: spoe: Directly xfer NOTIFY frame when SPOE applet is created X-Git-Tag: v3.1-dev4~67 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=07cf7769ce31f0fd4bb29b4f1389a2a8d0e01f4d;p=thirdparty%2Fhaproxy.git MEDIUM: spoe: Directly xfer NOTIFY frame when SPOE applet is created Instead of using a buffer from the SPOE filter to store the NOTIFY frame, to copy it in a trash buffer in the SPOE applet to add meta-data and then tranfer it to the channel, the original buffer is directly transfered to the channel during the SPOE applet creation. The SPOE applet is thus simplied, the I/O handler is now only responsible to retrieve the ACK reply. The related issue is #2502. --- diff --git a/src/flt_spoe.c b/src/flt_spoe.c index d91002730f..f640e6935a 100644 --- a/src/flt_spoe.c +++ b/src/flt_spoe.c @@ -74,8 +74,7 @@ enum spoe_ctx_state { /* All possible states for a SPOE applet */ enum spoe_appctx_state { - SPOE_APPCTX_ST_PROCESSING = 0, - SPOE_APPCTX_ST_WAITING_SYNC_ACK, + SPOE_APPCTX_ST_WAITING_ACK = 0, SPOE_APPCTX_ST_EXIT, SPOE_APPCTX_ST_END, }; @@ -266,7 +265,7 @@ struct flt_ops spoe_ops; static int spoe_acquire_buffer(struct buffer *buf, struct buffer_wait *buffer_wait); static void spoe_release_buffer(struct buffer *buf, struct buffer_wait *buffer_wait); -static struct appctx *spoe_create_appctx(struct spoe_config *conf); +static struct appctx *spoe_create_appctx(struct spoe_context *ctx); /******************************************************************** * helper functions/globals @@ -371,38 +370,8 @@ static inline void spoe_update_stat_time(ullong *since, long *t) } /******************************************************************** - * Functions that encode/decode SPOE frames + * Functions that decode SPOE frames ********************************************************************/ - -/* Encode the NOTIFY frame sent by HAProxy to an agent. It returns the number of - * encoded bytes in the frame on success, 0 if an encoding error occurred and -1 - * if a fatal error occurred. */ -static int spoe_prepare_hanotify_frame(struct appctx *appctx, char *frame, size_t size) -{ - char *p, *end; - size_t sz; - - p = frame; - end = frame+size; - - /* Set Frame type */ - *p++ = SPOP_FRM_T_HAPROXY_NOTIFY; - - /* Copy encoded messages, if possible */ - sz = b_data(&SPOE_APPCTX(appctx)->spoe_ctx->buffer); - if (p + sz >= end) - goto too_big; - memcpy(p, b_head(&SPOE_APPCTX(appctx)->spoe_ctx->buffer), sz); - b_del(&SPOE_APPCTX(appctx)->spoe_ctx->buffer, sz); - p += sz; - - return (p - frame); - - too_big: - SPOE_APPCTX(appctx)->status_code = SPOP_ERR_TOO_BIG; - return 0; -} - /* Decode ACK frame sent by an agent. It returns the number of read bytes on * success, 0 if the frame can be ignored and -1 if an error occurred. */ static int spoe_handle_agentack_frame(struct appctx *appctx, char *frame, size_t size) @@ -428,19 +397,6 @@ static int spoe_handle_agentack_frame(struct appctx *appctx, char *frame, size_t return (p - frame); } -/* Send a SPOE frame to an agent. It returns -1 when an error occurred, 0 when - * the frame can be ignored, 1 to retry later, and the frame length on - * success. */ -static int spoe_send_frame(struct appctx *appctx, char *buf, size_t framesz) -{ - int ret; - - ret = applet_putblk(appctx, buf, framesz); - if (ret <= 0) - return 1; /* retry */ - return framesz; -} - /* Receive a SPOE frame from an agent. It return -1 when an error occurred, 0 * when the frame can be ignored, 1 to retry later and the frame length on * success. */ @@ -493,7 +449,7 @@ static int spoe_init_appctx(struct appctx *appctx) struct spoe_agent *agent = spoe_appctx->agent; struct stream *s; - if (appctx_finalize_startup(appctx, &agent->fe, &BUF_NULL) == -1) + if (appctx_finalize_startup(appctx, &agent->fe, &spoe_appctx->spoe_ctx->buffer) == -1) goto error; spoe_appctx->owner = appctx; @@ -511,7 +467,7 @@ static int spoe_init_appctx(struct appctx *appctx) s->do_log = NULL; s->scb->flags |= SC_FL_RCV_ONCE; - appctx->st0 = SPOE_APPCTX_ST_PROCESSING; + appctx->st0 = SPOE_APPCTX_ST_WAITING_ACK; appctx_wakeup(appctx); return 0; @@ -563,51 +519,6 @@ static void spoe_release_appctx(struct appctx *appctx) pool_free(pool_head_spoe_appctx, spoe_appctx); } - -static int spoe_handle_sending_frame_appctx(struct appctx *appctx) -{ - char *frame, *buf; - int ret; - - /* 4 bytes are reserved at the beginning of to store the frame - * length. */ - buf = trash.area; frame = buf; - - if (!SPOE_APPCTX(appctx)->spoe_ctx) { - appctx->st0 = SPOE_APPCTX_ST_EXIT; - ret = -1; - goto end; - } - ret = spoe_prepare_hanotify_frame(appctx, frame, SPOE_APPCTX(appctx)->max_frame_size); - if (ret > 1) - ret = spoe_send_frame(appctx, buf, ret); - - switch (ret) { - case -1: /* error */ - case 0: /* ignore */ - spoe_release_buffer(&SPOE_APPCTX(appctx)->spoe_ctx->buffer, &SPOE_APPCTX(appctx)->spoe_ctx->buffer_wait); - SPOE_APPCTX(appctx)->spoe_ctx->spoe_appctx = NULL; - SPOE_APPCTX(appctx)->spoe_ctx->state = SPOE_CTX_ST_ERROR; - SPOE_APPCTX(appctx)->spoe_ctx->status_code = (SPOE_APPCTX(appctx)->status_code + 0x100); - task_wakeup(SPOE_APPCTX(appctx)->spoe_ctx->strm->task, TASK_WOKEN_MSG); - SPOE_APPCTX(appctx)->spoe_ctx = NULL; - appctx->st0 = SPOE_APPCTX_ST_EXIT; - break; - - case 1: /* retry */ - break; - - default: - spoe_release_buffer(&SPOE_APPCTX(appctx)->spoe_ctx->buffer, &SPOE_APPCTX(appctx)->spoe_ctx->buffer_wait); - SPOE_APPCTX(appctx)->spoe_ctx->state = SPOE_CTX_ST_WAITING_ACK; - appctx->st0 = SPOE_APPCTX_ST_WAITING_SYNC_ACK; - break; - } - - end: - return ret; -} - static int spoe_handle_receiving_frame_appctx(struct appctx *appctx) { char *frame; @@ -622,16 +533,12 @@ static int spoe_handle_receiving_frame_appctx(struct appctx *appctx) switch (ret) { case -1: /* error */ spoe_release_buffer(&SPOE_APPCTX(appctx)->spoe_ctx->buffer, &SPOE_APPCTX(appctx)->spoe_ctx->buffer_wait); - SPOE_APPCTX(appctx)->spoe_ctx->spoe_appctx = NULL; SPOE_APPCTX(appctx)->spoe_ctx->state = SPOE_CTX_ST_ERROR; SPOE_APPCTX(appctx)->spoe_ctx->status_code = (SPOE_APPCTX(appctx)->status_code + 0x100); - task_wakeup(SPOE_APPCTX(appctx)->spoe_ctx->strm->task, TASK_WOKEN_MSG); - SPOE_APPCTX(appctx)->spoe_ctx = NULL; - appctx->st0 = SPOE_APPCTX_ST_EXIT; - break; + goto exit; case 0: /* ignore */ - break; + goto out; case 1: /* retry */ goto end; @@ -640,62 +547,24 @@ static int spoe_handle_receiving_frame_appctx(struct appctx *appctx) SPOE_APPCTX(appctx)->spoe_ctx->buffer = SPOE_APPCTX(appctx)->buffer; SPOE_APPCTX(appctx)->buffer = BUF_NULL; SPOE_APPCTX(appctx)->spoe_ctx->state = SPOE_CTX_ST_DONE; - SPOE_APPCTX(appctx)->spoe_ctx->spoe_appctx = NULL; - task_wakeup(SPOE_APPCTX(appctx)->spoe_ctx->strm->task, TASK_WOKEN_MSG); - SPOE_APPCTX(appctx)->spoe_ctx = NULL; - appctx->st0 = SPOE_APPCTX_ST_EXIT; - ret = -1; + goto exit; } + out: /* Do not forget to remove processed frame from the output buffer */ if (trash.data) co_skip(sc_oc(appctx_sc(appctx)), trash.data); + end: return ret; -} -static int spoe_handle_processing_appctx(struct appctx *appctx) -{ - int ret; - - /* receiving_frame loop */ - while (1) { - ret = spoe_handle_receiving_frame_appctx(appctx); - switch (ret) { - case -1: /* error */ - goto next; - case 0: /* ignore */ - break; - case 1: /* retry */ - goto send; - default: - break; - } - } - - send: - if (appctx->st0 == SPOE_APPCTX_ST_WAITING_SYNC_ACK) - goto end; - - ret = spoe_handle_sending_frame_appctx(appctx); - switch (ret) { - case -1: /* error */ - goto next; - - case 0: /* ignore */ - break; - - case 1: /* retry */ - break; - - default: - - break; - } - end: - return 1; - next: - return 0; + exit: + SPOE_APPCTX(appctx)->spoe_ctx->spoe_appctx = NULL; + task_wakeup(SPOE_APPCTX(appctx)->spoe_ctx->strm->task, TASK_WOKEN_MSG); + SPOE_APPCTX(appctx)->spoe_ctx = NULL; + appctx->st0 = SPOE_APPCTX_ST_EXIT; + ret = 0; + goto out; } /* I/O Handler processing messages exchanged with the agent */ @@ -717,9 +586,9 @@ static void spoe_handle_appctx(struct appctx *appctx) switchstate: switch (appctx->st0) { - case SPOE_APPCTX_ST_PROCESSING: - case SPOE_APPCTX_ST_WAITING_SYNC_ACK: - if (spoe_handle_processing_appctx(appctx)) + /* case SPOE_APPCTX_ST_PROCESSING: */ + case SPOE_APPCTX_ST_WAITING_ACK: + if (spoe_handle_receiving_frame_appctx(appctx)) break; goto switchstate; @@ -749,8 +618,9 @@ struct applet spoe_applet = { /* Create a SPOE applet. On success, the created applet is returned, else * NULL. */ -static struct appctx *spoe_create_appctx(struct spoe_config *conf) +static struct appctx *spoe_create_appctx(struct spoe_context *ctx) { + struct spoe_config *conf = FLT_CONF(ctx->filter); struct spoe_agent *agent = conf->agent; struct spoe_appctx *spoe_appctx; struct appctx *appctx; @@ -765,7 +635,8 @@ static struct appctx *spoe_create_appctx(struct spoe_config *conf) spoe_appctx->flags = 0; spoe_appctx->status_code = SPOP_ERR_NONE; spoe_appctx->buffer = BUF_NULL; - + spoe_appctx->spoe_ctx = ctx; + ctx->spoe_appctx = spoe_appctx; if ((appctx = appctx_new_here(&spoe_applet, NULL)) == NULL) goto out_free_spoe_appctx; @@ -860,6 +731,9 @@ static int spoe_encode_messages(struct stream *s, struct spoe_context *ctx, p = b_head(&ctx->buffer); end = p + agent->max_frame_size - SPOP_FRAME_HDR_SIZE; + /* Set Frame type */ + *p++ = SPOP_FRM_T_HAPROXY_NOTIFY; + if (type == SPOE_MSGS_BY_EVENT) { /* Loop on messages by event */ list_for_each_entry(msg, messages, by_evt) { if (spoe_encode_message(s, ctx, msg, dir, &p, end) == -1) @@ -1195,13 +1069,11 @@ static int spoe_process_messages(struct stream *s, struct spoe_context *ctx, goto end; if (!ret) goto skip; - appctx = spoe_create_appctx(conf); + appctx = spoe_create_appctx(ctx); if (!appctx) { ctx->status_code = SPOE_CTX_ERR_RES; goto end; } - ctx->spoe_appctx = SPOE_APPCTX(appctx); - ctx->spoe_appctx->spoe_ctx = ctx; ctx->state = SPOE_CTX_ST_SENDING_MSGS; }