Merge remote-tracking branch 'upstream/master' into HEAD

Change-Id: If69c9202e8b15b93c4ba2345a0df19dd5f9bef2b
diff --git a/tcpip/adapters/gonet/gonet.go b/tcpip/adapters/gonet/gonet.go
index dd3c5b1..3d4a8f2 100644
--- a/tcpip/adapters/gonet/gonet.go
+++ b/tcpip/adapters/gonet/gonet.go
@@ -557,6 +557,21 @@
 	}
 }
 
+// RemoteAddr implements net.Conn.RemoteAddr.
+func (c *PacketConn) RemoteAddr() net.Addr {
+	a, err := c.ep.GetRemoteAddress()
+	if err != nil {
+		return nil
+	}
+	return fullToTCPAddr(a)
+}
+
+// Read implements net.Conn.Read
+func (c *PacketConn) Read(b []byte) (int, error) {
+	bytesRead, _, err := c.ReadFrom(b)
+	return bytesRead, err
+}
+
 // ReadFrom implements net.PacketConn.ReadFrom.
 func (c *PacketConn) ReadFrom(b []byte) (int, net.Addr, error) {
 	deadline := c.readCancel()
@@ -570,6 +585,10 @@
 	return copy(b, read), fullToUDPAddr(addr), nil
 }
 
+func (c *PacketConn) Write(b []byte) (int, error) {
+	return c.WriteTo(b, nil)
+}
+
 // WriteTo implements net.PacketConn.WriteTo.
 func (c *PacketConn) WriteTo(b []byte, addr net.Addr) (int, error) {
 	deadline := c.writeCancel()
@@ -581,13 +600,16 @@
 	default:
 	}
 
-	ua := addr.(*net.UDPAddr)
-	fullAddr := tcpip.FullAddress{Addr: tcpip.Address(ua.IP), Port: uint16(ua.Port)}
+	// If we're being called by Write, there is no addr
+	wopts := tcpip.WriteOptions{}
+	if addr != nil {
+		ua := addr.(*net.UDPAddr)
+		wopts.To = &tcpip.FullAddress{Addr: tcpip.Address(ua.IP), Port: uint16(ua.Port)}
+	}
 
 	v := buffer.NewView(len(b))
 	copy(v, b)
 
-	wopts := tcpip.WriteOptions{To: &fullAddr}
 	n, resCh, err := c.ep.Write(tcpip.SlicePayload(v), wopts)
 	if resCh != nil {
 		select {
diff --git a/tcpip/link/fdbased/endpoint.go b/tcpip/link/fdbased/endpoint.go
index ff755ad..a42785f 100644
--- a/tcpip/link/fdbased/endpoint.go
+++ b/tcpip/link/fdbased/endpoint.go
@@ -100,11 +100,6 @@
 	inboundDispatcher linkDispatcher
 	dispatcher        stack.NetworkDispatcher
 
-	// handleLocal indicates whether packets destined to itself should be
-	// handled by the netstack internally (true) or be forwarded to the FD
-	// endpoint (false).
-	handleLocal bool
-
 	// packetDispatchMode controls the packet dispatcher used by this
 	// endpoint.
 	packetDispatchMode PacketDispatchMode
@@ -128,7 +123,6 @@
 	Address            tcpip.LinkAddress
 	SaveRestore        bool
 	DisconnectOk       bool
-	HandleLocal        bool
 	PacketDispatchMode PacketDispatchMode
 }
 
@@ -168,7 +162,6 @@
 		closed:             opts.ClosedFunc,
 		addr:               opts.Address,
 		hdrSize:            hdrSize,
-		handleLocal:        opts.HandleLocal,
 		packetDispatchMode: opts.PacketDispatchMode,
 	}
 
