MINOR: tcp: add further tcp info fetchers

Adding on to Thierry's work (http://git.haproxy.org/?p=haproxy.git;h=6310bef5)
I have added a few more fetchers for counters based on the tcp_info struct
maintained by the kernel :

  fc_unacked, fc_sacked, fc_retrans, fc_fackets, fc_lost,
  fc_reordering

Two fields were not added because they're version-dependant :
  fc_rcv_rtt, fc_total_retrans

The fields name depend on the operating system. FreeBSD and NetBSD prefix
all the field names with "__" so we have to rely on a few #ifdef for
portability.
diff --git a/doc/configuration.txt b/doc/configuration.txt
index 430b0ca..9809360 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -12767,6 +12767,42 @@
   operating system does not support TCP_INFO, for example Linux kernels before
   2.4, the sample fetch fails.
 
+fc_unacked(<unit>) : integer
+  Returns the unacked counter measured by the kernel for the client connection.
+  If the server connection is not established, if the connection is not TCP or
+  if the operating system does not support TCP_INFO, for example Linux kernels
+  before 2.4, the sample fetch fails.
+
+fc_sacked(<unit>) : integer
+  Returns the sacked counter measured by the kernel for the client connection.
+  If the server connection is not established, if the connection is not TCP or
+  if the operating system does not support TCP_INFO, for example Linux kernels
+  before 2.4, the sample fetch fails.
+
+fc_retrans(<unit>) : integer
+  Returns the retransmits counter measured by the kernel for the client
+  connection. If the server connection is not established, if the connection is
+  not TCP or if the operating system does not support TCP_INFO, for example
+  Linux kernels before 2.4, the sample fetch fails.
+
+fc_fackets(<unit>) : integer
+  Returns the fack counter measured by the kernel for the client
+  connection. If the server connection is not established, if the connection is
+  not TCP or if the operating system does not support TCP_INFO, for example
+  Linux kernels before 2.4, the sample fetch fails.
+
+fc_lost(<unit>) : integer
+  Returns the lost counter measured by the kernel for the client
+  connection. If the server connection is not established, if the connection is
+  not TCP or if the operating system does not support TCP_INFO, for example
+  Linux kernels before 2.4, the sample fetch fails.
+
+fc_reordering(<unit>) : integer
+  Returns the reordering counter measured by the kernel for the client
+  connection. If the server connection is not established, if the connection is
+  not TCP or if the operating system does not support TCP_INFO, for example
+  Linux kernels before 2.4, the sample fetch fails.
+
 fe_id : integer
   Returns an integer containing the current frontend's id. It can be used in
   backends to check from which backend it was called, or to stick all users
diff --git a/src/proto_tcp.c b/src/proto_tcp.c
index 797ddcb..9c5ea98 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -2395,8 +2395,25 @@
 	/* extract the value. */
 	smp->data.type = SMP_T_SINT;
 	switch (val) {
-	case 0:  smp->data.u.sint = info.tcpi_rtt;    break;
-	case 1:  smp->data.u.sint = info.tcpi_rttvar; break;
+	case 0:  smp->data.u.sint = info.tcpi_rtt;            break;
+	case 1:  smp->data.u.sint = info.tcpi_rttvar;         break;
+#if defined(__linux__)
+	/* these ones are common to all Linux versions */
+	case 2:  smp->data.u.sint = info.tcpi_unacked;        break;
+	case 3:  smp->data.u.sint = info.tcpi_sacked;         break;
+	case 4:  smp->data.u.sint = info.tcpi_lost;           break;
+	case 5:  smp->data.u.sint = info.tcpi_retrans;        break;
+	case 6:  smp->data.u.sint = info.tcpi_fackets;        break;
+	case 7:  smp->data.u.sint = info.tcpi_reordering;     break;
+#elif defined(__FreeBSD__) || defined(__NetBSD__)
+	/* the ones are found on FreeBSD and NetBSD featuring TCP_INFO */
+	case 2:  smp->data.u.sint = info.__tcpi_unacked;      break;
+	case 3:  smp->data.u.sint = info.__tcpi_sacked;       break;
+	case 4:  smp->data.u.sint = info.__tcpi_lost;         break;
+	case 5:  smp->data.u.sint = info.__tcpi_retrans;      break;
+	case 6:  smp->data.u.sint = info.__tcpi_fackets;      break;
+	case 7:  smp->data.u.sint = info.__tcpi_reordering;   break;
+#endif
 	default: return 0;
 	}
 
