| // Copyright 2018 The gVisor Authors. |
| // |
| // 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 stack |
| |
| import ( |
| "fmt" |
| "reflect" |
| |
| "gvisor.dev/gvisor/pkg/atomicbitops" |
| "gvisor.dev/gvisor/pkg/sync" |
| "gvisor.dev/gvisor/pkg/tcpip" |
| "gvisor.dev/gvisor/pkg/tcpip/header" |
| ) |
| |
| type linkResolver struct { |
| resolver LinkAddressResolver |
| |
| neigh neighborCache |
| } |
| |
| func (l *linkResolver) getNeighborLinkAddress(addr, localAddr tcpip.Address, onResolve func(LinkResolutionResult)) (tcpip.LinkAddress, <-chan struct{}, tcpip.Error) { |
| entry, ch, err := l.neigh.entry(addr, localAddr, onResolve) |
| return entry.LinkAddr, ch, err |
| } |
| |
| func (l *linkResolver) confirmReachable(addr tcpip.Address) { |
| l.neigh.handleUpperLevelConfirmation(addr) |
| } |
| |
| var _ NetworkInterface = (*nic)(nil) |
| var _ NetworkDispatcher = (*nic)(nil) |
| |
| // nic represents a "network interface card" to which the networking stack is |
| // attached. |
| type nic struct { |
| NetworkLinkEndpoint |
| |
| stack *Stack |
| id tcpip.NICID |
| name string |
| context NICContext |
| |
| stats sharedStats |
| |
| // The network endpoints themselves may be modified by calling the interface's |
| // methods, but the map reference and entries must be constant. |
| networkEndpoints map[tcpip.NetworkProtocolNumber]NetworkEndpoint |
| linkAddrResolvers map[tcpip.NetworkProtocolNumber]*linkResolver |
| duplicateAddressDetectors map[tcpip.NetworkProtocolNumber]DuplicateAddressDetector |
| |
| // enabled is set to 1 when the NIC is enabled and 0 when it is disabled. |
| enabled atomicbitops.Uint32 |
| |
| // linkResQueue holds packets that are waiting for link resolution to |
| // complete. |
| linkResQueue packetsPendingLinkResolution |
| |
| // mu protects annotated fields below. |
| mu sync.RWMutex |
| |
| // +checklocks:mu |
| spoofing bool |
| |
| // +checklocks:mu |
| promiscuous bool |
| |
| // packetEPsMu protects annotated fields below. |
| packetEPsMu sync.RWMutex |
| |
| // eps is protected by the mutex, but the values contained in it are not. |
| // |
| // +checklocks:packetEPsMu |
| packetEPs map[tcpip.NetworkProtocolNumber]*packetEndpointList |
| |
| qDisc QueueingDiscipline |
| } |
| |
| // makeNICStats initializes the NIC statistics and associates them to the global |
| // NIC statistics. |
| func makeNICStats(global tcpip.NICStats) sharedStats { |
| var stats sharedStats |
| tcpip.InitStatCounters(reflect.ValueOf(&stats.local).Elem()) |
| stats.init(&stats.local, &global) |
| return stats |
| } |
| |
| type packetEndpointList struct { |
| mu sync.RWMutex |
| |
| // eps is protected by mu, but the contained PacketEndpoint values are not. |
| // |
| // +checklocks:mu |
| eps []PacketEndpoint |
| } |
| |
| func (p *packetEndpointList) add(ep PacketEndpoint) { |
| p.mu.Lock() |
| defer p.mu.Unlock() |
| p.eps = append(p.eps, ep) |
| } |
| |
| func (p *packetEndpointList) remove(ep PacketEndpoint) { |
| p.mu.Lock() |
| defer p.mu.Unlock() |
| for i, epOther := range p.eps { |
| if epOther == ep { |
| p.eps = append(p.eps[:i], p.eps[i+1:]...) |
| break |
| } |
| } |
| } |
| |
| func (p *packetEndpointList) len() int { |
| p.mu.RLock() |
| defer p.mu.RUnlock() |
| return len(p.eps) |
| } |
| |
| // forEach calls fn with each endpoints in p while holding the read lock on p. |
| func (p *packetEndpointList) forEach(fn func(PacketEndpoint)) { |
| p.mu.RLock() |
| defer p.mu.RUnlock() |
| for _, ep := range p.eps { |
| fn(ep) |
| } |
| } |
| |
| var _ QueueingDiscipline = (*delegatingQueueingDiscipline)(nil) |
| |
| type delegatingQueueingDiscipline struct { |
| LinkWriter |
| } |
| |
| func (*delegatingQueueingDiscipline) Close() {} |
| |
| // WritePacket passes the packet through to the underlying LinkWriter's WritePackets. |
| func (qDisc *delegatingQueueingDiscipline) WritePacket(pkt *PacketBuffer) tcpip.Error { |
| var pkts PacketBufferList |
| pkts.PushBack(pkt) |
| _, err := qDisc.LinkWriter.WritePackets(pkts) |
| return err |
| } |
| |
| // newNIC returns a new NIC using the default NDP configurations from stack. |
| func newNIC(stack *Stack, id tcpip.NICID, ep LinkEndpoint, opts NICOptions) *nic { |
| // TODO(b/141011931): Validate a LinkEndpoint (ep) is valid. For |
| // example, make sure that the link address it provides is a valid |
| // unicast ethernet address. |
| |
| // If no queueing discipline was specified provide a stub implementation that |
| // just delegates to the lower link endpoint. |
| qDisc := opts.QDisc |
| if qDisc == nil { |
| qDisc = &delegatingQueueingDiscipline{LinkWriter: ep} |
| } |
| |
| // TODO(b/143357959): RFC 8200 section 5 requires that IPv6 endpoints |
| // observe an MTU of at least 1280 bytes. Ensure that this requirement |
| // of IPv6 is supported on this endpoint's LinkEndpoint. |
| nic := &nic{ |
| NetworkLinkEndpoint: ep, |
| stack: stack, |
| id: id, |
| name: opts.Name, |
| context: opts.Context, |
| stats: makeNICStats(stack.Stats().NICs), |
| networkEndpoints: make(map[tcpip.NetworkProtocolNumber]NetworkEndpoint), |
| linkAddrResolvers: make(map[tcpip.NetworkProtocolNumber]*linkResolver), |
| duplicateAddressDetectors: make(map[tcpip.NetworkProtocolNumber]DuplicateAddressDetector), |
| qDisc: qDisc, |
| } |
| nic.linkResQueue.init(nic) |
| |
| nic.packetEPsMu.Lock() |
| defer nic.packetEPsMu.Unlock() |
| |
| nic.packetEPs = make(map[tcpip.NetworkProtocolNumber]*packetEndpointList) |
| |
| resolutionRequired := ep.Capabilities()&CapabilityResolutionRequired != 0 |
| |
| for _, netProto := range stack.networkProtocols { |
| netNum := netProto.Number() |
| netEP := netProto.NewEndpoint(nic, nic) |
| nic.networkEndpoints[netNum] = netEP |
| |
| if resolutionRequired { |
| if r, ok := netEP.(LinkAddressResolver); ok { |
| l := &linkResolver{resolver: r} |
| l.neigh.init(nic, r) |
| nic.linkAddrResolvers[r.LinkAddressProtocol()] = l |
| } |
| } |
| |
| if d, ok := netEP.(DuplicateAddressDetector); ok { |
| nic.duplicateAddressDetectors[d.DuplicateAddressProtocol()] = d |
| } |
| } |
| |
| nic.NetworkLinkEndpoint.Attach(nic) |
| |
| return nic |
| } |
| |
| func (n *nic) getNetworkEndpoint(proto tcpip.NetworkProtocolNumber) NetworkEndpoint { |
| return n.networkEndpoints[proto] |
| } |
| |
| // Enabled implements NetworkInterface. |
| func (n *nic) Enabled() bool { |
| return n.enabled.Load() == 1 |
| } |
| |
| // setEnabled sets the enabled status for the NIC. |
| // |
| // Returns true if the enabled status was updated. |
| func (n *nic) setEnabled(v bool) bool { |
| if v { |
| return n.enabled.Swap(1) == 0 |
| } |
| return n.enabled.Swap(0) == 1 |
| } |
| |
| // disable disables n. |
| // |
| // It undoes the work done by enable. |
| func (n *nic) disable() { |
| n.mu.Lock() |
| n.disableLocked() |
| n.mu.Unlock() |
| } |
| |
| // disableLocked disables n. |
| // |
| // It undoes the work done by enable. |
| // |
| // n MUST be locked. |
| func (n *nic) disableLocked() { |
| if !n.Enabled() { |
| return |
| } |
| |
| // TODO(gvisor.dev/issue/1491): Should Routes that are currently bound to n be |
| // invalidated? Currently, Routes will continue to work when a NIC is enabled |
| // again, and applications may not know that the underlying NIC was ever |
| // disabled. |
| |
| for _, ep := range n.networkEndpoints { |
| ep.Disable() |
| |
| // Clear the neighbour table (including static entries) as we cannot |
| // guarantee that the current neighbour table will be valid when the NIC is |
| // enabled again. |
| // |
| // This matches linux's behaviour at the time of writing: |
| // https://github.com/torvalds/linux/blob/71c061d2443814de15e177489d5cc00a4a253ef3/net/core/neighbour.c#L371 |
| netProto := ep.NetworkProtocolNumber() |
| switch err := n.clearNeighbors(netProto); err.(type) { |
| case nil, *tcpip.ErrNotSupported: |
| default: |
| panic(fmt.Sprintf("n.clearNeighbors(%d): %s", netProto, err)) |
| } |
| } |
| |
| if !n.setEnabled(false) { |
| panic("should have only done work to disable the NIC if it was enabled") |
| } |
| } |
| |
| // enable enables n. |
| // |
| // If the stack has IPv6 enabled, enable will join the IPv6 All-Nodes Multicast |
| // address (ff02::1), start DAD for permanent addresses, and start soliciting |
| // routers if the stack is not operating as a router. If the stack is also |
| // configured to auto-generate a link-local address, one will be generated. |
| func (n *nic) enable() tcpip.Error { |
| n.mu.Lock() |
| defer n.mu.Unlock() |
| |
| if !n.setEnabled(true) { |
| return nil |
| } |
| |
| for _, ep := range n.networkEndpoints { |
| if err := ep.Enable(); err != nil { |
| return err |
| } |
| } |
| |
| return nil |
| } |
| |
| // remove detaches NIC from the link endpoint and releases network endpoint |
| // resources. This guarantees no packets between this NIC and the network |
| // stack. |
| func (n *nic) remove() tcpip.Error { |
| n.mu.Lock() |
| defer n.mu.Unlock() |
| |
| n.disableLocked() |
| |
| for _, ep := range n.networkEndpoints { |
| ep.Close() |
| } |
| |
| // drain and drop any packets pending link resolution. |
| n.linkResQueue.cancel() |
| |
| // Prevent packets from going down to the link before shutting the link down. |
| n.qDisc.Close() |
| n.NetworkLinkEndpoint.Attach(nil) |
| |
| return nil |
| } |
| |
| // setPromiscuousMode enables or disables promiscuous mode. |
| func (n *nic) setPromiscuousMode(enable bool) { |
| n.mu.Lock() |
| n.promiscuous = enable |
| n.mu.Unlock() |
| } |
| |
| // Promiscuous implements NetworkInterface. |
| func (n *nic) Promiscuous() bool { |
| n.mu.RLock() |
| rv := n.promiscuous |
| n.mu.RUnlock() |
| return rv |
| } |
| |
| // IsLoopback implements NetworkInterface. |
| func (n *nic) IsLoopback() bool { |
| return n.NetworkLinkEndpoint.Capabilities()&CapabilityLoopback != 0 |
| } |
| |
| // WritePacket implements NetworkEndpoint. |
| func (n *nic) WritePacket(r *Route, pkt *PacketBuffer) tcpip.Error { |
| routeInfo, _, err := r.resolvedFields(nil) |
| switch err.(type) { |
| case nil: |
| pkt.EgressRoute = routeInfo |
| return n.writePacket(pkt) |
| case *tcpip.ErrWouldBlock: |
| // As per relevant RFCs, we should queue packets while we wait for link |
| // resolution to complete. |
| // |
| // RFC 1122 section 2.3.2.2 (for IPv4): |
| // The link layer SHOULD save (rather than discard) at least |
| // one (the latest) packet of each set of packets destined to |
| // the same unresolved IP address, and transmit the saved |
| // packet when the address has been resolved. |
| // |
| // RFC 4861 section 7.2.2 (for IPv6): |
| // While waiting for address resolution to complete, the sender MUST, for |
| // each neighbor, retain a small queue of packets waiting for address |
| // resolution to complete. The queue MUST hold at least one packet, and |
| // MAY contain more. However, the number of queued packets per neighbor |
| // SHOULD be limited to some small value. When a queue overflows, the new |
| // arrival SHOULD replace the oldest entry. Once address resolution |
| // completes, the node transmits any queued packets. |
| return n.linkResQueue.enqueue(r, pkt) |
| default: |
| return err |
| } |
| } |
| |
| // WritePacketToRemote implements NetworkInterface. |
| func (n *nic) WritePacketToRemote(remoteLinkAddr tcpip.LinkAddress, pkt *PacketBuffer) tcpip.Error { |
| pkt.EgressRoute = RouteInfo{ |
| routeInfo: routeInfo{ |
| NetProto: pkt.NetworkProtocolNumber, |
| LocalLinkAddress: n.LinkAddress(), |
| }, |
| RemoteLinkAddress: remoteLinkAddr, |
| } |
| return n.writePacket(pkt) |
| } |
| |
| func (n *nic) writePacket(pkt *PacketBuffer) tcpip.Error { |
| n.NetworkLinkEndpoint.AddHeader(pkt) |
| return n.writeRawPacket(pkt) |
| } |
| |
| func (n *nic) writeRawPacket(pkt *PacketBuffer) tcpip.Error { |
| if err := n.qDisc.WritePacket(pkt); err != nil { |
| if _, ok := err.(*tcpip.ErrNoBufferSpace); ok { |
| n.stats.txPacketsDroppedNoBufferSpace.Increment() |
| } |
| return err |
| } |
| |
| n.stats.tx.packets.Increment() |
| n.stats.tx.bytes.IncrementBy(uint64(pkt.Size())) |
| return nil |
| } |
| |
| // setSpoofing enables or disables address spoofing. |
| func (n *nic) setSpoofing(enable bool) { |
| n.mu.Lock() |
| n.spoofing = enable |
| n.mu.Unlock() |
| } |
| |
| // Spoofing implements NetworkInterface. |
| func (n *nic) Spoofing() bool { |
| n.mu.RLock() |
| defer n.mu.RUnlock() |
| return n.spoofing |
| } |
| |
| // primaryAddress returns an address that can be used to communicate with |
| // remoteAddr. |
| func (n *nic) primaryEndpoint(protocol tcpip.NetworkProtocolNumber, remoteAddr tcpip.Address) AssignableAddressEndpoint { |
| ep, ok := n.networkEndpoints[protocol] |
| if !ok { |
| return nil |
| } |
| |
| addressableEndpoint, ok := ep.(AddressableEndpoint) |
| if !ok { |
| return nil |
| } |
| |
| n.mu.RLock() |
| spoofing := n.spoofing |
| n.mu.RUnlock() |
| |
| return addressableEndpoint.AcquireOutgoingPrimaryAddress(remoteAddr, spoofing) |
| } |
| |
| type getAddressBehaviour int |
| |
| const ( |
| // spoofing indicates that the NIC's spoofing flag should be observed when |
| // getting a NIC's address endpoint. |
| spoofing getAddressBehaviour = iota |
| |
| // promiscuous indicates that the NIC's promiscuous flag should be observed |
| // when getting a NIC's address endpoint. |
| promiscuous |
| ) |
| |
| func (n *nic) getAddress(protocol tcpip.NetworkProtocolNumber, dst tcpip.Address) AssignableAddressEndpoint { |
| return n.getAddressOrCreateTemp(protocol, dst, CanBePrimaryEndpoint, promiscuous) |
| } |
| |
| func (n *nic) hasAddress(protocol tcpip.NetworkProtocolNumber, addr tcpip.Address) bool { |
| ep := n.getAddressOrCreateTempInner(protocol, addr, false, NeverPrimaryEndpoint) |
| if ep != nil { |
| ep.DecRef() |
| return true |
| } |
| |
| return false |
| } |
| |
| // findEndpoint finds the endpoint, if any, with the given address. |
| func (n *nic) findEndpoint(protocol tcpip.NetworkProtocolNumber, address tcpip.Address, peb PrimaryEndpointBehavior) AssignableAddressEndpoint { |
| return n.getAddressOrCreateTemp(protocol, address, peb, spoofing) |
| } |
| |
| // getAddressEpOrCreateTemp returns the address endpoint for the given protocol |
| // and address. |
| // |
| // If none exists a temporary one may be created if we are in promiscuous mode |
| // or spoofing. Promiscuous mode will only be checked if promiscuous is true. |
| // Similarly, spoofing will only be checked if spoofing is true. |
| // |
| // If the address is the IPv4 broadcast address for an endpoint's network, that |
| // endpoint will be returned. |
| func (n *nic) getAddressOrCreateTemp(protocol tcpip.NetworkProtocolNumber, address tcpip.Address, peb PrimaryEndpointBehavior, tempRef getAddressBehaviour) AssignableAddressEndpoint { |
| n.mu.RLock() |
| var spoofingOrPromiscuous bool |
| switch tempRef { |
| case spoofing: |
| spoofingOrPromiscuous = n.spoofing |
| case promiscuous: |
| spoofingOrPromiscuous = n.promiscuous |
| } |
| n.mu.RUnlock() |
| return n.getAddressOrCreateTempInner(protocol, address, spoofingOrPromiscuous, peb) |
| } |
| |
| // getAddressOrCreateTempInner is like getAddressEpOrCreateTemp except a boolean |
| // is passed to indicate whether or not we should generate temporary endpoints. |
| func (n *nic) getAddressOrCreateTempInner(protocol tcpip.NetworkProtocolNumber, address tcpip.Address, createTemp bool, peb PrimaryEndpointBehavior) AssignableAddressEndpoint { |
| ep, ok := n.networkEndpoints[protocol] |
| if !ok { |
| return nil |
| } |
| |
| addressableEndpoint, ok := ep.(AddressableEndpoint) |
| if !ok { |
| return nil |
| } |
| |
| return addressableEndpoint.AcquireAssignedAddress(address, createTemp, peb) |
| } |
| |
| // 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(protocolAddress tcpip.ProtocolAddress, properties AddressProperties) tcpip.Error { |
| ep, ok := n.networkEndpoints[protocolAddress.Protocol] |
| if !ok { |
| return &tcpip.ErrUnknownProtocol{} |
| } |
| |
| addressableEndpoint, ok := ep.(AddressableEndpoint) |
| if !ok { |
| return &tcpip.ErrNotSupported{} |
| } |
| |
| addressEndpoint, err := addressableEndpoint.AddAndAcquirePermanentAddress(protocolAddress.AddressWithPrefix, properties) |
| if err == nil { |
| // We have no need for the address endpoint. |
| addressEndpoint.DecRef() |
| } |
| return err |
| } |
| |
| // allPermanentAddresses returns all permanent addresses associated with |
| // this NIC. |
| func (n *nic) allPermanentAddresses() []tcpip.ProtocolAddress { |
| var addrs []tcpip.ProtocolAddress |
| for p, ep := range n.networkEndpoints { |
| addressableEndpoint, ok := ep.(AddressableEndpoint) |
| if !ok { |
| continue |
| } |
| |
| for _, a := range addressableEndpoint.PermanentAddresses() { |
| addrs = append(addrs, tcpip.ProtocolAddress{Protocol: p, AddressWithPrefix: a}) |
| } |
| } |
| return addrs |
| } |
| |
| // primaryAddresses returns the primary addresses associated with this NIC. |
| func (n *nic) primaryAddresses() []tcpip.ProtocolAddress { |
| var addrs []tcpip.ProtocolAddress |
| for p, ep := range n.networkEndpoints { |
| addressableEndpoint, ok := ep.(AddressableEndpoint) |
| if !ok { |
| continue |
| } |
| |
| for _, a := range addressableEndpoint.PrimaryAddresses() { |
| addrs = append(addrs, tcpip.ProtocolAddress{Protocol: p, AddressWithPrefix: a}) |
| } |
| } |
| return addrs |
| } |
| |
| // PrimaryAddress implements NetworkInterface. |
| func (n *nic) PrimaryAddress(proto tcpip.NetworkProtocolNumber) (tcpip.AddressWithPrefix, tcpip.Error) { |
| ep, ok := n.networkEndpoints[proto] |
| if !ok { |
| return tcpip.AddressWithPrefix{}, &tcpip.ErrUnknownProtocol{} |
| } |
| |
| addressableEndpoint, ok := ep.(AddressableEndpoint) |
| if !ok { |
| return tcpip.AddressWithPrefix{}, &tcpip.ErrNotSupported{} |
| } |
| |
| return addressableEndpoint.MainAddress(), nil |
| } |
| |
| // removeAddress removes an address from n. |
| func (n *nic) removeAddress(addr tcpip.Address) tcpip.Error { |
| for _, ep := range n.networkEndpoints { |
| addressableEndpoint, ok := ep.(AddressableEndpoint) |
| if !ok { |
| continue |
| } |
| |
| switch err := addressableEndpoint.RemovePermanentAddress(addr); err.(type) { |
| case *tcpip.ErrBadLocalAddress: |
| continue |
| default: |
| return err |
| } |
| } |
| |
| return &tcpip.ErrBadLocalAddress{} |
| } |
| |
| func (n *nic) setAddressDeprecated(addr tcpip.Address, deprecated bool) tcpip.Error { |
| for _, ep := range n.networkEndpoints { |
| ep, ok := ep.(AddressableEndpoint) |
| if !ok { |
| continue |
| } |
| |
| switch err := ep.SetDeprecated(addr, deprecated); err.(type) { |
| case *tcpip.ErrBadLocalAddress: |
| continue |
| default: |
| return err |
| } |
| } |
| |
| return &tcpip.ErrBadLocalAddress{} |
| } |
| |
| func (n *nic) getLinkAddress(addr, localAddr tcpip.Address, protocol tcpip.NetworkProtocolNumber, onResolve func(LinkResolutionResult)) tcpip.Error { |
| linkRes, ok := n.linkAddrResolvers[protocol] |
| if !ok { |
| return &tcpip.ErrNotSupported{} |
| } |
| |
| if linkAddr, ok := linkRes.resolver.ResolveStaticAddress(addr); ok { |
| onResolve(LinkResolutionResult{LinkAddress: linkAddr, Err: nil}) |
| return nil |
| } |
| |
| _, _, err := linkRes.getNeighborLinkAddress(addr, localAddr, onResolve) |
| return err |
| } |
| |
| func (n *nic) neighbors(protocol tcpip.NetworkProtocolNumber) ([]NeighborEntry, tcpip.Error) { |
| if linkRes, ok := n.linkAddrResolvers[protocol]; ok { |
| return linkRes.neigh.entries(), nil |
| } |
| |
| return nil, &tcpip.ErrNotSupported{} |
| } |
| |
| func (n *nic) addStaticNeighbor(addr tcpip.Address, protocol tcpip.NetworkProtocolNumber, linkAddress tcpip.LinkAddress) tcpip.Error { |
| if linkRes, ok := n.linkAddrResolvers[protocol]; ok { |
| linkRes.neigh.addStaticEntry(addr, linkAddress) |
| return nil |
| } |
| |
| return &tcpip.ErrNotSupported{} |
| } |
| |
| func (n *nic) removeNeighbor(protocol tcpip.NetworkProtocolNumber, addr tcpip.Address) tcpip.Error { |
| if linkRes, ok := n.linkAddrResolvers[protocol]; ok { |
| if !linkRes.neigh.removeEntry(addr) { |
| return &tcpip.ErrBadAddress{} |
| } |
| return nil |
| } |
| |
| return &tcpip.ErrNotSupported{} |
| } |
| |
| func (n *nic) clearNeighbors(protocol tcpip.NetworkProtocolNumber) tcpip.Error { |
| if linkRes, ok := n.linkAddrResolvers[protocol]; ok { |
| linkRes.neigh.clear() |
| return nil |
| } |
| |
| return &tcpip.ErrNotSupported{} |
| } |
| |
| // joinGroup adds a new endpoint for the given multicast address, if none |
| // exists yet. Otherwise it just increments its count. |
| func (n *nic) joinGroup(protocol tcpip.NetworkProtocolNumber, addr tcpip.Address) tcpip.Error { |
| // TODO(b/143102137): When implementing MLD, make sure MLD packets are |
| // not sent unless a valid link-local address is available for use on n |
| // as an MLD packet's source address must be a link-local address as |
| // outlined in RFC 3810 section 5. |
| |
| ep, ok := n.networkEndpoints[protocol] |
| if !ok { |
| return &tcpip.ErrNotSupported{} |
| } |
| |
| gep, ok := ep.(GroupAddressableEndpoint) |
| if !ok { |
| return &tcpip.ErrNotSupported{} |
| } |
| |
| return gep.JoinGroup(addr) |
| } |
| |
| // leaveGroup decrements the count for the given multicast address, and when it |
| // reaches zero removes the endpoint for this address. |
| func (n *nic) leaveGroup(protocol tcpip.NetworkProtocolNumber, addr tcpip.Address) tcpip.Error { |
| ep, ok := n.networkEndpoints[protocol] |
| if !ok { |
| return &tcpip.ErrNotSupported{} |
| } |
| |
| gep, ok := ep.(GroupAddressableEndpoint) |
| if !ok { |
| return &tcpip.ErrNotSupported{} |
| } |
| |
| return gep.LeaveGroup(addr) |
| } |
| |
| // isInGroup returns true if n has joined the multicast group addr. |
| func (n *nic) isInGroup(addr tcpip.Address) bool { |
| for _, ep := range n.networkEndpoints { |
| gep, ok := ep.(GroupAddressableEndpoint) |
| if !ok { |
| continue |
| } |
| |
| if gep.IsInGroup(addr) { |
| return true |
| } |
| } |
| |
| return false |
| } |
| |
| // DeliverNetworkPacket finds the appropriate network protocol endpoint and |
| // hands the packet over for further processing. This function is called when |
| // the NIC receives a packet from the link endpoint. |
| func (n *nic) DeliverNetworkPacket(protocol tcpip.NetworkProtocolNumber, pkt *PacketBuffer) { |
| enabled := n.Enabled() |
| // If the NIC is not yet enabled, don't receive any packets. |
| if !enabled { |
| n.stats.disabledRx.packets.Increment() |
| n.stats.disabledRx.bytes.IncrementBy(uint64(pkt.Data().Size())) |
| return |
| } |
| |
| n.stats.rx.packets.Increment() |
| n.stats.rx.bytes.IncrementBy(uint64(pkt.Data().Size())) |
| |
| networkEndpoint, ok := n.networkEndpoints[protocol] |
| if !ok { |
| n.stats.unknownL3ProtocolRcvdPacketCounts.Increment(uint64(protocol)) |
| return |
| } |
| |
| pkt.RXTransportChecksumValidated = n.NetworkLinkEndpoint.Capabilities()&CapabilityRXChecksumOffload != 0 |
| |
| networkEndpoint.HandlePacket(pkt) |
| } |
| |
| func (n *nic) DeliverLinkPacket(protocol tcpip.NetworkProtocolNumber, pkt *PacketBuffer, incoming bool) { |
| // Deliver to interested packet endpoints without holding NIC lock. |
| var packetEPPkt *PacketBuffer |
| defer func() { |
| if packetEPPkt != nil { |
| packetEPPkt.DecRef() |
| } |
| }() |
| deliverPacketEPs := func(ep PacketEndpoint) { |
| if packetEPPkt == nil { |
| // Packet endpoints hold the full packet. |
| // |
| // We perform a deep copy because higher-level endpoints may point to |
| // the middle of a view that is held by a packet endpoint. Save/Restore |
| // does not support overlapping slices and will panic in this case. |
| // |
| // TODO(https://gvisor.dev/issue/6517): Avoid this copy once S/R supports |
| // overlapping slices (e.g. by passing a shallow copy of pkt to the packet |
| // endpoint). |
| packetEPPkt = NewPacketBuffer(PacketBufferOptions{ |
| Data: PayloadSince(pkt.LinkHeader()).ToVectorisedView(), |
| }) |
| // If a link header was populated in the original packet buffer, then |
| // populate it in the packet buffer we provide to packet endpoints as |
| // packet endpoints inspect link headers. |
| packetEPPkt.LinkHeader().Consume(pkt.LinkHeader().View().Size()) |
| |
| if incoming { |
| packetEPPkt.PktType = tcpip.PacketHost |
| } else { |
| packetEPPkt.PktType = tcpip.PacketOutgoing |
| } |
| } |
| |
| clone := packetEPPkt.Clone() |
| defer clone.DecRef() |
| ep.HandlePacket(n.id, protocol, clone) |
| } |
| |
| n.packetEPsMu.Lock() |
| // Are any packet type sockets listening for this network protocol? |
| protoEPs, protoEPsOK := n.packetEPs[protocol] |
| // Other packet type sockets that are listening for all protocols. |
| anyEPs, anyEPsOK := n.packetEPs[header.EthernetProtocolAll] |
| n.packetEPsMu.Unlock() |
| |
| // On Linux, only ETH_P_ALL endpoints get outbound packets. |
| if incoming && protoEPsOK { |
| protoEPs.forEach(deliverPacketEPs) |
| } |
| if anyEPsOK { |
| anyEPs.forEach(deliverPacketEPs) |
| } |
| } |
| |
| // DeliverTransportPacket delivers the packets to the appropriate transport |
| // protocol endpoint. |
| func (n *nic) DeliverTransportPacket(protocol tcpip.TransportProtocolNumber, pkt *PacketBuffer) TransportPacketDisposition { |
| state, ok := n.stack.transportProtocols[protocol] |
| if !ok { |
| n.stats.unknownL4ProtocolRcvdPacketCounts.Increment(uint64(protocol)) |
| return TransportPacketProtocolUnreachable |
| } |
| |
| transProto := state.proto |
| |
| if pkt.TransportHeader().View().IsEmpty() { |
| n.stats.malformedL4RcvdPackets.Increment() |
| return TransportPacketHandled |
| } |
| |
| srcPort, dstPort, err := transProto.ParsePorts(pkt.TransportHeader().View()) |
| if err != nil { |
| n.stats.malformedL4RcvdPackets.Increment() |
| return TransportPacketHandled |
| } |
| |
| netProto, ok := n.stack.networkProtocols[pkt.NetworkProtocolNumber] |
| if !ok { |
| panic(fmt.Sprintf("expected network protocol = %d, have = %#v", pkt.NetworkProtocolNumber, n.stack.networkProtocolNumbers())) |
| } |
| |
| src, dst := netProto.ParseAddresses(pkt.NetworkHeader().View()) |
| id := TransportEndpointID{ |
| LocalPort: dstPort, |
| LocalAddress: dst, |
| RemotePort: srcPort, |
| RemoteAddress: src, |
| } |
| if n.stack.demux.deliverPacket(protocol, pkt, id) { |
| return TransportPacketHandled |
| } |
| |
| // Try to deliver to per-stack default handler. |
| if state.defaultHandler != nil { |
| if state.defaultHandler(id, pkt) { |
| return TransportPacketHandled |
| } |
| } |
| |
| // We could not find an appropriate destination for this packet so |
| // give the protocol specific error handler a chance to handle it. |
| // If it doesn't handle it then we should do so. |
| switch res := transProto.HandleUnknownDestinationPacket(id, pkt); res { |
| case UnknownDestinationPacketMalformed: |
| n.stats.malformedL4RcvdPackets.Increment() |
| return TransportPacketHandled |
| case UnknownDestinationPacketUnhandled: |
| return TransportPacketDestinationPortUnreachable |
| case UnknownDestinationPacketHandled: |
| return TransportPacketHandled |
| default: |
| panic(fmt.Sprintf("unrecognized result from HandleUnknownDestinationPacket = %d", res)) |
| } |
| } |
| |
| // DeliverTransportError implements TransportDispatcher. |
| func (n *nic) DeliverTransportError(local, remote tcpip.Address, net tcpip.NetworkProtocolNumber, trans tcpip.TransportProtocolNumber, transErr TransportError, pkt *PacketBuffer) { |
| state, ok := n.stack.transportProtocols[trans] |
| if !ok { |
| return |
| } |
| |
| transProto := state.proto |
| |
| // ICMPv4 only guarantees that 8 bytes of the transport protocol will |
| // be present in the payload. We know that the ports are within the |
| // first 8 bytes for all known transport protocols. |
| transHeader, ok := pkt.Data().PullUp(8) |
| if !ok { |
| return |
| } |
| |
| srcPort, dstPort, err := transProto.ParsePorts(transHeader) |
| if err != nil { |
| return |
| } |
| |
| id := TransportEndpointID{srcPort, local, dstPort, remote} |
| if n.stack.demux.deliverError(n, net, trans, transErr, pkt, id) { |
| return |
| } |
| } |
| |
| // DeliverRawPacket implements TransportDispatcher. |
| func (n *nic) DeliverRawPacket(protocol tcpip.TransportProtocolNumber, pkt *PacketBuffer) { |
| // For ICMPv4 only we validate the header length for compatibility with |
| // raw(7) ICMP_FILTER. The same check is made in Linux here: |
| // https://github.com/torvalds/linux/blob/70585216/net/ipv4/raw.c#L189. |
| if protocol == header.ICMPv4ProtocolNumber && pkt.TransportHeader().View().Size()+pkt.Data().Size() < header.ICMPv4MinimumSize { |
| return |
| } |
| n.stack.demux.deliverRawPacket(protocol, pkt) |
| } |
| |
| // ID implements NetworkInterface. |
| func (n *nic) ID() tcpip.NICID { |
| return n.id |
| } |
| |
| // Name implements NetworkInterface. |
| func (n *nic) Name() string { |
| return n.name |
| } |
| |
| // nudConfigs gets the NUD configurations for n. |
| func (n *nic) nudConfigs(protocol tcpip.NetworkProtocolNumber) (NUDConfigurations, tcpip.Error) { |
| if linkRes, ok := n.linkAddrResolvers[protocol]; ok { |
| return linkRes.neigh.config(), nil |
| } |
| |
| return NUDConfigurations{}, &tcpip.ErrNotSupported{} |
| } |
| |
| // setNUDConfigs sets the NUD configurations for n. |
| // |
| // Note, if c contains invalid NUD configuration values, it will be fixed to |
| // use default values for the erroneous values. |
| func (n *nic) setNUDConfigs(protocol tcpip.NetworkProtocolNumber, c NUDConfigurations) tcpip.Error { |
| if linkRes, ok := n.linkAddrResolvers[protocol]; ok { |
| c.resetInvalidFields() |
| linkRes.neigh.setConfig(c) |
| return nil |
| } |
| |
| return &tcpip.ErrNotSupported{} |
| } |
| |
| func (n *nic) registerPacketEndpoint(netProto tcpip.NetworkProtocolNumber, ep PacketEndpoint) tcpip.Error { |
| n.packetEPsMu.Lock() |
| defer n.packetEPsMu.Unlock() |
| |
| eps, ok := n.packetEPs[netProto] |
| if !ok { |
| eps = new(packetEndpointList) |
| n.packetEPs[netProto] = eps |
| } |
| eps.add(ep) |
| |
| return nil |
| } |
| |
| func (n *nic) unregisterPacketEndpoint(netProto tcpip.NetworkProtocolNumber, ep PacketEndpoint) { |
| n.packetEPsMu.Lock() |
| defer n.packetEPsMu.Unlock() |
| |
| eps, ok := n.packetEPs[netProto] |
| if !ok { |
| return |
| } |
| eps.remove(ep) |
| if eps.len() == 0 { |
| delete(n.packetEPs, netProto) |
| } |
| } |
| |
| // isValidForOutgoing returns true if the endpoint can be used to send out a |
| // packet. It requires the endpoint to not be marked expired (i.e., its address |
| // has been removed) unless the NIC is in spoofing mode, or temporary. |
| func (n *nic) isValidForOutgoing(ep AssignableAddressEndpoint) bool { |
| n.mu.RLock() |
| spoofing := n.spoofing |
| n.mu.RUnlock() |
| return n.Enabled() && ep.IsAssigned(spoofing) |
| } |
| |
| // HandleNeighborProbe implements NetworkInterface. |
| func (n *nic) HandleNeighborProbe(protocol tcpip.NetworkProtocolNumber, addr tcpip.Address, linkAddr tcpip.LinkAddress) tcpip.Error { |
| if l, ok := n.linkAddrResolvers[protocol]; ok { |
| l.neigh.handleProbe(addr, linkAddr) |
| return nil |
| } |
| |
| return &tcpip.ErrNotSupported{} |
| } |
| |
| // HandleNeighborConfirmation implements NetworkInterface. |
| func (n *nic) HandleNeighborConfirmation(protocol tcpip.NetworkProtocolNumber, addr tcpip.Address, linkAddr tcpip.LinkAddress, flags ReachabilityConfirmationFlags) tcpip.Error { |
| if l, ok := n.linkAddrResolvers[protocol]; ok { |
| l.neigh.handleConfirmation(addr, linkAddr, flags) |
| return nil |
| } |
| |
| return &tcpip.ErrNotSupported{} |
| } |
| |
| // CheckLocalAddress implements NetworkInterface. |
| func (n *nic) CheckLocalAddress(protocol tcpip.NetworkProtocolNumber, addr tcpip.Address) bool { |
| if n.Spoofing() { |
| return true |
| } |
| |
| if addressEndpoint := n.getAddressOrCreateTempInner(protocol, addr, false /* createTemp */, NeverPrimaryEndpoint); addressEndpoint != nil { |
| addressEndpoint.DecRef() |
| return true |
| } |
| |
| return false |
| } |
| |
| func (n *nic) checkDuplicateAddress(protocol tcpip.NetworkProtocolNumber, addr tcpip.Address, h DADCompletionHandler) (DADCheckAddressDisposition, tcpip.Error) { |
| d, ok := n.duplicateAddressDetectors[protocol] |
| if !ok { |
| return 0, &tcpip.ErrNotSupported{} |
| } |
| |
| return d.CheckDuplicateAddress(addr, h), nil |
| } |
| |
| func (n *nic) setForwarding(protocol tcpip.NetworkProtocolNumber, enable bool) (bool, tcpip.Error) { |
| ep := n.getNetworkEndpoint(protocol) |
| if ep == nil { |
| return false, &tcpip.ErrUnknownProtocol{} |
| } |
| |
| forwardingEP, ok := ep.(ForwardingNetworkEndpoint) |
| if !ok { |
| return false, &tcpip.ErrNotSupported{} |
| } |
| |
| return forwardingEP.SetForwarding(enable), nil |
| } |
| |
| func (n *nic) forwarding(protocol tcpip.NetworkProtocolNumber) (bool, tcpip.Error) { |
| ep := n.getNetworkEndpoint(protocol) |
| if ep == nil { |
| return false, &tcpip.ErrUnknownProtocol{} |
| } |
| |
| forwardingEP, ok := ep.(ForwardingNetworkEndpoint) |
| if !ok { |
| return false, &tcpip.ErrNotSupported{} |
| } |
| |
| return forwardingEP.Forwarding(), nil |
| } |
| |
| func (n *nic) multicastForwardingEndpoint(protocol tcpip.NetworkProtocolNumber) (MulticastForwardingNetworkEndpoint, tcpip.Error) { |
| ep := n.getNetworkEndpoint(protocol) |
| if ep == nil { |
| return nil, &tcpip.ErrUnknownProtocol{} |
| } |
| |
| forwardingEP, ok := ep.(MulticastForwardingNetworkEndpoint) |
| if !ok { |
| return nil, &tcpip.ErrNotSupported{} |
| } |
| |
| return forwardingEP, nil |
| } |
| |
| func (n *nic) setMulticastForwarding(protocol tcpip.NetworkProtocolNumber, enable bool) (bool, tcpip.Error) { |
| ep, err := n.multicastForwardingEndpoint(protocol) |
| if err != nil { |
| return false, err |
| } |
| |
| return ep.SetMulticastForwarding(enable), nil |
| } |
| |
| func (n *nic) multicastForwarding(protocol tcpip.NetworkProtocolNumber) (bool, tcpip.Error) { |
| ep, err := n.multicastForwardingEndpoint(protocol) |
| if err != nil { |
| return false, err |
| } |
| |
| return ep.MulticastForwarding(), nil |
| } |