[MAJOR] session: add track-counters to track counters related to the session

This patch adds the ability to set a pointer in the session to an
entry in a stick table which holds various counters related to a
specific pattern.

Right now the syntax matches the target syntax and only the "src"
pattern can be specified, to track counters related to the session's
IPv4 source address. There is a special function to extract it and
convert it to a key. But the goal is to be able to later support as
many patterns as for the stick rules, and get rid of the specific
function.

The "track-counters" directive may only be set in a "tcp-request"
statement right now. Only the first one applies. Probably that later
we'll support multi-criteria tracking for a single session and that
we'll have to name tracking pointers.

No counter is updated right now, only the refcount is. Some subsequent
patches will have to bring that feature.
diff --git a/src/proto_tcp.c b/src/proto_tcp.c
index 24906be..7adb0f9 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -46,6 +46,7 @@
 #include <proto/protocols.h>
 #include <proto/proto_tcp.h>
 #include <proto/proxy.h>
+#include <proto/session.h>
 #include <proto/stick_table.h>
 #include <proto/stream_sock.h>
 #include <proto/task.h>
@@ -704,6 +705,9 @@
 int tcp_exec_req_rules(struct session *s)
 {
 	struct tcp_rule *rule;
+	struct stksess *ts = s->tracked_counters;
+	struct stktable *t = NULL;
+	int result = 1;
 	int ret;
 
 	list_for_each_entry(rule, &s->fe->tcp_req.l4_rules, list) {
@@ -727,13 +731,29 @@
 					s->flags |= SN_ERR_PRXCOND;
 				if (!(s->flags & SN_FINST_MASK))
 					s->flags |= SN_FINST_R;
-				return 0;
+				result = 0;
+				break;
 			}
-			/* otherwise it's an accept */
-			break;
+			else if (rule->action == TCP_ACT_TRK_CTR) {
+				if (!s->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_counters(s, t, ts);
+				}
+			}
+			else {
+				/* otherwise it's an accept */
+				break;
+			}
 		}
 	}
-	return 1;
+	return result;
 }
 
 /* This function should be called to parse a line starting with the "tcp-request"
@@ -840,13 +860,29 @@
 
 	/* OK so we're in front of plain L4 rules */
 
-	if (strcmp(args[1], "accept") == 0)
+	if (strcmp(args[1], "accept") == 0) {
+		arg++;
 		rule->action = TCP_ACT_ACCEPT;
-	else if (strcmp(args[1], "reject") == 0)
+	}
+	else if (strcmp(args[1], "reject") == 0) {
+		arg++;
 		rule->action = TCP_ACT_REJECT;
+	}
+	else if (strcmp(args[1], "track-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_CTR;
+	}
 	else {
 		retlen = snprintf(err, errlen,
-				  "'%s' expects 'inspect-delay', 'content', 'accept' or 'reject', in %s '%s' (was '%s')",
+				  "'%s' expects 'inspect-delay', 'content', 'accept', 'reject', or 'track-counters' in %s '%s' (was '%s')",
 				  args[0], proxy_type_str(curpx), curpx->id, args[1]);
 		goto error;
 	}
@@ -857,7 +893,6 @@
 		goto error;
 	}
 
-	arg++;
 	pol = ACL_COND_NONE;
 
 	if (strcmp(args[arg], "if") == 0 || strcmp(args[arg], "unless") == 0) {