@@ -256,14 +249,6 @@
 // WritePacket writes outbound packets to the file descriptor. If it is not
 // currently writable, the packet is dropped.
 func (e *endpoint) WritePacket(r *stack.Route, hdr buffer.Prependable, payload buffer.VectorisedView, protocol tcpip.NetworkProtocolNumber) *tcpip.Error {
-	if e.handleLocal && r.LocalAddress != "" && r.LocalAddress == r.RemoteAddress {
-		views := make([]buffer.View, 1, 1+len(payload.Views()))
-		views[0] = hdr.View()
-		views = append(views, payload.Views()...)
-		vv := buffer.NewVectorisedView(len(views[0])+payload.Size(), views)
-		e.dispatcher.DeliverNetworkPacket(e, r.RemoteLinkAddress, r.LocalLinkAddress, protocol, vv)
-		return nil
-	}
 	if e.hdrSize > 0 {
 		// Add ethernet header if needed.
 		eth := header.Ethernet(hdr.Prepend(header.EthernetMinimumSize))
diff --git a/tcpip/link/fdbased/mmap_amd64_unsafe.go b/tcpip/link/fdbased/mmap_amd64_unsafe.go
index 27ceccf..9687816 100644
--- a/tcpip/link/fdbased/mmap_amd64_unsafe.go
+++ b/tcpip/link/fdbased/mmap_amd64_unsafe.go
@@ -40,11 +40,13 @@
 // We overallocate the frame size to accommodate space for the
 // TPacketHdr+RawSockAddrLinkLayer+MAC header and any padding.
 //
+// Memory allocated for the ring buffer: tpBlockSize * tpBlockNR = 2 MiB
+//
 // NOTE: Frames need to be aligned at 16 byte boundaries.
 const (
 	tpFrameSize = 65536 + 128
-	tpBlockSize = tpFrameSize * 128
-	tpBlockNR   = 10
+	tpBlockSize = tpFrameSize * 32
+	tpBlockNR   = 1
 	tpFrameNR   = (tpBlockSize * tpBlockNR) / tpFrameSize
 )
 
diff --git a/tcpip/stack/nic.go b/tcpip/stack/nic.go
index 97f6bdd..8bc669a 100644
--- a/tcpip/stack/nic.go
+++ b/tcpip/stack/nic.go
@@ -42,6 +42,20 @@
 	primary     map[tcpip.NetworkProtocolNumber]*ilist.List
 	endpoints   map[NetworkEndpointID]*referencedNetworkEndpoint
 	subnets     []tcpip.Subnet
+
+	stats NICStats
+}
+
+// NICStats includes transmitted and received stats.
+type NICStats struct {
+	Tx DirectionStats
+	Rx DirectionStats
+}
+
+// DirectionStats includes packet and byte counts.
+type DirectionStats struct {
+	Packets *tcpip.StatCounter
+	Bytes   *tcpip.StatCounter
 }
 
 // PrimaryEndpointBehavior is an enumeration of an endpoint's primacy behavior.
@@ -73,6 +87,16 @@
 		demux:     newTransportDemuxer(stack),
 		primary:   make(map[tcpip.NetworkProtocolNumber]*ilist.List),
 		endpoints: make(map[NetworkEndpointID]*referencedNetworkEndpoint),
+		stats: NICStats{
+			Tx: DirectionStats{
+				Packets: &tcpip.StatCounter{},
+				Bytes:   &tcpip.StatCounter{},
+			},
+			Rx: DirectionStats{
+				Packets: &tcpip.StatCounter{},
+				Bytes:   &tcpip.StatCounter{},
+			},
+		},
 	}
 }
 
