> What do you think ? If you want, as a first step we can merge your patch
> as-is with surrounding #ifdef __linux__ and drop the two parts that are
> not compatible with 2.4. Probably that we'll have to think about dropping
> support for linux < 2.6.something for version 1.8.

I think this seems like the most reasonable solution for the time being. I
agree in the long run it probably makes sense to have a wrapper around
tcp_info to make things agnostic.

-Joe


On Wed, Aug 10, 2016 at 11:39 AM, Willy Tarreau <[email protected]> wrote:

> Hi again Joe,
>
> On Wed, Aug 10, 2016 at 05:36:16PM +0200, Willy Tarreau wrote:
> > On Wed, Aug 10, 2016 at 07:11:44AM -0700, Joe Williams wrote:
> > > Hello list,
> > >
> > > Adding on to Theirry's work (
> > > http://git.haproxy.org/?p=haproxy.git;a=commit;h=
> 6310bef51148b747f9019bd0bd67fd285eff0ae3)
> > > I have added a few more fetchers for counters based on the tcp_info
> struct
> > > maintained by the kernel.
> >
> > Thanks for this! As I told you initially I thought we wouldn't need
> > the extra metrics, but you proved me wrong :-)
> >
> > I've merged it and added your comment as the commit message. However
> > I was having a doubt about the presence of older fields on older kernels,
> > so I gave it a try with linux-2.6.32 and glibc 2.3.6 and it failed on me
> > like this :
> >
> > src/proto_tcp.c: In function `get_tcp_info':
> > src/proto_tcp.c:2407: error: structure has no member named `tcpi_rcv_rtt'
> > src/proto_tcp.c:2408: error: structure has no member named
> `tcpi_total_retrans'
> > make: *** [src/proto_tcp.o] Error 1
> > make: *** Waiting for unfinished jobs....
> >
> > So I'm seeing two possibilities :
> >   - either you don't need these ones and we simply drop them from the
> patch
> >     (the most likely solution given that total_retrans is meaningless in
> HTTP
> >     since it applies to the whole connection)
> >
> >   - or we find a way to detect them and disable them at build time (I'm
> >     looking at this now).
> >
> > Please let me know, I've not pushed the commit yet, and I'd admit that
> > the first option still seems the easiest to me :-/
>
> From what I'm seeing it also breaks FreeBSD where only Thierry's entries
> are declared, and some of yours exist with a "__" in front of their name :
>
> clang -Iinclude -Iebtree -Wall  -O2 -g -fno-strict-aliasing
> -Wdeclaration-after-statement       -DTPROXY -DCONFIG_HAP_CRYPT
> -DENABLE_POLL -DENABLE_KQUEUE  -DCONFIG_HAPROXY_VERSION=\"1.7-dev3-f5f03ef\"
> -DCONFIG_HAPROXY_DATE=\"2016/08/10\" -c -o src/proto_tcp.o src/proto_tcp.c
> src/proto_tcp.c:2392:34: error: use of undeclared identifier 'SOL_TCP'
>         if (getsockopt(conn->t.sock.fd, SOL_TCP, TCP_INFO, &info, &optlen)
> == -1)
>                                         ^
> src/proto_tcp.c:2400:35: error: no member named 'tcpi_unacked' in 'struct
> tcp_info'; did you mean '__tcpi_unacked'?
>         case 2:  smp->data.u.sint = info.tcpi_unacked;        break;
>                                          ^~~~~~~~~~~~
>                                          __tcpi_unacked
> /usr/include/netinet/tcp.h:212:12: note: '__tcpi_unacked' declared here
>         u_int32_t       __tcpi_unacked;
>                         ^
> src/proto_tcp.c:2401:35: error: no member named 'tcpi_sacked' in 'struct
> tcp_info'; did you mean '__tcpi_sacked'?
>         case 3:  smp->data.u.sint = info.tcpi_sacked;         break;
>                                          ^~~~~~~~~~~
>                                          __tcpi_sacked
> /usr/include/netinet/tcp.h:213:12: note: '__tcpi_sacked' declared here
>         u_int32_t       __tcpi_sacked;
>                         ^
> src/proto_tcp.c:2402:35: error: no member named 'tcpi_lost' in 'struct
> tcp_info'; did you mean '__tcpi_lost'?
>         case 4:  smp->data.u.sint = info.tcpi_lost;           break;
>                                          ^~~~~~~~~
>                                          __tcpi_lost
> /usr/include/netinet/tcp.h:214:12: note: '__tcpi_lost' declared here
>         u_int32_t       __tcpi_lost;
>                         ^
> src/proto_tcp.c:2403:35: error: no member named 'tcpi_retrans' in 'struct
> tcp_info'; did you mean '__tcpi_retrans'?
>         case 5:  smp->data.u.sint = info.tcpi_retrans;        break;
>                                          ^~~~~~~~~~~~
>                                          __tcpi_retrans
> /usr/include/netinet/tcp.h:215:12: note: '__tcpi_retrans' declared here
>         u_int32_t       __tcpi_retrans;
>                         ^
> src/proto_tcp.c:2404:35: error: no member named 'tcpi_fackets' in 'struct
> tcp_info'; did you mean '__tcpi_fackets'?
>         case 6:  smp->data.u.sint = info.tcpi_fackets;        break;
>                                          ^~~~~~~~~~~~
>                                          __tcpi_fackets
> /usr/include/netinet/tcp.h:216:12: note: '__tcpi_fackets' declared here
>         u_int32_t       __tcpi_fackets;
>                         ^
> src/proto_tcp.c:2405:35: error: no member named 'tcpi_reordering' in
> 'struct tcp_info'; did you mean '__tcpi_reordering'?
>         case 7:  smp->data.u.sint = info.tcpi_reordering;     break;
>                                          ^~~~~~~~~~~~~~~
>                                          __tcpi_reordering
> /usr/include/netinet/tcp.h:232:12: note: '__tcpi_reordering' declared here
>         u_int32_t       __tcpi_reordering;
>                         ^
> src/proto_tcp.c:2406:35: error: no member named 'tcpi_rcv_rtt' in 'struct
> tcp_info'
>         case 8:  smp->data.u.sint = info.tcpi_rcv_rtt;        break;
>                                     ~~~~ ^
> src/proto_tcp.c:2407:35: error: no member named 'tcpi_total_retrans' in
> 'struct tcp_info'
>         case 9:  smp->data.u.sint = info.tcpi_total_retrans;  break;
>                                     ~~~~ ^
> 9 errors generated.
> Makefile:791: recipe for target 'src/proto_tcp.o' failed
> gmake: *** [src/proto_tcp.o] Error 1
>
> So I think we'll have to be tricky here :
>
> - the basic info are accessible when TCP_INFO is declared. These ones
>   are common between Linux 2.4-4.x and FreeBSD 10.3 :
>
>         u_int8_t        tcpi_state;             /* TCP FSM state. */
>         u_int8_t        tcpi_options;           /* Options enabled on
> conn. */
>         u_int8_t        tcpi_snd_wscale:4,      /* RFC1323 send shift
> value. */
>                         tcpi_rcv_wscale:4;      /* RFC1323 recv shift
> value. */
>         u_int32_t       tcpi_rto;               /* Retransmission timeout
> (usec). */
>         u_int32_t       tcpi_snd_mss;           /* Max segment size for
> send. */
>         u_int32_t       tcpi_rcv_mss;           /* Max segment size for
> receive. */
>         u_int32_t       tcpi_last_data_recv;    /* Time since last recv
> data. */
>         u_int32_t       tcpi_rtt;               /* Smoothed RTT in usecs.
> */
>         u_int32_t       tcpi_rttvar;            /* RTT variance in usecs.
> */
>         u_int32_t       tcpi_snd_ssthresh;      /* Slow start threshold. */
>         u_int32_t       tcpi_snd_cwnd;          /* Send congestion window.
> */
>
>   Thus I consider it is safe to rely only on these ones by default for now.
>
> - A number of other fields are available on FreeBSD with the same names as
>   on Linux but with "__" prepended (eg: __tcp_sacked). We could have a
> #define
>   for this in the compat.h file.
>
> - some more fields are available and differ on these OSes. Afteri
>   "tcpi_reordering" which is the last common one, we find :
>
> Linux 2.4 : (nothing)
>
> Linux 2.6.12-3.14 :
>         __u32   tcpi_rcv_rtt;
>         __u32   tcpi_rcv_space;
>
>         __u32   tcpi_total_retrans;
>
> Linux 3.15-4.0 further add :
>         __u64   tcpi_pacing_rate;
>         __u64   tcpi_max_pacing_rate;
>
> Linux 4.1 adds :
>         __u64   tcpi_bytes_acked; /* RFC4898 tcpEStatsAppHCThruOctetsAcked
> */
>         __u64   tcpi_bytes_received; /* RFC4898
> tcpEStatsAppHCThruOctetsReceived */
>
> Linux 4.2-4.5 add :
>         __u32   tcpi_segs_out;       /* RFC4898 tcpEStatsPerfSegsOut */
>         __u32   tcpi_segs_in;        /* RFC4898 tcpEStatsPerfSegsIn */
>
> Linux 4.6-4.7 add :
>         __u32   tcpi_notsent_bytes;
>         __u32   tcpi_min_rtt;
>         __u32   tcpi_data_segs_in;      /* RFC4898 tcpEStatsDataSegsIn */
>         __u32   tcpi_data_segs_out;     /* RFC4898 tcpEStatsDataSegsOut */
>
> FreeBSD 10.3 has this instead :
>         u_int32_t       __tcpi_rcv_rtt;
>         u_int32_t       tcpi_rcv_space;         /* Advertised recv window.
> */
>
>         /* FreeBSD extensions to tcp_info. */
>         u_int32_t       tcpi_snd_wnd;           /* Advertised send window.
> */
>         u_int32_t       tcpi_snd_bwnd;          /* No longer used. */
>         u_int32_t       tcpi_snd_nxt;           /* Next egress seqno */
>         u_int32_t       tcpi_rcv_nxt;           /* Next ingress seqno */
>         u_int32_t       tcpi_toe_tid;           /* HWTID for TOE endpoints
> */
>         u_int32_t       tcpi_snd_rexmitpack;    /* Retransmitted packets */
>         u_int32_t       tcpi_rcv_ooopack;       /* Out-of-order packets */
>         u_int32_t       tcpi_snd_zerowin;       /* Zero-sized windows sent
> */
>
>         /* Padding to grow without breaking ABI. */
>         u_int32_t       __tcpi_pad[26];         /* Padding. */
>
>         u_int32_t       tcpi_rcv_space;         /* Advertised recv window.
> */
>
> One interesting point is that FreeBSD explicitly mentions their intent to
> be compatible with Linux's struct :
>
>  * The TCP_INFO socket option comes from the Linux 2.6 TCP API, and permits
>  * the caller to query certain information about the state of a TCP
>  * connection.  We provide an overlapping set of fields with the Linux
>  * implementation, but since this is a fixed size structure, room has been
>  * left for growth.  In order to maximize potential future compatibility
> with
>  * the Linux API, the same variable names and order have been adopted, and
>  * padding left to make room for omitted fields in case they are added
> later.
>
> Given that we won't have the proper knowledge of these fields from the
> libc itself which is not always in sync with the kernel (especially since
> people run whatever OS in containers on a different kernel), I tend to
> think
> that in order to maximize the portability we should simply define our own
> structure with our own fields, and possibly adjust it a bit depending on
> the operating system (eg: linux vs freebsd).
>
> What do you think ? If you want, as a first step we can merge your patch
> as-is with surrounding #ifdef __linux__ and drop the two parts that are
> not compatible with 2.4. Probably that we'll have to think about dropping
> support for linux < 2.6.something for version 1.8.
>
> CCing Thierry in case he has other ideas on the subject.
>
> Thanks,
> Willy
>
> PS: I'm appending your current patch in which I only adjusted the commit
>     message
>
>

Reply via email to