mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Add multicast support
PiperOrigin-RevId: 212750821 Change-Id: I822fd63e48c684b45fd91f9ce057867b7eceb792
This commit is contained in:
committed by
Shentubot
parent
9dec7a3db9
commit
5adb3468d4
+3
-3
@@ -119,10 +119,10 @@ func (c *Client) Config() Config {
|
||||
// If the server sets a lease limit a timer is set to automatically
|
||||
// renew it.
|
||||
func (c *Client) Request(ctx context.Context, requestedAddr tcpip.Address) (cfg Config, reterr error) {
|
||||
if err := c.stack.AddAddress(c.nicid, ipv4.ProtocolNumber, "\xff\xff\xff\xff"); err != nil && err != tcpip.ErrDuplicateAddress {
|
||||
if err := c.stack.AddAddressWithOptions(c.nicid, ipv4.ProtocolNumber, "\xff\xff\xff\xff", stack.NeverPrimaryEndpoint); err != nil && err != tcpip.ErrDuplicateAddress {
|
||||
return Config{}, fmt.Errorf("dhcp: %v", err)
|
||||
}
|
||||
if err := c.stack.AddAddress(c.nicid, ipv4.ProtocolNumber, "\x00\x00\x00\x00"); err != nil && err != tcpip.ErrDuplicateAddress {
|
||||
if err := c.stack.AddAddressWithOptions(c.nicid, ipv4.ProtocolNumber, "\x00\x00\x00\x00", stack.NeverPrimaryEndpoint); err != nil && err != tcpip.ErrDuplicateAddress {
|
||||
return Config{}, fmt.Errorf("dhcp: %v", err)
|
||||
}
|
||||
defer c.stack.RemoveAddress(c.nicid, "\xff\xff\xff\xff")
|
||||
@@ -237,7 +237,7 @@ func (c *Client) Request(ctx context.Context, requestedAddr tcpip.Address) (cfg
|
||||
|
||||
// DHCPREQUEST
|
||||
addr := tcpip.Address(h.yiaddr())
|
||||
if err := c.stack.AddAddress(c.nicid, ipv4.ProtocolNumber, addr); err != nil {
|
||||
if err := c.stack.AddAddressWithOptions(c.nicid, ipv4.ProtocolNumber, addr, stack.FirstPrimaryEndpoint); err != nil {
|
||||
if err != tcpip.ErrDuplicateAddress {
|
||||
return Config{}, fmt.Errorf("adding address: %v", err)
|
||||
}
|
||||
|
||||
@@ -86,6 +86,22 @@ func DstAddr(addr tcpip.Address) NetworkChecker {
|
||||
}
|
||||
}
|
||||
|
||||
// TTL creates a checker that checks the TTL (ipv4) or HopLimit (ipv6).
|
||||
func TTL(ttl uint8) NetworkChecker {
|
||||
return func(t *testing.T, h []header.Network) {
|
||||
var v uint8
|
||||
switch ip := h[0].(type) {
|
||||
case header.IPv4:
|
||||
v = ip.TTL()
|
||||
case header.IPv6:
|
||||
v = ip.HopLimit()
|
||||
}
|
||||
if v != ttl {
|
||||
t.Fatalf("Bad TTL, got %v, want %v", v, ttl)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PayloadLen creates a checker that checks the payload length.
|
||||
func PayloadLen(plen int) NetworkChecker {
|
||||
return func(t *testing.T, h []header.Network) {
|
||||
|
||||
@@ -93,6 +93,12 @@ const (
|
||||
|
||||
// IPv4Version is the version of the ipv4 protocol.
|
||||
IPv4Version = 4
|
||||
|
||||
// IPv4Broadcast is the broadcast address of the IPv4 procotol.
|
||||
IPv4Broadcast tcpip.Address = "\xff\xff\xff\xff"
|
||||
|
||||
// IPv4Any is the non-routable IPv4 "any" meta address.
|
||||
IPv4Any tcpip.Address = "\x00\x00\x00\x00"
|
||||
)
|
||||
|
||||
// Flags that may be set in an IPv4 packet.
|
||||
@@ -259,3 +265,13 @@ func (b IPv4) IsValid(pktSize int) bool {
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// IsV4MulticastAddress determines if the provided address is an IPv4 multicast
|
||||
// address (range 224.0.0.0 to 239.255.255.255). The four most significant bits
|
||||
// will be 1110 = 0xe0.
|
||||
func IsV4MulticastAddress(addr tcpip.Address) bool {
|
||||
if len(addr) != IPv4AddressSize {
|
||||
return false
|
||||
}
|
||||
return (addr[0] & 0xf0) == 0xe0
|
||||
}
|
||||
|
||||
@@ -193,3 +193,12 @@ func IsV4MappedAddress(addr tcpip.Address) bool {
|
||||
|
||||
return strings.HasPrefix(string(addr), "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff")
|
||||
}
|
||||
|
||||
// IsV6MulticastAddress determines if the provided address is an IPv6
|
||||
// multicast address (anything starting with FF).
|
||||
func IsV6MulticastAddress(addr tcpip.Address) bool {
|
||||
if len(addr) != IPv6AddressSize {
|
||||
return false
|
||||
}
|
||||
return addr[0] == 0xff
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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.
|
||||
|
||||
+46
-7
@@ -43,6 +43,25 @@ type NIC struct {
|
||||
subnets []tcpip.Subnet
|
||||
}
|
||||
|
||||
// PrimaryEndpointBehavior is an enumeration of an endpoint's primacy behavior.
|
||||
type PrimaryEndpointBehavior int
|
||||
|
||||
const (
|
||||
// CanBePrimaryEndpoint indicates the endpoint can be used as a primary
|
||||
// endpoint for new connections with no local address. This is the
|
||||
// default when calling NIC.AddAddress.
|
||||
CanBePrimaryEndpoint PrimaryEndpointBehavior = iota
|
||||
|
||||
// FirstPrimaryEndpoint indicates the endpoint should be the first
|
||||
// primary endpoint considered. If there are multiple endpoints with
|
||||
// this behavior, the most recently-added one will be first.
|
||||
FirstPrimaryEndpoint
|
||||
|
||||
// NeverPrimaryEndpoint indicates the endpoint should never be a
|
||||
// primary endpoint.
|
||||
NeverPrimaryEndpoint
|
||||
)
|
||||
|
||||
func newNIC(stack *Stack, id tcpip.NICID, name string, ep LinkEndpoint) *NIC {
|
||||
return &NIC{
|
||||
stack: stack,
|
||||
@@ -141,6 +160,11 @@ func (n *NIC) primaryEndpoint(protocol tcpip.NetworkProtocolNumber) *referencedN
|
||||
|
||||
for e := list.Front(); e != nil; e = e.Next() {
|
||||
r := e.(*referencedNetworkEndpoint)
|
||||
// TODO: allow broadcast address when SO_BROADCAST is set.
|
||||
switch r.ep.ID().LocalAddress {
|
||||
case header.IPv4Broadcast, header.IPv4Any:
|
||||
continue
|
||||
}
|
||||
if r.tryIncRef() {
|
||||
return r
|
||||
}
|
||||
@@ -150,7 +174,7 @@ func (n *NIC) primaryEndpoint(protocol tcpip.NetworkProtocolNumber) *referencedN
|
||||
}
|
||||
|
||||
// findEndpoint finds the endpoint, if any, with the given address.
|
||||
func (n *NIC) findEndpoint(protocol tcpip.NetworkProtocolNumber, address tcpip.Address) *referencedNetworkEndpoint {
|
||||
func (n *NIC) findEndpoint(protocol tcpip.NetworkProtocolNumber, address tcpip.Address, peb PrimaryEndpointBehavior) *referencedNetworkEndpoint {
|
||||
id := NetworkEndpointID{address}
|
||||
|
||||
n.mu.RLock()
|
||||
@@ -171,7 +195,7 @@ func (n *NIC) findEndpoint(protocol tcpip.NetworkProtocolNumber, address tcpip.A
|
||||
n.mu.Lock()
|
||||
ref = n.endpoints[id]
|
||||
if ref == nil || !ref.tryIncRef() {
|
||||
ref, _ = n.addAddressLocked(protocol, address, true)
|
||||
ref, _ = n.addAddressLocked(protocol, address, peb, true)
|
||||
if ref != nil {
|
||||
ref.holdsInsertRef = false
|
||||
}
|
||||
@@ -180,7 +204,7 @@ func (n *NIC) findEndpoint(protocol tcpip.NetworkProtocolNumber, address tcpip.A
|
||||
return ref
|
||||
}
|
||||
|
||||
func (n *NIC) addAddressLocked(protocol tcpip.NetworkProtocolNumber, addr tcpip.Address, replace bool) (*referencedNetworkEndpoint, *tcpip.Error) {
|
||||
func (n *NIC) addAddressLocked(protocol tcpip.NetworkProtocolNumber, addr tcpip.Address, peb PrimaryEndpointBehavior, replace bool) (*referencedNetworkEndpoint, *tcpip.Error) {
|
||||
netProto, ok := n.stack.networkProtocols[protocol]
|
||||
if !ok {
|
||||
return nil, tcpip.ErrUnknownProtocol
|
||||
@@ -224,7 +248,12 @@ func (n *NIC) addAddressLocked(protocol tcpip.NetworkProtocolNumber, addr tcpip.
|
||||
n.primary[protocol] = l
|
||||
}
|
||||
|
||||
l.PushBack(ref)
|
||||
switch peb {
|
||||
case CanBePrimaryEndpoint:
|
||||
l.PushBack(ref)
|
||||
case FirstPrimaryEndpoint:
|
||||
l.PushFront(ref)
|
||||
}
|
||||
|
||||
return ref, nil
|
||||
}
|
||||
@@ -232,9 +261,15 @@ func (n *NIC) addAddressLocked(protocol tcpip.NetworkProtocolNumber, addr tcpip.
|
||||
// AddAddress adds a new address to n, so that it starts accepting packets
|
||||
// targeted at the given address (and network protocol).
|
||||
func (n *NIC) AddAddress(protocol tcpip.NetworkProtocolNumber, addr tcpip.Address) *tcpip.Error {
|
||||
return n.AddAddressWithOptions(protocol, addr, CanBePrimaryEndpoint)
|
||||
}
|
||||
|
||||
// AddAddressWithOptions is the same as AddAddress, but allows you to specify
|
||||
// whether the new endpoint can be primary or not.
|
||||
func (n *NIC) AddAddressWithOptions(protocol tcpip.NetworkProtocolNumber, addr tcpip.Address, peb PrimaryEndpointBehavior) *tcpip.Error {
|
||||
// Add the endpoint.
|
||||
n.mu.Lock()
|
||||
_, err := n.addAddressLocked(protocol, addr, false)
|
||||
_, err := n.addAddressLocked(protocol, addr, peb, false)
|
||||
n.mu.Unlock()
|
||||
|
||||
return err
|
||||
@@ -319,7 +354,11 @@ func (n *NIC) removeEndpointLocked(r *referencedNetworkEndpoint) {
|
||||
}
|
||||
|
||||
delete(n.endpoints, id)
|
||||
n.primary[r.protocol].Remove(r)
|
||||
wasInList := r.Next() != nil || r.Prev() != nil || r == n.primary[r.protocol].Front()
|
||||
if wasInList {
|
||||
n.primary[r.protocol].Remove(r)
|
||||
}
|
||||
|
||||
r.ep.Close()
|
||||
}
|
||||
|
||||
@@ -398,7 +437,7 @@ func (n *NIC) DeliverNetworkPacket(linkEP LinkEndpoint, remoteLinkAddr tcpip.Lin
|
||||
ref, ok = n.endpoints[id]
|
||||
if !ok || !ref.tryIncRef() {
|
||||
var err *tcpip.Error
|
||||
ref, err = n.addAddressLocked(protocol, dst, true)
|
||||
ref, err = n.addAddressLocked(protocol, dst, CanBePrimaryEndpoint, true)
|
||||
if err == nil {
|
||||
ref.holdsInsertRef = false
|
||||
}
|
||||
|
||||
@@ -124,6 +124,10 @@ type TransportDispatcher interface {
|
||||
// NetworkEndpoint is the interface that needs to be implemented by endpoints
|
||||
// of network layer protocols (e.g., ipv4, ipv6).
|
||||
type NetworkEndpoint interface {
|
||||
// DefaultTTL is the default time-to-live value (or hop limit, in ipv6)
|
||||
// for this endpoint.
|
||||
DefaultTTL() uint8
|
||||
|
||||
// MTU is the maximum transmission unit for this endpoint. This is
|
||||
// generally calculated as the MTU of the underlying data link endpoint
|
||||
// minus the network endpoint max header length.
|
||||
@@ -141,7 +145,7 @@ type NetworkEndpoint interface {
|
||||
|
||||
// WritePacket writes a packet to the given destination address and
|
||||
// protocol.
|
||||
WritePacket(r *Route, hdr *buffer.Prependable, payload buffer.VectorisedView, protocol tcpip.TransportProtocolNumber) *tcpip.Error
|
||||
WritePacket(r *Route, hdr *buffer.Prependable, payload buffer.VectorisedView, protocol tcpip.TransportProtocolNumber, ttl uint8) *tcpip.Error
|
||||
|
||||
// ID returns the network protocol endpoint ID.
|
||||
ID() *NetworkEndpointID
|
||||
|
||||
@@ -129,14 +129,19 @@ func (r *Route) IsResolutionRequired() bool {
|
||||
}
|
||||
|
||||
// WritePacket writes the packet through the given route.
|
||||
func (r *Route) WritePacket(hdr *buffer.Prependable, payload buffer.VectorisedView, protocol tcpip.TransportProtocolNumber) *tcpip.Error {
|
||||
err := r.ref.ep.WritePacket(r, hdr, payload, protocol)
|
||||
func (r *Route) WritePacket(hdr *buffer.Prependable, payload buffer.VectorisedView, protocol tcpip.TransportProtocolNumber, ttl uint8) *tcpip.Error {
|
||||
err := r.ref.ep.WritePacket(r, hdr, payload, protocol, ttl)
|
||||
if err == tcpip.ErrNoRoute {
|
||||
r.Stats().IP.OutgoingPacketErrors.Increment()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// DefaultTTL returns the default TTL of the underlying network endpoint.
|
||||
func (r *Route) DefaultTTL() uint8 {
|
||||
return r.ref.ep.DefaultTTL()
|
||||
}
|
||||
|
||||
// MTU returns the MTU of the underlying network endpoint.
|
||||
func (r *Route) MTU() uint32 {
|
||||
return r.ref.ep.MTU()
|
||||
|
||||
@@ -607,6 +607,12 @@ type NICStateFlags struct {
|
||||
|
||||
// AddAddress adds a new network-layer address to the specified NIC.
|
||||
func (s *Stack) AddAddress(id tcpip.NICID, protocol tcpip.NetworkProtocolNumber, addr tcpip.Address) *tcpip.Error {
|
||||
return s.AddAddressWithOptions(id, protocol, addr, CanBePrimaryEndpoint)
|
||||
}
|
||||
|
||||
// AddAddressWithOptions is the same as AddAddress, but allows you to specify
|
||||
// whether the new endpoint can be primary or not.
|
||||
func (s *Stack) AddAddressWithOptions(id tcpip.NICID, protocol tcpip.NetworkProtocolNumber, addr tcpip.Address, peb PrimaryEndpointBehavior) *tcpip.Error {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
@@ -615,7 +621,7 @@ func (s *Stack) AddAddress(id tcpip.NICID, protocol tcpip.NetworkProtocolNumber,
|
||||
return tcpip.ErrUnknownNICID
|
||||
}
|
||||
|
||||
return nic.AddAddress(protocol, addr)
|
||||
return nic.AddAddressWithOptions(protocol, addr, peb)
|
||||
}
|
||||
|
||||
// AddSubnet adds a subnet range to the specified NIC.
|
||||
@@ -703,7 +709,7 @@ func (s *Stack) FindRoute(id tcpip.NICID, localAddr, remoteAddr tcpip.Address, n
|
||||
|
||||
var ref *referencedNetworkEndpoint
|
||||
if len(localAddr) != 0 {
|
||||
ref = nic.findEndpoint(netProto, localAddr)
|
||||
ref = nic.findEndpoint(netProto, localAddr, CanBePrimaryEndpoint)
|
||||
} else {
|
||||
ref = nic.primaryEndpoint(netProto)
|
||||
}
|
||||
@@ -746,7 +752,7 @@ func (s *Stack) CheckLocalAddress(nicid tcpip.NICID, protocol tcpip.NetworkProto
|
||||
return 0
|
||||
}
|
||||
|
||||
ref := nic.findEndpoint(protocol, addr)
|
||||
ref := nic.findEndpoint(protocol, addr, CanBePrimaryEndpoint)
|
||||
if ref == nil {
|
||||
return 0
|
||||
}
|
||||
@@ -758,7 +764,7 @@ func (s *Stack) CheckLocalAddress(nicid tcpip.NICID, protocol tcpip.NetworkProto
|
||||
|
||||
// Go through all the NICs.
|
||||
for _, nic := range s.nics {
|
||||
ref := nic.findEndpoint(protocol, addr)
|
||||
ref := nic.findEndpoint(protocol, addr, CanBePrimaryEndpoint)
|
||||
if ref != nil {
|
||||
ref.decRef()
|
||||
return nic.id
|
||||
@@ -926,3 +932,14 @@ func (s *Stack) RemoveTCPProbe() {
|
||||
s.tcpProbeFunc = nil
|
||||
s.mu.Unlock()
|
||||
}
|
||||
|
||||
// JoinGroup joins the given multicast group on the given NIC.
|
||||
func (s *Stack) JoinGroup(protocol tcpip.NetworkProtocolNumber, nicID tcpip.NICID, multicastAddr tcpip.Address) *tcpip.Error {
|
||||
// TODO: notify network of subscription via igmp protocol.
|
||||
return s.AddAddressWithOptions(nicID, protocol, multicastAddr, NeverPrimaryEndpoint)
|
||||
}
|
||||
|
||||
// LeaveGroup leaves the given multicast group on the given NIC.
|
||||
func (s *Stack) LeaveGroup(protocol tcpip.NetworkProtocolNumber, nicID tcpip.NICID, multicastAddr tcpip.Address) *tcpip.Error {
|
||||
return s.RemoveAddress(nicID, multicastAddr)
|
||||
}
|
||||
|
||||
@@ -65,6 +65,10 @@ func (f *fakeNetworkEndpoint) NICID() tcpip.NICID {
|
||||
return f.nicid
|
||||
}
|
||||
|
||||
func (*fakeNetworkEndpoint) DefaultTTL() uint8 {
|
||||
return 123
|
||||
}
|
||||
|
||||
func (f *fakeNetworkEndpoint) ID() *stack.NetworkEndpointID {
|
||||
return &f.id
|
||||
}
|
||||
@@ -105,7 +109,7 @@ func (f *fakeNetworkEndpoint) Capabilities() stack.LinkEndpointCapabilities {
|
||||
return f.linkEP.Capabilities()
|
||||
}
|
||||
|
||||
func (f *fakeNetworkEndpoint) WritePacket(r *stack.Route, hdr *buffer.Prependable, payload buffer.VectorisedView, protocol tcpip.TransportProtocolNumber) *tcpip.Error {
|
||||
func (f *fakeNetworkEndpoint) WritePacket(r *stack.Route, hdr *buffer.Prependable, payload buffer.VectorisedView, protocol tcpip.TransportProtocolNumber, _ uint8) *tcpip.Error {
|
||||
// Increment the sent packet count in the protocol descriptor.
|
||||
f.proto.sendPacketCount[int(r.RemoteAddress[0])%len(f.proto.sendPacketCount)]++
|
||||
|
||||
@@ -269,7 +273,7 @@ func sendTo(t *testing.T, s *stack.Stack, addr tcpip.Address) {
|
||||
defer r.Release()
|
||||
|
||||
hdr := buffer.NewPrependable(int(r.MaxHeaderLength()))
|
||||
if err := r.WritePacket(&hdr, buffer.VectorisedView{}, fakeTransNumber); err != nil {
|
||||
if err := r.WritePacket(&hdr, buffer.VectorisedView{}, fakeTransNumber, 123); err != nil {
|
||||
t.Errorf("WritePacket failed: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ func (f *fakeTransportEndpoint) Write(p tcpip.Payload, opts tcpip.WriteOptions)
|
||||
return 0, err
|
||||
}
|
||||
vv := buffer.NewVectorisedView(len(v), []buffer.View{v})
|
||||
if err := f.route.WritePacket(&hdr, vv, fakeTransNumber); err != nil {
|
||||
if err := f.route.WritePacket(&hdr, vv, fakeTransNumber, 123); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
|
||||
@@ -453,6 +453,28 @@ type KeepaliveIntervalOption time.Duration
|
||||
// closed.
|
||||
type KeepaliveCountOption int
|
||||
|
||||
// MulticastTTLOption is used by SetSockOpt/GetSockOpt to control the default
|
||||
// TTL value for multicast messages. The default is 1.
|
||||
type MulticastTTLOption uint8
|
||||
|
||||
// MembershipOption is used by SetSockOpt/GetSockOpt as an argument to
|
||||
// AddMembershipOption and RemoveMembershipOption.
|
||||
type MembershipOption struct {
|
||||
NIC NICID
|
||||
InterfaceAddr Address
|
||||
MulticastAddr Address
|
||||
}
|
||||
|
||||
// AddMembershipOption is used by SetSockOpt/GetSockOpt to join a multicast
|
||||
// group identified by the given multicast address, on the interface matching
|
||||
// the given interface address.
|
||||
type AddMembershipOption MembershipOption
|
||||
|
||||
// RemoveMembershipOption is used by SetSockOpt/GetSockOpt to leave a multicast
|
||||
// group identified by the given multicast address, on the interface matching
|
||||
// the given interface address.
|
||||
type RemoveMembershipOption MembershipOption
|
||||
|
||||
// Route is a row in the routing table. It specifies through which NIC (and
|
||||
// gateway) sets of packets should be routed. A row is considered viable if the
|
||||
// masked target address matches the destination adddress in the row.
|
||||
|
||||
@@ -385,7 +385,7 @@ func sendPing4(r *stack.Route, ident uint16, 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())
|
||||
}
|
||||
|
||||
func sendPing6(r *stack.Route, ident uint16, data buffer.View) *tcpip.Error {
|
||||
@@ -408,8 +408,9 @@ func sendPing6(r *stack.Route, ident uint16, data buffer.View) *tcpip.Error {
|
||||
|
||||
icmpv6.SetChecksum(0)
|
||||
icmpv6.SetChecksum(^header.Checksum(icmpv6, header.Checksum(data, 0)))
|
||||
|
||||
vv := buffer.NewVectorisedView(len(data), []buffer.View{data})
|
||||
return r.WritePacket(&hdr, vv, header.ICMPv6ProtocolNumber)
|
||||
return r.WritePacket(&hdr, vv, header.ICMPv6ProtocolNumber, r.DefaultTTL())
|
||||
}
|
||||
|
||||
func (e *endpoint) checkV4Mapped(addr *tcpip.FullAddress, allowMismatch bool) (tcpip.NetworkProtocolNumber, *tcpip.Error) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user