@@ -384,6 +408,9 @@
 // This rule applies only to the slice itself, not to the items of the slice;
 // the ownership of the items is not retained by the caller.
 func (n *NIC) DeliverNetworkPacket(linkEP LinkEndpoint, remote, _ tcpip.LinkAddress, protocol tcpip.NetworkProtocolNumber, vv buffer.VectorisedView) {
+	n.stats.Rx.Packets.Increment()
+	n.stats.Rx.Bytes.IncrementBy(uint64(vv.Size()))
+
 	netProto, ok := n.stack.networkProtocols[protocol]
 	if !ok {
 		n.stack.stats.UnknownProtocolRcvdPackets.Increment()
@@ -409,7 +436,7 @@
 		n.mu.RLock()
 		for _, ref := range n.endpoints {
 			if ref.protocol == header.IPv4ProtocolNumber && ref.tryIncRef() {
-				r := makeRoute(protocol, dst, src, linkEP.LinkAddress(), ref, false /* multicastLoop */)
+				r := makeRoute(protocol, dst, src, linkEP.LinkAddress(), ref, false /* handleLocal */, false /* multicastLoop */)
 				r.RemoteLinkAddress = remote
 				ref.ep.HandlePacket(&r, vv)
 				ref.decRef()
@@ -420,7 +447,7 @@
 	}
 
 	if ref := n.getRef(protocol, dst); ref != nil {
-		r := makeRoute(protocol, dst, src, linkEP.LinkAddress(), ref, false /* multicastLoop */)
+		r := makeRoute(protocol, dst, src, linkEP.LinkAddress(), ref, false /* handleLocal */, false /* multicastLoop */)
 		r.RemoteLinkAddress = remote
 		ref.ep.HandlePacket(&r, vv)
 		ref.decRef()
@@ -457,7 +484,14 @@
 			// Send the packet out of n.
 			hdr := buffer.NewPrependableFromView(vv.First())
 			vv.RemoveFirst()
-			n.linkEP.WritePacket(&r, hdr, vv, protocol)
+
+			// TODO: use route.WritePacket.
+			if err := n.linkEP.WritePacket(&r, hdr, vv, protocol); err != nil {
+				r.Stats().IP.OutgoingPacketErrors.Increment()
+			} else {
+				n.stats.Tx.Packets.Increment()
+				n.stats.Tx.Bytes.IncrementBy(uint64(hdr.UsedLength() + vv.Size()))
+			}
 		}
 		return
 	}
diff --git a/tcpip/stack/route.go b/tcpip/stack/route.go
index bb41364..2ca7b15 100644
--- a/tcpip/stack/route.go
+++ b/tcpip/stack/route.go
@@ -47,19 +47,27 @@
 	// starts.
 	ref *referencedNetworkEndpoint
 
-	multicastLoop bool
+	// loop controls where WritePacket should send packets.
+	loop PacketLooping
 }
 
 // makeRoute initializes a new route. It takes ownership of the provided
 // reference to a network endpoint.
-func makeRoute(netProto tcpip.NetworkProtocolNumber, localAddr, remoteAddr tcpip.Address, localLinkAddr tcpip.LinkAddress, ref *referencedNetworkEndpoint, multicastLoop bool) Route {
+func makeRoute(netProto tcpip.NetworkProtocolNumber, localAddr, remoteAddr tcpip.Address, localLinkAddr tcpip.LinkAddress, ref *referencedNetworkEndpoint, handleLocal, multicastLoop bool) Route {
+	loop := PacketOut
+	if handleLocal && localAddr != "" && remoteAddr == localAddr {
+		loop = PacketLoop
+	} else if multicastLoop && (header.IsV4MulticastAddress(remoteAddr) || header.IsV6MulticastAddress(remoteAddr)) {
+		loop |= PacketLoop
+	}
+
 	return Route{
 		NetProto:         netProto,
 		LocalAddress:     localAddr,
 		LocalLinkAddress: localLinkAddr,
 		RemoteAddress:    remoteAddr,
 		ref:              ref,
-		multicastLoop:    multicastLoop,
+		loop:             loop,
 	}
 }
 
@@ -137,14 +145,12 @@
 
 // WritePacket writes the packet through the given route.
 func (r *Route) WritePacket(hdr buffer.Prependable, payload buffer.VectorisedView, protocol tcpip.TransportProtocolNumber, ttl uint8) *tcpip.Error {
-	loop := PacketOut
-	if r.multicastLoop && (header.IsV4MulticastAddress(r.RemoteAddress) || header.IsV6MulticastAddress(r.RemoteAddress)) {
-		loop |= PacketLoop
-	}
-
-	err := r.ref.ep.WritePacket(r, hdr, payload, protocol, ttl, loop)
-	if err == tcpip.ErrNoRoute {
+	err := r.ref.ep.WritePacket(r, hdr, payload, protocol, ttl, r.loop)
+	if err != nil {
 		r.Stats().IP.OutgoingPacketErrors.Increment()
+	} else {
+		r.ref.nic.stats.Tx.Packets.Increment()
+		r.ref.nic.stats.Tx.Bytes.IncrementBy(uint64(hdr.UsedLength() + payload.Size()))
 	}
 	return err
 }
diff --git a/tcpip/stack/stack.go b/tcpip/stack/stack.go
index 8941661..02640ea 100644
--- a/tcpip/stack/stack.go
+++ b/tcpip/stack/stack.go
@@ -308,6 +308,9 @@
 
 	// clock is used to generate user-visible times.
 	clock tcpip.Clock
+
+	// handleLocal allows non-loopback interfaces to loop packets.
+	handleLocal bool
 }
 
 // Options contains optional Stack configuration.
@@ -319,6 +322,11 @@
 
 	// Stats are optional statistic counters.
 	Stats tcpip.Stats
+
+	// HandleLocal indicates whether packets destined to their source
+	// should be handled by the stack internally (true) or outside the
+	// stack (false).
+	HandleLocal bool
 }
 
 // New allocates a new networking stack with only the requested networking and
@@ -343,6 +351,7 @@
 		PortManager:        ports.NewPortManager(),
 		clock:              clock,
 		stats:              opts.Stats.FillIn(),
+		handleLocal:        opts.HandleLocal,
 	}
 
 	// Add specified network protocols.
@@ -618,6 +627,8 @@
 
 	// MTU is the maximum transmission unit.
 	MTU uint32
+
+	Stats NICStats
 }
 
 // NICInfo returns a map of NICIDs to their associated information.
@@ -639,6 +650,7 @@
 			ProtocolAddresses: nic.Addresses(),
 			Flags:             flags,
 			MTU:               nic.linkEP.MTU(),
+			Stats:             nic.stats,
 		}
 	}
 	return nics
@@ -764,7 +776,7 @@
 	if id != 0 && !needRoute {
 		if nic, ok := s.nics[id]; ok {
 			if ref := s.getRefEP(nic, localAddr, netProto); ref != nil {
-				return makeRoute(netProto, ref.ep.ID().LocalAddress, remoteAddr, nic.linkEP.LinkAddress(), ref, multicastLoop && !nic.loopback), nil
+				return makeRoute(netProto, ref.ep.ID().LocalAddress, remoteAddr, nic.linkEP.LinkAddress(), ref, s.handleLocal && !nic.loopback, multicastLoop && !nic.loopback), nil
 			}
 		}
 	} else {
@@ -780,7 +792,7 @@
 						remoteAddr = ref.ep.ID().LocalAddress
 					}
 
