diff options
author | Tamir Duberstein <tamird@google.com> | 2018-09-12 20:38:27 -0700 |
---|---|---|
committer | Shentubot <shentubot@google.com> | 2018-09-12 20:39:24 -0700 |
commit | 5adb3468d4de249df055d641e01ce6582b3a9388 (patch) | |
tree | fa75f573912b3647dcc7158961aa1085e572a8a1 /pkg/tcpip/network | |
parent | 9dec7a3db99d8c7045324bc6d8f0c27e88407f6c (diff) |
Add multicast support
PiperOrigin-RevId: 212750821
Change-Id: I822fd63e48c684b45fd91f9ce057867b7eceb792
Diffstat (limited to 'pkg/tcpip/network')
-rw-r--r-- | pkg/tcpip/network/arp/arp.go | 7 | ||||
-rw-r--r-- | pkg/tcpip/network/ip_test.go | 4 | ||||
-rw-r--r-- | pkg/tcpip/network/ipv4/BUILD | 18 | ||||
-rw-r--r-- | pkg/tcpip/network/ipv4/icmp.go | 2 | ||||
-rw-r--r-- | pkg/tcpip/network/ipv4/ipv4.go | 13 | ||||
-rw-r--r-- | pkg/tcpip/network/ipv4/ipv4_test.go | 92 | ||||
-rw-r--r-- | pkg/tcpip/network/ipv6/icmp.go | 5 | ||||
-rw-r--r-- | pkg/tcpip/network/ipv6/ipv6.go | 22 |
8 files changed, 138 insertions, 25 deletions
diff --git a/pkg/tcpip/network/arp/arp.go b/pkg/tcpip/network/arp/arp.go index 6bf4be868..8f64e3f42 100644 --- a/pkg/tcpip/network/arp/arp.go +++ b/pkg/tcpip/network/arp/arp.go @@ -51,6 +51,11 @@ type endpoint struct { linkAddrCache stack.LinkAddressCache } +// DefaultTTL is unused for ARP. It implements stack.NetworkEndpoint. +func (e *endpoint) DefaultTTL() uint8 { + return 0 +} + func (e *endpoint) MTU() uint32 { lmtu := e.linkEP.MTU() return lmtu - uint32(e.MaxHeaderLength()) @@ -74,7 +79,7 @@ func (e *endpoint) MaxHeaderLength() uint16 { func (e *endpoint) Close() {} -func (e *endpoint) WritePacket(r *stack.Route, hdr *buffer.Prependable, payload buffer.VectorisedView, protocol tcpip.TransportProtocolNumber) *tcpip.Error { +func (e *endpoint) WritePacket(r *stack.Route, hdr *buffer.Prependable, payload buffer.VectorisedView, protocol tcpip.TransportProtocolNumber, ttl uint8) *tcpip.Error { return tcpip.ErrNotSupported } diff --git a/pkg/tcpip/network/ip_test.go b/pkg/tcpip/network/ip_test.go index 1e92b7ae9..0cb53fb42 100644 --- a/pkg/tcpip/network/ip_test.go +++ b/pkg/tcpip/network/ip_test.go @@ -222,7 +222,7 @@ func TestIPv4Send(t *testing.T) { t.Fatalf("could not find route: %v", err) } vv := buffer.NewVectorisedView(len(payload), []buffer.View{payload}) - if err := ep.WritePacket(&r, &hdr, vv, 123); err != nil { + if err := ep.WritePacket(&r, &hdr, vv, 123, 123); err != nil { t.Fatalf("WritePacket failed: %v", err) } } @@ -461,7 +461,7 @@ func TestIPv6Send(t *testing.T) { t.Fatalf("could not find route: %v", err) } vv := buffer.NewVectorisedView(len(payload), []buffer.View{payload}) - if err := ep.WritePacket(&r, &hdr, vv, 123); err != nil { + if err := ep.WritePacket(&r, &hdr, vv, 123, 123); err != nil { t.Fatalf("WritePacket failed: %v", err) } } diff --git a/pkg/tcpip/network/ipv4/BUILD b/pkg/tcpip/network/ipv4/BUILD index 19314e9bd..90d65d531 100644 --- a/pkg/tcpip/network/ipv4/BUILD +++ b/pkg/tcpip/network/ipv4/BUILD @@ -1,6 +1,6 @@ package(licenses = ["notice"]) # Apache 2.0 -load("//tools/go_stateify:defs.bzl", "go_library") +load("//tools/go_stateify:defs.bzl", "go_library", "go_test") go_library( name = "ipv4", @@ -21,3 +21,19 @@ go_library( "//pkg/tcpip/stack", ], ) + +go_test( + name = "ipv4_test", + size = "small", + srcs = ["ipv4_test.go"], + deps = [ + "//pkg/tcpip", + "//pkg/tcpip/header", + "//pkg/tcpip/link/channel", + "//pkg/tcpip/link/sniffer", + "//pkg/tcpip/network/ipv4", + "//pkg/tcpip/stack", + "//pkg/tcpip/transport/udp", + "//pkg/waiter", + ], +) diff --git a/pkg/tcpip/network/ipv4/icmp.go b/pkg/tcpip/network/ipv4/icmp.go index de21e623e..74454f605 100644 --- a/pkg/tcpip/network/ipv4/icmp.go +++ b/pkg/tcpip/network/ipv4/icmp.go @@ -121,5 +121,5 @@ func sendPing4(r *stack.Route, code byte, data buffer.View) *tcpip.Error { icmpv4.SetChecksum(^header.Checksum(icmpv4, header.Checksum(data, 0))) vv := buffer.NewVectorisedView(len(data), []buffer.View{data}) - return r.WritePacket(&hdr, vv, header.ICMPv4ProtocolNumber) + return r.WritePacket(&hdr, vv, header.ICMPv4ProtocolNumber, r.DefaultTTL()) } diff --git a/pkg/tcpip/network/ipv4/ipv4.go b/pkg/tcpip/network/ipv4/ipv4.go index 478957827..0a2378a6a 100644 --- a/pkg/tcpip/network/ipv4/ipv4.go +++ b/pkg/tcpip/network/ipv4/ipv4.go @@ -44,10 +44,6 @@ const ( // buckets is the number of identifier buckets. buckets = 2048 - - // defaultIPv4TTL is the defautl TTL for IPv4 Packets egressed by - // Netstack. - defaultIPv4TTL = 255 ) type address [header.IPv4AddressSize]byte @@ -78,6 +74,11 @@ func newEndpoint(nicid tcpip.NICID, addr tcpip.Address, dispatcher stack.Transpo return e } +// DefaultTTL is the default time-to-live value for this endpoint. +func (e *endpoint) DefaultTTL() uint8 { + return 255 +} + // MTU implements stack.NetworkEndpoint.MTU. It returns the link-layer MTU minus // the network layer max header length. func (e *endpoint) MTU() uint32 { @@ -106,7 +107,7 @@ func (e *endpoint) MaxHeaderLength() uint16 { } // WritePacket writes a packet to the given destination address and protocol. -func (e *endpoint) WritePacket(r *stack.Route, hdr *buffer.Prependable, payload buffer.VectorisedView, protocol tcpip.TransportProtocolNumber) *tcpip.Error { +func (e *endpoint) WritePacket(r *stack.Route, hdr *buffer.Prependable, payload buffer.VectorisedView, protocol tcpip.TransportProtocolNumber, ttl uint8) *tcpip.Error { ip := header.IPv4(hdr.Prepend(header.IPv4MinimumSize)) length := uint16(hdr.UsedLength() + payload.Size()) id := uint32(0) @@ -119,7 +120,7 @@ func (e *endpoint) WritePacket(r *stack.Route, hdr *buffer.Prependable, payload IHL: header.IPv4MinimumSize, TotalLength: length, ID: uint16(id), - TTL: defaultIPv4TTL, + TTL: ttl, Protocol: uint8(protocol), SrcAddr: tcpip.Address(e.address[:]), DstAddr: r.RemoteAddress, diff --git a/pkg/tcpip/network/ipv4/ipv4_test.go b/pkg/tcpip/network/ipv4/ipv4_test.go new file mode 100644 index 000000000..2b7067a50 --- /dev/null +++ b/pkg/tcpip/network/ipv4/ipv4_test.go @@ -0,0 +1,92 @@ +// Copyright 2018 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ipv4_test + +import ( + "testing" + + "gvisor.googlesource.com/gvisor/pkg/tcpip" + "gvisor.googlesource.com/gvisor/pkg/tcpip/header" + "gvisor.googlesource.com/gvisor/pkg/tcpip/link/channel" + "gvisor.googlesource.com/gvisor/pkg/tcpip/link/sniffer" + "gvisor.googlesource.com/gvisor/pkg/tcpip/network/ipv4" + "gvisor.googlesource.com/gvisor/pkg/tcpip/stack" + "gvisor.googlesource.com/gvisor/pkg/tcpip/transport/udp" + "gvisor.googlesource.com/gvisor/pkg/waiter" +) + +func TestExcludeBroadcast(t *testing.T) { + s := stack.New([]string{ipv4.ProtocolName}, []string{udp.ProtocolName}, stack.Options{}) + + const defaultMTU = 65536 + id, _ := channel.New(256, defaultMTU, "") + if testing.Verbose() { + id = sniffer.New(id) + } + if err := s.CreateNIC(1, id); err != nil { + t.Fatalf("CreateNIC failed: %v", err) + } + + if err := s.AddAddress(1, ipv4.ProtocolNumber, header.IPv4Broadcast); err != nil { + t.Fatalf("AddAddress failed: %v", err) + } + if err := s.AddAddress(1, ipv4.ProtocolNumber, header.IPv4Any); err != nil { + t.Fatalf("AddAddress failed: %v", err) + } + + s.SetRouteTable([]tcpip.Route{{ + Destination: "\x00\x00\x00\x00", + Mask: "\x00\x00\x00\x00", + Gateway: "", + NIC: 1, + }}) + + randomAddr := tcpip.FullAddress{NIC: 1, Addr: "\x0a\x00\x00\x01", Port: 53} + + var wq waiter.Queue + t.Run("WithoutPrimaryAddress", func(t *testing.T) { + ep, err := s.NewEndpoint(udp.ProtocolNumber, ipv4.ProtocolNumber, &wq) + if err != nil { + t.Fatal(err) + } + defer ep.Close() + + // Cannot connect using a broadcast address as the source. + if err := ep.Connect(randomAddr); err != tcpip.ErrNoRoute { + t.Errorf("got ep.Connect(...) = %v, want = %v", err, tcpip.ErrNoRoute) + } + + // However, we can bind to a broadcast address to listen. + if err := ep.Bind(tcpip.FullAddress{Addr: header.IPv4Broadcast, Port: 53, NIC: 1}, nil); err != nil { + t.Errorf("Bind failed: %v", err) + } + }) + + t.Run("WithPrimaryAddress", func(t *testing.T) { + ep, err := s.NewEndpoint(udp.ProtocolNumber, ipv4.ProtocolNumber, &wq) + if err != nil { + t.Fatal(err) + } + defer ep.Close() + + // Add a valid primary endpoint address, now we can connect. + if err := s.AddAddress(1, ipv4.ProtocolNumber, "\x0a\x00\x00\x02"); err != nil { + t.Fatalf("AddAddress failed: %v", err) + } + if err := ep.Connect(randomAddr); err != nil { + t.Errorf("Connect failed: %v", err) + } + }) +} diff --git a/pkg/tcpip/network/ipv6/icmp.go b/pkg/tcpip/network/ipv6/icmp.go index b18b78830..2158ba8f7 100644 --- a/pkg/tcpip/network/ipv6/icmp.go +++ b/pkg/tcpip/network/ipv6/icmp.go @@ -62,7 +62,6 @@ func (e *endpoint) handleControl(typ stack.ControlType, extra uint32, vv *buffer e.dispatcher.DeliverTransportControlPacket(e.id.LocalAddress, h.DestinationAddress(), ProtocolNumber, p, typ, extra, vv) } -// TODO: take buffer.VectorisedView by value. func (e *endpoint) handleICMP(r *stack.Route, vv *buffer.VectorisedView) { v := vv.First() if len(v) < header.ICMPv6MinimumSize { @@ -107,7 +106,7 @@ func (e *endpoint) handleICMP(r *stack.Route, vv *buffer.VectorisedView) { pkt[icmpV6LengthOffset] = 1 copy(pkt[icmpV6LengthOffset+1:], r.LocalLinkAddress[:]) pkt.SetChecksum(icmpChecksum(pkt, r.LocalAddress, r.RemoteAddress, buffer.VectorisedView{})) - r.WritePacket(&hdr, buffer.VectorisedView{}, header.ICMPv6ProtocolNumber) + r.WritePacket(&hdr, buffer.VectorisedView{}, header.ICMPv6ProtocolNumber, r.DefaultTTL()) e.linkAddrCache.AddLinkAddress(e.nicid, r.RemoteAddress, r.RemoteLinkAddress) @@ -131,7 +130,7 @@ func (e *endpoint) handleICMP(r *stack.Route, vv *buffer.VectorisedView) { copy(pkt, h) pkt.SetType(header.ICMPv6EchoReply) pkt.SetChecksum(icmpChecksum(pkt, r.LocalAddress, r.RemoteAddress, *vv)) - r.WritePacket(&hdr, *vv, header.ICMPv6ProtocolNumber) + r.WritePacket(&hdr, *vv, header.ICMPv6ProtocolNumber, r.DefaultTTL()) case header.ICMPv6EchoReply: if len(v) < header.ICMPv6EchoMinimumSize { diff --git a/pkg/tcpip/network/ipv6/ipv6.go b/pkg/tcpip/network/ipv6/ipv6.go index 19dc1b49e..eb89168c3 100644 --- a/pkg/tcpip/network/ipv6/ipv6.go +++ b/pkg/tcpip/network/ipv6/ipv6.go @@ -43,17 +43,19 @@ const ( defaultIPv6HopLimit = 255 ) -type address [header.IPv6AddressSize]byte - type endpoint struct { nicid tcpip.NICID id stack.NetworkEndpointID - address address linkEP stack.LinkEndpoint linkAddrCache stack.LinkAddressCache dispatcher stack.TransportDispatcher } +// DefaultTTL is the default hop limit for this endpoint. +func (e *endpoint) DefaultTTL() uint8 { + return 255 +} + // MTU implements stack.NetworkEndpoint.MTU. It returns the link-layer MTU minus // the network layer max header length. func (e *endpoint) MTU() uint32 { @@ -82,14 +84,14 @@ func (e *endpoint) MaxHeaderLength() uint16 { } // WritePacket writes a packet to the given destination address and protocol. -func (e *endpoint) WritePacket(r *stack.Route, hdr *buffer.Prependable, payload buffer.VectorisedView, protocol tcpip.TransportProtocolNumber) *tcpip.Error { +func (e *endpoint) WritePacket(r *stack.Route, hdr *buffer.Prependable, payload buffer.VectorisedView, protocol tcpip.TransportProtocolNumber, ttl uint8) *tcpip.Error { length := uint16(hdr.UsedLength() + payload.Size()) ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize)) ip.Encode(&header.IPv6Fields{ PayloadLength: length, NextHeader: uint8(protocol), - HopLimit: defaultIPv6HopLimit, - SrcAddr: tcpip.Address(e.address[:]), + HopLimit: ttl, + SrcAddr: e.id.LocalAddress, DstAddr: r.RemoteAddress, }) r.Stats().IP.PacketsSent.Increment() @@ -149,15 +151,13 @@ func (*protocol) ParseAddresses(v buffer.View) (src, dst tcpip.Address) { // NewEndpoint creates a new ipv6 endpoint. func (p *protocol) NewEndpoint(nicid tcpip.NICID, addr tcpip.Address, linkAddrCache stack.LinkAddressCache, dispatcher stack.TransportDispatcher, linkEP stack.LinkEndpoint) (stack.NetworkEndpoint, *tcpip.Error) { - e := &endpoint{ + return &endpoint{ nicid: nicid, + id: stack.NetworkEndpointID{LocalAddress: addr}, linkEP: linkEP, linkAddrCache: linkAddrCache, dispatcher: dispatcher, - } - copy(e.address[:], addr) - e.id = stack.NetworkEndpointID{LocalAddress: tcpip.Address(e.address[:])} - return e, nil + }, nil } // SetOption implements NetworkProtocol.SetOption. |