]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MEDIUM] tcp: accept the "track-counters" in "tcp-request content" rules
authorWilly Tarreau <w@1wt.eu>
Tue, 3 Aug 2010 17:34:32 +0000 (19:34 +0200)
committerWilly Tarreau <w@1wt.eu>
Tue, 10 Aug 2010 16:04:15 +0000 (18:04 +0200)
Doing so allows us to track counters from backends or depending on contents.
For instance, it now becomes possible to decide to track a connection based
on a Host header if enough time is granted to parse the HTTP request. It is
also possible to just track frontend counters in the frontend and unconditionally
track backend counters in the backend without having to write complex rules.

The first track-fe-counters rule executed is used to track counters for
the frontend, and the first track-be-counters rule executed is used to track
counters for the backend. Nothing prevents a frontend from setting a track-be
rule nor a backend from setting a track-fe rule. In fact these rules are
arbitrarily split between FE and BE with no dependencies.

src/cfgparse.c
src/proto_tcp.c

index 19785f0e86a475ab3fa599d5e3d6414aa079b1fd..6ca7ec57a4f09a711d756f6ca75e431dcebb1371 100644 (file)
@@ -5023,6 +5023,43 @@ int check_config_validity()
                        }
                }
 
+               /* find the target table for 'tcp-request' layer 6 rules */
+               list_for_each_entry(trule, &curproxy->tcp_req.inspect_rules, list) {
+                       struct proxy *target;
+
+                       if (trule->action != TCP_ACT_TRK_FE_CTR && trule->action != TCP_ACT_TRK_BE_CTR)
+                               continue;
+
+                       if (trule->act_prm.trk_ctr.table.n)
+                               target = findproxy(trule->act_prm.trk_ctr.table.n, 0);
+                       else
+                               target = curproxy;
+
+                       if (!target) {
+                               Alert("Proxy '%s': unable to find table '%s' referenced by track-counter.\n",
+                                     curproxy->id, trule->act_prm.trk_ctr.table.n);
+                               cfgerr++;
+                       }
+                       else if (target->table.size == 0) {
+                               Alert("Proxy '%s': table '%s' used but not configured.\n",
+                                     curproxy->id, trule->act_prm.trk_ctr.table.n ? trule->act_prm.trk_ctr.table.n : curproxy->id);
+                               cfgerr++;
+                       }
+                       else if (trule->act_prm.trk_ctr.type != target->table.type) {
+                               Alert("Proxy '%s': type of track-counters pattern not usable with type of stick-table '%s'.\n",
+                                     curproxy->id, trule->act_prm.trk_ctr.table.n ? trule->act_prm.trk_ctr.table.n : curproxy->id);
+                               cfgerr++;
+                       }
+                       else {
+                               free(trule->act_prm.trk_ctr.table.n);
+                               trule->act_prm.trk_ctr.table.t = &target->table;
+                               /* Note: if we decide to enhance the track-counters syntax, we may be able
+                                * to pass a list of counters to track and allocate them right here using
+                                * stktable_alloc_data_type().
+                                */
+                       }
+               }
+
                if (curproxy->uri_auth && !(curproxy->uri_auth->flags & ST_CONVDONE) &&
                    !LIST_ISEMPTY(&curproxy->uri_auth->req_acl) &&
                    (curproxy->uri_auth->userlist || curproxy->uri_auth->auth_realm )) {
index 4ff9ed04e6215863cffcfb10a40625d2840783a8..e87860b5e444f066c9f86340a4cef67fb374da96 100644 (file)
@@ -623,6 +623,8 @@ void tcpv6_add_listener(struct listener *listener)
 int tcp_inspect_request(struct session *s, struct buffer *req, int an_bit)
 {
        struct tcp_rule *rule;
+       struct stksess *ts;
+       struct stktable *t;
        int partial;
 
        DPRINTF(stderr,"[%u] %s: session=%p b=%p, exp(r,w)=%u,%u bf=%08x bl=%d analysers=%02x\n",
@@ -684,8 +686,36 @@ int tcp_inspect_request(struct session *s, struct buffer *req, int an_bit)
                                        s->flags |= SN_FINST_R;
                                return 0;
                        }
+                       else if (rule->action == TCP_ACT_TRK_FE_CTR) {
+                               if (!s->fe_tracked_counters) {
+                                       /* only the first valid track-counters directive applies.
+                                        * Also, note that right now we can only track SRC so we
+                                        * don't check how to get the key, but later we may need
+                                        * to consider rule->act_prm->trk_ctr.type.
+                                        */
+                                       t = rule->act_prm.trk_ctr.table.t;
+                                       ts = stktable_get_entry(t, tcpv4_src_to_stktable_key(s));
+                                       if (ts)
+                                               session_track_fe_counters(s, t, ts);
+                               }
+                       }
+                       else if (rule->action == TCP_ACT_TRK_BE_CTR) {
+                               if (!s->be_tracked_counters) {
+                                       /* only the first valid track-counters directive applies.
+                                        * Also, note that right now we can only track SRC so we
+                                        * don't check how to get the key, but later we may need
+                                        * to consider rule->act_prm->trk_ctr.type.
+                                        */
+                                       t = rule->act_prm.trk_ctr.table.t;
+                                       ts = stktable_get_entry(t, tcpv4_src_to_stktable_key(s));
+                                       if (ts)
+                                               session_track_be_counters(s, t, ts);
+                               }
+                       }
+                       else {
                                /* otherwise accept */
-                       break;
+                               break;
+                       }
                }
        }
 