-					r := makeRoute(netProto, ref.ep.ID().LocalAddress, remoteAddr, nic.linkEP.LinkAddress(), ref, multicastLoop && !nic.loopback)
+					r := makeRoute(netProto, ref.ep.ID().LocalAddress, remoteAddr, nic.linkEP.LinkAddress(), ref, s.handleLocal && !nic.loopback, multicastLoop && !nic.loopback)
 					if needRoute {
 						r.NextHop = route.Gateway
 					}
diff --git a/tcpip/stack/stack_test.go b/tcpip/stack/stack_test.go
index ae9653c..e746ec3 100644
--- a/tcpip/stack/stack_test.go
+++ b/tcpip/stack/stack_test.go
@@ -273,7 +273,7 @@
 	}
 }
 
-func sendTo(t *testing.T, s *stack.Stack, addr tcpip.Address) {
+func sendTo(t *testing.T, s *stack.Stack, addr tcpip.Address, payload buffer.View) {
 	r, err := s.FindRoute(0, "", addr, fakeNetNumber, false /* multicastLoop */)
 	if err != nil {
 		t.Fatalf("FindRoute failed: %v", err)
@@ -281,9 +281,8 @@
 	defer r.Release()
 
 	hdr := buffer.NewPrependable(int(r.MaxHeaderLength()))
-	if err := r.WritePacket(hdr, buffer.VectorisedView{}, fakeTransNumber, 123); err != nil {
+	if err := r.WritePacket(hdr, payload.ToVectorisedView(), fakeTransNumber, 123); err != nil {
 		t.Errorf("WritePacket failed: %v", err)
-		return
 	}
 }
 
@@ -304,7 +303,7 @@
 	}
 
 	// Make sure that the link-layer endpoint received the outbound packet.
-	sendTo(t, s, "\x03")
+	sendTo(t, s, "\x03", nil)
 	if c := linkEP.Drain(); c != 1 {
 		t.Errorf("packetCount = %d, want %d", c, 1)
 	}
@@ -351,14 +350,14 @@
 	})
 
 	// Send a packet to an odd destination.
-	sendTo(t, s, "\x05")
+	sendTo(t, s, "\x05", nil)
 
 	if c := linkEP1.Drain(); c != 1 {
 		t.Errorf("packetCount = %d, want %d", c, 1)
 	}
 
 	// Send a packet to an even destination.
-	sendTo(t, s, "\x06")
+	sendTo(t, s, "\x06", nil)
 
 	if c := linkEP2.Drain(); c != 1 {
 		t.Errorf("packetCount = %d, want %d", c, 1)
@@ -1055,6 +1054,44 @@
 	}
 }
 
+func TestNICStats(t *testing.T) {
+	s := stack.New([]string{"fakeNet"}, nil, stack.Options{})
+	id1, linkEP1 := channel.New(10, defaultMTU, "")
+	if err := s.CreateNIC(1, id1); err != nil {
+		t.Fatalf("CreateNIC failed: %v", err)
+	}
+	if err := s.AddAddress(1, fakeNetNumber, "\x01"); err != nil {
+		t.Fatalf("AddAddress failed: %v", err)
+	}
+	// Route all packets for address \x01 to NIC 1.
+	s.SetRouteTable([]tcpip.Route{
+		{"\x01", "\xff", "\x00", 1},
+	})
+
+	// Send a packet to address 1.
+	buf := buffer.NewView(30)
+	linkEP1.Inject(fakeNetNumber, buf.ToVectorisedView())
+	if got, want := s.NICInfo()[1].Stats.Rx.Packets.Value(), uint64(1); got != want {
+		t.Errorf("got Rx.Packets.Value() = %d, want = %d", got, want)
+	}
+
+	if got, want := s.NICInfo()[1].Stats.Rx.Bytes.Value(), uint64(len(buf)); got != want {
+		t.Errorf("got Rx.Bytes.Value() = %d, want = %d", got, want)
+	}
+
+	payload := buffer.NewView(10)
+	// Write a packet out via the address for NIC 1
+	sendTo(t, s, "\x01", payload)
+	want := uint64(linkEP1.Drain())
+	if got := s.NICInfo()[1].Stats.Tx.Packets.Value(); got != want {
+		t.Errorf("got Tx.Packets.Value() = %d, linkEP1.Drain() = %d", got, want)
+	}
+
+	if got, want := s.NICInfo()[1].Stats.Tx.Bytes.Value(), uint64(len(payload)); got != want {
+		t.Errorf("got Tx.Bytes.Value() = %d, want = %d", got, want)
+	}
+}
+
 func TestNICForwarding(t *testing.T) {
 	// Create a stack with the fake network protocol, two NICs, each with
 	// an address.
@@ -1092,6 +1129,15 @@
 	default:
 		t.Fatal("Packet not forwarded")
 	}