@@ -2435,7 +2452,64 @@
 		return 0;
 	return 1;
 }
-#endif
+
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__)
+
+/* get the unacked counter on a client connexion */
+static int
+smp_fetch_fc_unacked(const struct arg *args, struct sample *smp, const char *kw, void *private)
+{
+	if (!get_tcp_info(args, smp, 0, 2))
+		return 0;
+	return 1;
+}
+
+/* get the sacked counter on a client connexion */
+static int
+smp_fetch_fc_sacked(const struct arg *args, struct sample *smp, const char *kw, void *private)
+{
+	if (!get_tcp_info(args, smp, 0, 3))
+		return 0;
+	return 1;
+}
+
+/* get the lost counter on a client connexion */
+static int
+smp_fetch_fc_lost(const struct arg *args, struct sample *smp, const char *kw, void *private)
+{
+	if (!get_tcp_info(args, smp, 0, 4))
+		return 0;
+	return 1;
+}
+
+/* get the retrans counter on a client connexion */
+static int
+smp_fetch_fc_retrans(const struct arg *args, struct sample *smp, const char *kw, void *private)
+{
+	if (!get_tcp_info(args, smp, 0, 5))
+		return 0;
+	return 1;
+}
+
+/* get the fackets counter on a client connexion */
+static int
+smp_fetch_fc_fackets(const struct arg *args, struct sample *smp, const char *kw, void *private)
+{
+	if (!get_tcp_info(args, smp, 0, 6))
+		return 0;
+	return 1;
+}
+
+/* get the reordering counter on a client connexion */
+static int
+smp_fetch_fc_reordering(const struct arg *args, struct sample *smp, const char *kw, void *private)
+{
+	if (!get_tcp_info(args, smp, 0, 7))
+		return 0;
+	return 1;
+}
+#endif // linux || freebsd || netbsd
+#endif // TCP_INFO
 
 #ifdef IPV6_V6ONLY
 /* parse the "v4v6" bind keyword */
@@ -2667,9 +2741,17 @@
 	{ "src_is_local", smp_fetch_src_is_local, 0, NULL, SMP_T_BOOL, SMP_USE_L4CLI },
 	{ "src_port", smp_fetch_sport, 0, NULL, SMP_T_SINT, SMP_USE_L4CLI },
 #ifdef TCP_INFO
-	{ "fc_rtt",    smp_fetch_fc_rtt,    ARG1(0,STR), NULL, SMP_T_SINT, SMP_USE_L4CLI },
-	{ "fc_rttvar", smp_fetch_fc_rttvar, ARG1(0,STR), NULL, SMP_T_SINT, SMP_USE_L4CLI },
-#endif
+	{ "fc_rtt",           smp_fetch_fc_rtt,           ARG1(0,STR), NULL, SMP_T_SINT, SMP_USE_L4CLI },
+	{ "fc_rttvar",        smp_fetch_fc_rttvar,        ARG1(0,STR), NULL, SMP_T_SINT, SMP_USE_L4CLI },
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__)
+	{ "fc_unacked",       smp_fetch_fc_unacked,       ARG1(0,STR), NULL, SMP_T_SINT, SMP_USE_L4CLI },
+	{ "fc_sacked",        smp_fetch_fc_sacked,        ARG1(0,STR), NULL, SMP_T_SINT, SMP_USE_L4CLI },
+	{ "fc_retrans",       smp_fetch_fc_retrans,       ARG1(0,STR), NULL, SMP_T_SINT, SMP_USE_L4CLI },
+	{ "fc_fackets",       smp_fetch_fc_fackets,       ARG1(0,STR), NULL, SMP_T_SINT, SMP_USE_L4CLI },
+	{ "fc_lost",          smp_fetch_fc_lost,          ARG1(0,STR), NULL, SMP_T_SINT, SMP_USE_L4CLI },
+	{ "fc_reordering",    smp_fetch_fc_reordering,    ARG1(0,STR), NULL, SMP_T_SINT, SMP_USE_L4CLI },
+#endif // linux || freebsd || netbsd
+#endif // TCP_INFO
 	{ /* END */ },
 }};