Add TCP.SegmentsSent to stack.Stats.

NET-255 #progress

Change-Id: I0ef54afa9c672448b50cc497072aaf39893b3ccd
diff --git a/tcpip/tcpip.go b/tcpip/tcpip.go
index 393f048..e419999 100644
--- a/tcpip/tcpip.go
+++ b/tcpip/tcpip.go
@@ -428,6 +428,13 @@
 		// InvalidSegmentsReceived is the number of TCP segments received that
 		// the transport layer could not parse.
 		InvalidSegmentsReceived uint64
+
+		// SegmentsSent is the number of TCP segments sent from the transport
+		// layer. Excludes shutdown, reset, and syn segments, because those
+		// segments are sent via stack.Route, which writes directly to the network
+		// endpoint (bypassing the transport endpoint and its associated Stats
+		// struct completely).
+		SegmentsSent uint64
 	}
 }
 
diff --git a/tcpip/transport/tcp/connect.go b/tcpip/transport/tcp/connect.go
index 7ea1223..b4d0d8e 100644
--- a/tcpip/transport/tcp/connect.go
+++ b/tcpip/transport/tcp/connect.go
@@ -488,6 +488,7 @@
 
 // sendRaw sends a TCP segment to the endpoint's peer.
 func (e *endpoint) sendRaw(data buffer.View, flags byte, seq, ack seqnum.Value, rcvWnd seqnum.Size) *tcpip.Error {
+	atomic.AddUint64(&e.stack.MutableStats().TCP.SegmentsSent, 1)
 	if e.sendTSOk {
 		// Embed the timestamp if timestamp has been enabled.
 		//
diff --git a/tcpip/transport/tcp/tcp_test.go b/tcpip/transport/tcp/tcp_test.go
index 2344142..2ce3b49 100644
--- a/tcpip/transport/tcp/tcp_test.go
+++ b/tcpip/transport/tcp/tcp_test.go
@@ -145,6 +145,19 @@
 	}
 }
 
+func TestTCPSegmentsSentIncrement(t *testing.T) {
+	c := context.New(t, defaultMTU)
+	defer c.Cleanup()
+
+	stats := c.Stack().MutableStats()
+	expected := stats.TCP.SegmentsSent + 1
+	c.CreateConnected(789, 30000, nil)
+
+	if actual := stats.TCP.SegmentsSent; actual != expected {
+		t.Fatalf("Expected SegmentsSent to be %d, got %d", expected, actual)
+	}
+}
+
 func TestActiveHandshake(t *testing.T) {
 	c := context.New(t, defaultMTU)
 	defer c.Cleanup()