+
+	// Test that forwarding increments Tx stats correctly.
+	if got, want := s.NICInfo()[2].Stats.Tx.Packets.Value(), uint64(1); got != want {
+		t.Errorf("got Tx.Packets.Value() = %d, want = %d", got, want)
+	}
+
+	if got, want := s.NICInfo()[2].Stats.Tx.Bytes.Value(), uint64(len(buf)); got != want {
+		t.Errorf("got Tx.Bytes.Value() = %d, want = %d", got, want)
+	}
 }
 
 func init() {
diff --git a/tcpip/transport/tcp/accept.go b/tcpip/transport/tcp/accept.go
index ecaa132..0d4b217 100644
--- a/tcpip/transport/tcp/accept.go
+++ b/tcpip/transport/tcp/accept.go
@@ -297,7 +297,7 @@
 // and needs to handle it.
 func (e *endpoint) handleListenSegment(ctx *listenContext, s *segment) {
 	switch s.flags {
-	case flagSyn:
+	case header.TCPFlagSyn:
 		opts := parseSynSegmentOptions(s)
 		if incSynRcvdCount() {
 			s.incRef()
@@ -315,10 +315,10 @@
 				TSVal: tcpTimeStamp(timeStampOffset()),
 				TSEcr: opts.TSVal,
 			}
-			sendSynTCP(&s.route, s.id, flagSyn|flagAck, cookie, s.sequenceNumber+1, ctx.rcvWnd, synOpts)
+			sendSynTCP(&s.route, s.id, header.TCPFlagSyn|header.TCPFlagAck, cookie, s.sequenceNumber+1, ctx.rcvWnd, synOpts)
 		}
 
-	case flagAck:
+	case header.TCPFlagAck:
 		if data, ok := ctx.isCookieValid(s.id, s.ackNumber-1, s.sequenceNumber-1); ok && int(data) < len(mssTable) {
 			// Create newly accepted endpoint and deliver it.
 			rcvdSynOptions := &header.TCPSynOptions{
diff --git a/tcpip/transport/tcp/connect.go b/tcpip/transport/tcp/connect.go
index 19cf7ce..7b2563e 100644
--- a/tcpip/transport/tcp/connect.go
+++ b/tcpip/transport/tcp/connect.go
@@ -123,7 +123,7 @@
 	}
 
 	h.state = handshakeSynSent
-	h.flags = flagSyn
+	h.flags = header.TCPFlagSyn
 	h.ackNum = 0
 	h.mss = 0
 	h.iss = seqnum.Value(uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24)
@@ -144,7 +144,7 @@
 func (h *handshake) resetToSynRcvd(iss seqnum.Value, irs seqnum.Value, opts *header.TCPSynOptions) {
 	h.active = false
 	h.state = handshakeSynRcvd
-	h.flags = flagSyn | flagAck
+	h.flags = header.TCPFlagSyn | header.TCPFlagAck
 	h.iss = iss
 	h.ackNum = irs + 1
 	h.mss = opts.MSS
@@ -155,13 +155,13 @@
 // a TCP 3-way handshake is valid. If it's not, a RST segment is sent back in
 // response.
 func (h *handshake) checkAck(s *segment) bool {
-	if s.flagIsSet(flagAck) && s.ackNumber != h.iss+1 {
+	if s.flagIsSet(header.TCPFlagAck) && s.ackNumber != h.iss+1 {
 		// RFC 793, page 36, states that a reset must be generated when
 		// the connection is in any non-synchronized state and an
 		// incoming segment acknowledges something not yet sent. The
 		// connection remains in the same state.
 		ack := s.sequenceNumber.Add(s.logicalLen())
-		h.ep.sendRaw(buffer.VectorisedView{}, flagRst|flagAck, s.ackNumber, ack, 0)
+		h.ep.sendRaw(buffer.VectorisedView{}, header.TCPFlagRst|header.TCPFlagAck, s.ackNumber, ack, 0)
 		return false
 	}
 
@@ -173,8 +173,8 @@
 func (h *handshake) synSentState(s *segment) *tcpip.Error {
 	// RFC 793, page 37, states that in the SYN-SENT state, a reset is
 	// acceptable if the ack field acknowledges the SYN.
-	if s.flagIsSet(flagRst) {
-		if s.flagIsSet(flagAck) && s.ackNumber == h.iss+1 {
+	if s.flagIsSet(header.TCPFlagRst) {
+		if s.flagIsSet(header.TCPFlagAck) && s.ackNumber == h.iss+1 {
 			return tcpip.ErrConnectionRefused
 		}
 		return nil
@@ -186,7 +186,7 @@
 
 	// We are in the SYN-SENT state. We only care about segments that have
 	// the SYN flag.
-	if !s.flagIsSet(flagSyn) {
+	if !s.flagIsSet(header.TCPFlagSyn) {
 		return nil
 	}
 
@@ -201,15 +201,15 @@
 
 	// Remember the sequence we'll ack from now on.
 	h.ackNum = s.sequenceNumber + 1
-	h.flags |= flagAck
+	h.flags |= header.TCPFlagAck
 	h.mss = rcvSynOpts.MSS
 	h.sndWndScale = rcvSynOpts.WS
 
 	// If this is a SYN ACK response, we only need to acknowledge the SYN
 	// and the handshake is completed.
-	if s.flagIsSet(flagAck) {
+	if s.flagIsSet(header.TCPFlagAck) {
 		h.state = handshakeCompleted
-		h.ep.sendRaw(buffer.VectorisedView{}, flagAck, h.iss+1, h.ackNum, h.rcvWnd>>h.effectiveRcvWndScale())
+		h.ep.sendRaw(buffer.VectorisedView{}, header.TCPFlagAck, h.iss+1, h.ackNum, h.rcvWnd>>h.effectiveRcvWndScale())
 		return nil
 	}
 
@@ -236,7 +236,7 @@
 // synRcvdState handles a segment received when the TCP 3-way handshake is in
 // the SYN-RCVD state.
 func (h *handshake) synRcvdState(s *segment) *tcpip.Error {
-	if s.flagIsSet(flagRst) {
+	if s.flagIsSet(header.TCPFlagRst) {
 		// RFC 793, page 37, states that in the SYN-RCVD state, a reset
 		// is acceptable if the sequence number is in the window.
 		if s.sequenceNumber.InWindow(h.ackNum, h.rcvWnd) {
@@ -249,16 +249,16 @@
 		return nil
 	}
 
-	if s.flagIsSet(flagSyn) && s.sequenceNumber != h.ackNum-1 {
+	if s.flagIsSet(header.TCPFlagSyn) && s.sequenceNumber != h.ackNum-1 {
 		// We received two SYN segments with different sequence
 		// numbers, so we reset this and restart the whole
 		// process, except that we don't reset the timer.
 		ack := s.sequenceNumber.Add(s.logicalLen())
 		seq := seqnum.Value(0)
-		if s.flagIsSet(flagAck) {
+		if s.flagIsSet(header.TCPFlagAck) {
 			seq = s.ackNumber
 		}
-		h.ep.sendRaw(buffer.VectorisedView{}, flagRst|flagAck, seq, ack, 0)
+		h.ep.sendRaw(buffer.VectorisedView{}, header.TCPFlagRst|header.TCPFlagAck, seq, ack, 0)
 
 		if !h.active {
 			return tcpip.ErrInvalidEndpointState
@@ -278,7 +278,7 @@
 
 	// We have previously received (and acknowledged) the peer's SYN. If the
 	// peer acknowledges our SYN, the handshake is completed.
-	if s.flagIsSet(flagAck) {
+	if s.flagIsSet(header.TCPFlagAck) {
 
 		// If the timestamp option is negotiated and the segment does
 		// not carry a timestamp option then the segment must be dropped
@@ -301,7 +301,7 @@
 
 func (h *handshake) handleSegment(s *segment) *tcpip.Error {
 	h.sndWnd = s.window
-	if !s.flagIsSet(flagSyn) && h.sndWndScale > 0 {
+	if !s.flagIsSet(header.TCPFlagSyn) && h.sndWndScale > 0 {
 		h.sndWnd <<= uint8(h.sndWndScale)
 	}
 
@@ -472,7 +472,7 @@
 }
 
 func parseSynSegmentOptions(s *segment) header.TCPSynOptions {
-	synOpts := header.ParseSynOptions(s.options, s.flagIsSet(flagAck))
+	synOpts := header.ParseSynOptions(s.options, s.flagIsSet(header.TCPFlagAck))
 	if synOpts.TS {
 		s.parsedOptions.TSVal = synOpts.TSVal
 		s.parsedOptions.TSEcr = synOpts.TSEcr
@@ -596,7 +596,7 @@
 	}
 
 	r.Stats().TCP.SegmentsSent.Increment()
-	if (flags & flagRst) != 0 {
+	if (flags & header.TCPFlagRst) != 0 {
 		r.Stats().TCP.ResetsSent.Increment()
 	}
 
@@ -645,7 +645,7 @@
 // sendRaw sends a TCP segment to the endpoint's peer.
 func (e *endpoint) sendRaw(data buffer.VectorisedView, flags byte, seq, ack seqnum.Value, rcvWnd seqnum.Size) *tcpip.Error {
 	var sackBlocks []header.SACKBlock
-	if e.state == stateConnected && e.rcv.pendingBufSize > 0 && (flags&flagAck != 0) {
+	if e.state == stateConnected && e.rcv.pendingBufSize > 0 && (flags&header.TCPFlagAck != 0) {
 		sackBlocks = e.sack.Blocks[:e.sack.NumBlocks]
 	}
 	options := e.makeOptions(sackBlocks)
@@ -695,7 +695,7 @@
 // state with the given error code. This method must only be called from the
 // protocol goroutine.
 func (e *endpoint) resetConnectionLocked(err *tcpip.Error) {
-	e.sendRaw(buffer.VectorisedView{}, flagAck|flagRst, e.snd.sndUna, e.rcv.rcvNxt, 0)
+	e.sendRaw(buffer.VectorisedView{}, header.TCPFlagAck|header.TCPFlagRst, e.snd.sndUna, e.rcv.rcvNxt, 0)
 
 	e.state = stateError
 	e.hardError = err
@@ -727,7 +727,7 @@
 			e.probe(e.completeState())
 		}
 
-		if s.flagIsSet(flagRst) {
+		if s.flagIsSet(header.TCPFlagRst) {
 			if e.rcv.acceptable(s.sequenceNumber, 0) {
 				// RFC 793, page 37 states that "in all states
 				// except SYN-SENT, all reset (RST) segments are
@@ -736,7 +736,7 @@
 				s.decRef()
 				return tcpip.ErrConnectionReset
 			}
-		} else if s.flagIsSet(flagAck) {
+		} else if s.flagIsSet(header.TCPFlagAck) {
 			// Patch the window size in the segment according to the
 			// send window scale.
 			s.window <<= e.snd.sndWndScale
@@ -785,7 +785,7 @@
 	// seg.seq = snd.nxt-1.
 	e.keepalive.unacked++
 	e.keepalive.Unlock()
-	e.snd.sendSegment(buffer.VectorisedView{}, flagAck, e.snd.sndNxt-1)
+	e.snd.sendSegment(buffer.VectorisedView{}, header.TCPFlagAck, e.snd.sndNxt-1)
 	e.resetKeepaliveTimer(false)
 	return nil
 }
diff --git a/tcpip/transport/tcp/endpoint.go b/tcpip/transport/tcp/endpoint.go
index 90d9c3a..30e7e3d 100644
--- a/tcpip/transport/tcp/endpoint.go
+++ b/tcpip/transport/tcp/endpoint.go
@@ -1443,7 +1443,7 @@
 	}
 
 	e.stack.Stats().TCP.ValidSegmentsReceived.Increment()
-	if (s.flags & flagRst) != 0 {
+	if (s.flags & header.TCPFlagRst) != 0 {
 		e.stack.Stats().TCP.ResetsReceived.Increment()
 	}
 
diff --git a/tcpip/transport/tcp/forwarder.go b/tcpip/transport/tcp/forwarder.go
index 93511c3..9f49732 100644
--- a/tcpip/transport/tcp/forwarder.go
+++ b/tcpip/transport/tcp/forwarder.go
@@ -68,7 +68,7 @@
 	defer s.decRef()
 
 	// We only care about well-formed SYN packets.
-	if !s.parse() || s.flags != flagSyn {
+	if !s.parse() || s.flags != header.TCPFlagSyn {
 		return false
 	}
 
diff --git a/tcpip/transport/tcp/protocol.go b/tcpip/transport/tcp/protocol.go
index 195c375..9344e7b 100644
--- a/tcpip/transport/tcp/protocol.go
+++ b/tcpip/transport/tcp/protocol.go
@@ -135,7 +135,7 @@
 	}
 
 	// There's nothing to do if this is already a reset packet.
-	if s.flagIsSet(flagRst) {
+	if s.flagIsSet(header.TCPFlagRst) {
 		return true
 	}
 
@@ -147,13 +147,13 @@
 func replyWithReset(s *segment) {
 	// Get the seqnum from the packet if the ack flag is set.
 	seq := seqnum.Value(0)
-	if s.flagIsSet(flagAck) {
+	if s.flagIsSet(header.TCPFlagAck) {
 		seq = s.ackNumber
 	}
 
 	ack := s.sequenceNumber.Add(s.logicalLen())
 
-	sendTCP(&s.route, s.id, buffer.VectorisedView{}, s.route.DefaultTTL(), flagRst|flagAck, seq, ack, 0, nil)
+	sendTCP(&s.route, s.id, buffer.VectorisedView{}, s.route.DefaultTTL(), header.TCPFlagRst|header.TCPFlagAck, seq, ack, 0, nil)
 }
 
 // SetOption implements TransportProtocol.SetOption.
diff --git a/tcpip/transport/tcp/rcv.go b/tcpip/transport/tcp/rcv.go
index 66c1f13..29fc666 100644
--- a/tcpip/transport/tcp/rcv.go
+++ b/tcpip/transport/tcp/rcv.go
@@ -17,6 +17,7 @@
 import (
 	"container/heap"
 
+	"github.com/google/netstack/tcpip/header"
 	"github.com/google/netstack/tcpip/seqnum"
 )
 
@@ -133,7 +134,7 @@
 	// sequence numbers that have been consumed.
 	TrimSACKBlockList(&r.ep.sack, r.rcvNxt)
 
-	if s.flagIsSet(flagFin) {
+	if s.flagIsSet(header.TCPFlagFin) {
 		r.rcvNxt++
 
 		// Send ACK immediately.
@@ -181,7 +182,7 @@
 
 	// Defer segment processing if it can't be consumed now.
 	if !r.consumeSegment(s, segSeq, segLen) {
-		if segLen > 0 || s.flagIsSet(flagFin) {
+		if segLen > 0 || s.flagIsSet(header.TCPFlagFin) {
 			// We only store the segment if it's within our buffer
 			// size limit.
 			if r.pendingBufUsed < r.pendingBufSize {
diff --git a/tcpip/transport/tcp/segment.go b/tcpip/transport/tcp/segment.go
index 71553c4..7b67007 100644
--- a/tcpip/transport/tcp/segment.go
+++ b/tcpip/transport/tcp/segment.go
@@ -24,16 +24,6 @@
 	"github.com/google/netstack/tcpip/stack"
 )
 
-// Flags that may be set in a TCP segment.
-const (
-	flagFin = 1 << iota
-	flagSyn
-	flagRst
-	flagPsh
-	flagAck
-	flagUrg
-)
-
 // segment represents a TCP segment. It holds the payload and parsed TCP segment
 // information, and can be added to intrusive lists.
 // segment is mostly immutable, the only field allowed to change is viewToDeliver.
@@ -123,10 +113,10 @@
 // as the data length plus one for each of the SYN and FIN bits set.
 func (s *segment) logicalLen() seqnum.Size {
 	l := seqnum.Size(s.data.Size())
-	if s.flagIsSet(flagSyn) {
+	if s.flagIsSet(header.TCPFlagSyn) {
 		l++
 	}
-	if s.flagIsSet(flagFin) {
+	if s.flagIsSet(header.TCPFlagFin) {
 		l++
 	}
 	return l
diff --git a/tcpip/transport/tcp/snd.go b/tcpip/transport/tcp/snd.go
index a586b5d..bc5ebd3 100644
--- a/tcpip/transport/tcp/snd.go
+++ b/tcpip/transport/tcp/snd.go
@@ -273,7 +273,7 @@
 
 // sendAck sends an ACK segment.
 func (s *sender) sendAck() {
-	s.sendSegment(buffer.VectorisedView{}, flagAck, s.sndNxt)
+	s.sendSegment(buffer.VectorisedView{}, header.TCPFlagAck, s.sndNxt)
 }
 
 // updateRTO updates the retransmit timeout when a new roud-trip time is
@@ -483,7 +483,7 @@
 			// Assign flags. We don't do it above so that we can merge
 			// additional data if Nagle holds the segment.
 			seg.sequenceNumber = s.sndNxt
-			seg.flags = flagAck | flagPsh
+			seg.flags = header.TCPFlagAck | header.TCPFlagPsh
 		}
 
 		var segEnd seqnum.Value
@@ -491,11 +491,11 @@
 			if s.writeList.Back() != seg {
 				panic("FIN segments must be the final segment in the write list.")
 			}
-			seg.flags = flagAck | flagFin
+			seg.flags = header.TCPFlagAck | header.TCPFlagFin
 			segEnd = seg.sequenceNumber.Add(1)
 		} else {
 			// We're sending a non-FIN segment.
-			if seg.flags&flagFin != 0 {
+			if seg.flags&header.TCPFlagFin != 0 {
 				panic("Netstack queues FIN segments without data.")
 			}
 
diff --git a/tcpip/transport/udp/endpoint.go b/tcpip/transport/udp/endpoint.go
index d625567..23e7ce9 100644
--- a/tcpip/transport/udp/endpoint.go
+++ b/tcpip/transport/udp/endpoint.go
@@ -131,27 +131,6 @@
 	}
 }
 
-// NewConnectedEndpoint creates a new endpoint in the connected state using the
-// provided route.
-func NewConnectedEndpoint(stack *stack.Stack, r *stack.Route, id stack.TransportEndpointID, waiterQueue *waiter.Queue) (tcpip.Endpoint, *tcpip.Error) {
-	ep := newEndpoint(stack, r.NetProto, waiterQueue)
-
-	// Register new endpoint so that packets are routed to it.
-	if err := stack.RegisterTransportEndpoint(r.NICID(), []tcpip.NetworkProtocolNumber{r.NetProto}, ProtocolNumber, id, ep, ep.reusePort); err != nil {
-		ep.Close()
-		return nil, err
-	}
-
-	ep.id = id
-	ep.route = r.Clone()
-	ep.dstPort = id.RemotePort
-	ep.regNICID = r.NICID()
-
-	ep.state = stateConnected
-
-	return ep, nil
-}
-
 // Close puts the endpoint in a closed state and frees all resources
 // associated with it.
 func (e *endpoint) Close() {