@@ -819,19 +849,48 @@ static int tcp_parse_tcp_req(char **args, int section_type, struct proxy *curpx,
        arg = 1;
 
        if (!strcmp(args[1], "content")) {
+               arg++;
                if (curpx == defpx) {
                        snprintf(err, errlen, "%s %s is not allowed in 'defaults' sections",
                                 args[0], args[1]);
                        goto error;
                }
 
-               if (!strcmp(args[2], "accept"))
+               if (!strcmp(args[2], "accept")) {
+                       arg++;
                        rule->action = TCP_ACT_ACCEPT;
-               else if (!strcmp(args[2], "reject"))
+               }
+               else if (!strcmp(args[2], "reject")) {
+                       arg++;
                        rule->action = TCP_ACT_REJECT;
+               }
+               else if (strcmp(args[2], "track-fe-counters") == 0) {
+                       int ret;
+
+                       arg++;
+                       ret = parse_track_counters(args, &arg, section_type, curpx,
+                                                  &rule->act_prm.trk_ctr, defpx, err, errlen);
+
+                       if (ret < 0) /* nb: warnings are not handled yet */
+                               goto error;
+
+                       rule->action = TCP_ACT_TRK_FE_CTR;
+               }
+               else if (strcmp(args[2], "track-be-counters") == 0) {
+                       int ret;
+
+                       arg++;
+                       ret = parse_track_counters(args, &arg, section_type, curpx,
+                                                  &rule->act_prm.trk_ctr, defpx, err, errlen);
+
+                       if (ret < 0) /* nb: warnings are not handled yet */
+                               goto error;
+
+                       rule->action = TCP_ACT_TRK_BE_CTR;
+               }
                else {
                        retlen = snprintf(err, errlen,
-                                         "'%s %s' expects 'accept' or 'reject', in %s '%s' (was '%s')",
+                                         "'%s %s' expects 'accept', 'reject', 'track-fe-counters' or 'track-be-counters' in %s '%s' (was '%s')",
                                          args[0], args[1], proxy_type_str(curpx), curpx->id, args[2]);
                        goto error;
                }
@@ -839,18 +898,18 @@ static int tcp_parse_tcp_req(char **args, int section_type, struct proxy *curpx,
                pol = ACL_COND_NONE;
                rule->cond = NULL;
 
-               if (strcmp(args[3], "if") == 0 || strcmp(args[3], "unless") == 0) {
-                       if ((rule->cond = build_acl_cond(NULL, 0, curpx, (const char **)args+3)) == NULL) {
+               if (strcmp(args[arg], "if") == 0 || strcmp(args[arg], "unless") == 0) {
+                       if ((rule->cond = build_acl_cond(NULL, 0, curpx, (const char **)args+arg)) == NULL) {
                                retlen = snprintf(err, errlen,
                                                  "error detected in %s '%s' while parsing '%s' condition",
-                                                 proxy_type_str(curpx), curpx->id, args[3]);
+                                                 proxy_type_str(curpx), curpx->id, args[arg]);
                                goto error;
                        }
                }
-               else if (*args[3]) {
+               else if (*args[arg]) {
                        retlen = snprintf(err, errlen,
                                          "'%s %s %s' only accepts 'if' or 'unless', in %s '%s' (was '%s')",
-                                         args[0], args[1], args[2], proxy_type_str(curpx), curpx->id, args[3]);
+                                         args[0], args[1], args[2], proxy_type_str(curpx), curpx->id, args[arg]);
                        goto error;
                }
 
@@ -907,7 +966,7 @@ static int tcp_parse_tcp_req(char **args, int section_type, struct proxy *curpx,
        }
        else {
                retlen = snprintf(err, errlen,
-                                 "'%s' expects 'inspect-delay', 'content', 'accept', 'reject',  'track-fe-counters' or 'track-be-counters' in %s '%s' (was '%s')",
+                                 "'%s' expects 'inspect-delay', 'content', 'accept', 'reject', 'track-fe-counters' or 'track-be-counters' in %s '%s' (was '%s')",
                                  args[0], proxy_type_str(curpx), curpx->id, args[1]);
                goto error;
        }