mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Add support for virtio net headers in sharedmem endpoint.
PiperOrigin-RevId: 416221825
This commit is contained in:
committed by
gVisor bot
parent
9b56ce185a
commit
c06c9deb1c
+4
-1
@@ -8,7 +8,10 @@ go_library(
|
||||
"eventfd.go",
|
||||
"eventfd_unsafe.go",
|
||||
],
|
||||
visibility = ["//:sandbox"],
|
||||
visibility = [
|
||||
"//:sandbox",
|
||||
"//cloud/cluster/node/network/client/go:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
"//pkg/hostarch",
|
||||
"//pkg/tcpip/link/rawfile",
|
||||
|
||||
@@ -26,6 +26,7 @@ go_library(
|
||||
"ndpoptionidentifier_string.go",
|
||||
"tcp.go",
|
||||
"udp.go",
|
||||
"virtionet.go",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
// Copyright 2021 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 header
|
||||
|
||||
import "encoding/binary"
|
||||
|
||||
// These constants are declared in linux/virtio_net.h.
|
||||
const (
|
||||
_VIRTIO_NET_HDR_F_NEEDS_CSUM = 1
|
||||
_VIRTIO_NET_HDR_GSO_NONE = 0
|
||||
_VIRTIO_NET_HDR_GSO_TCPV4 = 1
|
||||
_VIRTIO_NET_HDR_GSO_TCPV6 = 4
|
||||
)
|
||||
|
||||
const (
|
||||
// VirtioNetHeaderSize is the size of VirtioNetHeader in bytes.
|
||||
VirtioNetHeaderSize = 10
|
||||
)
|
||||
|
||||
// Offsets for fields in the virtio net header.
|
||||
const (
|
||||
flags = 0
|
||||
gsoType = 1
|
||||
hdrLen = 2
|
||||
gsoSize = 4
|
||||
csumStart = 6
|
||||
csumOffset = 8
|
||||
)
|
||||
|
||||
// VirtioNetHeaderFields is the Go equivalent of the struct declared in
|
||||
// linux/virtio_net.h.
|
||||
type VirtioNetHeaderFields struct {
|
||||
Flags uint8
|
||||
GSOType uint8
|
||||
HdrLen uint16
|
||||
GSOSize uint16
|
||||
CSumStart uint16
|
||||
CSumOffset uint16
|
||||
}
|
||||
|
||||
// VirtioNetHeader represents a virtio net header stored in a byte array.
|
||||
type VirtioNetHeader []byte
|
||||
|
||||
// Flags returns the "flags" field of the virtio net header.
|
||||
func (v VirtioNetHeader) Flags() uint8 {
|
||||
return uint8(v[flags])
|
||||
}
|
||||
|
||||
// GSOType returns the "gsoType" field of the virtio net header.
|
||||
func (v VirtioNetHeader) GSOType() uint8 {
|
||||
return uint8(v[gsoType])
|
||||
}
|
||||
|
||||
// HdrLen returns the "hdrLen" field of the virtio net header.
|
||||
func (v VirtioNetHeader) HdrLen() uint16 {
|
||||
return binary.BigEndian.Uint16(v[hdrLen:])
|
||||
}
|
||||
|
||||
// GSOSize returns the "gsoSize" field of the virtio net header.
|
||||
func (v VirtioNetHeader) GSOSize() uint16 {
|
||||
return binary.BigEndian.Uint16(v[gsoSize:])
|
||||
}
|
||||
|
||||
// CSumStart returns the "csumStart" field of the virtio net header.
|
||||
func (v VirtioNetHeader) CSumStart() uint16 {
|
||||
return binary.BigEndian.Uint16(v[csumStart:])
|
||||
}
|
||||
|
||||
// CSumOffset returns the "csumOffset" field of the virtio net header.
|
||||
func (v VirtioNetHeader) CSumOffset() uint16 {
|
||||
return binary.BigEndian.Uint16(v[csumOffset:])
|
||||
}
|
||||
|
||||
// Encode encodes all the fields of the virtio net header.
|
||||
func (v VirtioNetHeader) Encode(f *VirtioNetHeaderFields) {
|
||||
v[flags] = uint8(f.Flags)
|
||||
v[gsoType] = uint8(f.GSOType)
|
||||
binary.BigEndian.PutUint16(v[hdrLen:], f.HdrLen)
|
||||
binary.BigEndian.PutUint16(v[gsoSize:], f.GSOSize)
|
||||
binary.BigEndian.PutUint16(v[csumStart:], f.CSumStart)
|
||||
binary.BigEndian.PutUint16(v[csumOffset:], f.CSumOffset)
|
||||
}
|
||||
@@ -14,7 +14,9 @@ go_library(
|
||||
"sharedmem_unsafe.go",
|
||||
"tx.go",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
],
|
||||
deps = [
|
||||
"//pkg/cleanup",
|
||||
"//pkg/eventfd",
|
||||
|
||||
@@ -129,6 +129,10 @@ type Options struct {
|
||||
// RXChecksumOffload if true, indicates that this endpoints capability
|
||||
// set should include CapabilityRXChecksumOffload.
|
||||
RXChecksumOffload bool
|
||||
|
||||
// VirtioNetHeaderRequired if true, indicates that all outbound packets should have
|
||||
// a virtio header and inbound packets should have a virtio header as well.
|
||||
VirtioNetHeaderRequired bool
|
||||
}
|
||||
|
||||
type endpoint struct {
|
||||
@@ -156,6 +160,10 @@ type endpoint struct {
|
||||
// hdrSize is immutable.
|
||||
hdrSize uint32
|
||||
|
||||
// virtioNetHeaderRequired if true indicates that a virtio header is expected
|
||||
// in all inbound/outbound packets.
|
||||
virtioNetHeaderRequired bool
|
||||
|
||||
// rx is the receive queue.
|
||||
rx rx
|
||||
|
||||
@@ -186,11 +194,12 @@ type endpoint struct {
|
||||
// into buffers of "bufferSize" bytes.
|
||||
func New(opts Options) (stack.LinkEndpoint, error) {
|
||||
e := &endpoint{
|
||||
mtu: opts.MTU,
|
||||
bufferSize: opts.BufferSize,
|
||||
addr: opts.LinkAddress,
|
||||
peerFD: opts.PeerFD,
|
||||
onClosed: opts.OnClosed,
|
||||
mtu: opts.MTU,
|
||||
bufferSize: opts.BufferSize,
|
||||
addr: opts.LinkAddress,
|
||||
peerFD: opts.PeerFD,
|
||||
onClosed: opts.OnClosed,
|
||||
virtioNetHeaderRequired: opts.VirtioNetHeaderRequired,
|
||||
}
|
||||
|
||||
if err := e.tx.init(opts.BufferSize, &opts.TX); err != nil {
|
||||
@@ -215,6 +224,11 @@ func New(opts Options) (stack.LinkEndpoint, error) {
|
||||
e.hdrSize = header.EthernetMinimumSize
|
||||
e.caps |= stack.CapabilityResolutionRequired
|
||||
}
|
||||
|
||||
if opts.VirtioNetHeaderRequired {
|
||||
e.hdrSize += header.VirtioNetHeaderSize
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}
|
||||
|
||||
@@ -322,6 +336,11 @@ func (e *endpoint) AddHeader(local, remote tcpip.LinkAddress, protocol tcpip.Net
|
||||
eth.Encode(ethHdr)
|
||||
}
|
||||
|
||||
func (e *endpoint) AddVirtioNetHeader(pkt *stack.PacketBuffer) {
|
||||
virtio := header.VirtioNetHeader(pkt.VirtioNetHeader().Push(header.VirtioNetHeaderSize))
|
||||
virtio.Encode(&header.VirtioNetHeaderFields{})
|
||||
}
|
||||
|
||||
// WriteRawPacket implements stack.LinkEndpoint.
|
||||
func (*endpoint) WriteRawPacket(*stack.PacketBuffer) tcpip.Error { return &tcpip.ErrNotSupported{} }
|
||||
|
||||
@@ -330,6 +349,9 @@ func (e *endpoint) writePacketLocked(r stack.RouteInfo, protocol tcpip.NetworkPr
|
||||
if e.addr != "" {
|
||||
e.AddHeader(r.LocalLinkAddress, r.RemoteLinkAddress, protocol, pkt)
|
||||
}
|
||||
if e.virtioNetHeaderRequired {
|
||||
e.AddVirtioNetHeader(pkt)
|
||||
}
|
||||
|
||||
views := pkt.Views()
|
||||
// Transmit the packet.
|
||||
@@ -414,6 +436,14 @@ func (e *endpoint) dispatchLoop(d stack.NetworkDispatcher) {
|
||||
Data: buffer.View(b).ToVectorisedView(),
|
||||
})
|
||||
|
||||
if e.virtioNetHeaderRequired {
|
||||
_, ok := pkt.VirtioNetHeader().Consume(header.VirtioNetHeaderSize)
|
||||
if !ok {
|
||||
pkt.DecRef()
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
var src, dst tcpip.LinkAddress
|
||||
var proto tcpip.NetworkProtocolNumber
|
||||
if e.addr != "" {
|
||||
|
||||
@@ -63,6 +63,10 @@ type serverEndpoint struct {
|
||||
// hdrSize is immutable.
|
||||
hdrSize uint32
|
||||
|
||||
// virtioNetHeaderRequired if true indicates that a virtio header is expected
|
||||
// in all inbound/outbound packets.
|
||||
virtioNetHeaderRequired bool
|
||||
|
||||
// onClosed is a function to be called when the FD's peer (if any) closes its
|
||||
// end of the communication pipe.
|
||||
onClosed func(tcpip.Error)
|
||||
@@ -218,6 +222,11 @@ func (e *serverEndpoint) AddHeader(local, remote tcpip.LinkAddress, protocol tcp
|
||||
eth.Encode(ethHdr)
|
||||
}
|
||||
|
||||
func (e *serverEndpoint) AddVirtioNetHeader(pkt *stack.PacketBuffer) {
|
||||
virtio := header.VirtioNetHeader(pkt.VirtioNetHeader().Push(header.VirtioNetHeaderSize))
|
||||
virtio.Encode(&header.VirtioNetHeaderFields{})
|
||||
}
|
||||
|
||||
// WriteRawPacket implements stack.LinkEndpoint.WriteRawPacket
|
||||
func (e *serverEndpoint) WriteRawPacket(pkt *stack.PacketBuffer) tcpip.Error {
|
||||
views := pkt.Views()
|
||||
@@ -237,6 +246,10 @@ func (e *serverEndpoint) writePacketLocked(r stack.RouteInfo, protocol tcpip.Net
|
||||
e.AddHeader(r.LocalLinkAddress, r.RemoteLinkAddress, protocol, pkt)
|
||||
}
|
||||
|
||||
if e.virtioNetHeaderRequired {
|
||||
e.AddVirtioNetHeader(pkt)
|
||||
}
|
||||
|
||||
views := pkt.Views()
|
||||
ok := e.tx.transmit(views)
|
||||
if !ok {
|
||||
@@ -306,6 +319,13 @@ func (e *serverEndpoint) dispatchLoop(d stack.NetworkDispatcher) {
|
||||
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
Data: buffer.View(b).ToVectorisedView(),
|
||||
})
|
||||
if e.virtioNetHeaderRequired {
|
||||
_, ok := pkt.VirtioNetHeader().Consume(header.VirtioNetHeaderSize)
|
||||
if !ok {
|
||||
pkt.DecRef()
|
||||
continue
|
||||
}
|
||||
}
|
||||
var src, dst tcpip.LinkAddress
|
||||
var proto tcpip.NetworkProtocolNumber
|
||||
if e.addr != "" {
|
||||
|
||||
@@ -207,6 +207,7 @@ func logPacket(prefix string, dir direction, protocol tcpip.NetworkProtocolNumbe
|
||||
// We trim the link headers from the cloned buffer as the sniffer doesn't
|
||||
// handle link headers.
|
||||
vv := buffer.NewVectorisedView(pkt.Size(), pkt.Views())
|
||||
vv.TrimFront(len(pkt.VirtioNetHeader().View()))
|
||||
vv.TrimFront(len(pkt.LinkHeader().View()))
|
||||
pkt = stack.NewPacketBuffer(stack.PacketBufferOptions{Data: vv})
|
||||
defer pkt.DecRef()
|
||||
|
||||
@@ -21,13 +21,14 @@ func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[linkHeader-0]
|
||||
_ = x[networkHeader-1]
|
||||
_ = x[transportHeader-2]
|
||||
_ = x[numHeaderType-3]
|
||||
_ = x[virtioNetHeader-0]
|
||||
_ = x[linkHeader-1]
|
||||
_ = x[networkHeader-2]
|
||||
_ = x[transportHeader-3]
|
||||
_ = x[numHeaderType-4]
|
||||
}
|
||||
|
||||
const _headerType_name = "linkHeadernetworkHeadertransportHeadernumHeaderType"
|
||||
const _headerType_name = "virtioNetHeaderlinkHeadernetworkHeadertransportHeadernumHeaderType"
|
||||
|
||||
var _headerType_index = [...]uint8{0, 10, 23, 38, 51}
|
||||
|
||||
|
||||
@@ -27,7 +27,8 @@ import (
|
||||
type headerType int
|
||||
|
||||
const (
|
||||
linkHeader headerType = iota
|
||||
virtioNetHeader headerType = iota
|
||||
linkHeader
|
||||
networkHeader
|
||||
transportHeader
|
||||
numHeaderType
|
||||
@@ -216,6 +217,14 @@ func (pk *PacketBuffer) AvailableHeaderBytes() int {
|
||||
return pk.reserved - pk.pushed
|
||||
}
|
||||
|
||||
// VirtioNetHeader returns the handle to virtio-layer header.
|
||||
func (pk *PacketBuffer) VirtioNetHeader() PacketHeader {
|
||||
return PacketHeader{
|
||||
pk: pk,
|
||||
typ: virtioNetHeader,
|
||||
}
|
||||
}
|
||||
|
||||
// LinkHeader returns the handle to link-layer header.
|
||||
func (pk *PacketBuffer) LinkHeader() PacketHeader {
|
||||
return PacketHeader{
|
||||
|
||||
@@ -26,6 +26,7 @@ go_library(
|
||||
imports = ["gvisor.dev/gvisor/pkg/tcpip/buffer"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//pkg/log",
|
||||
"//pkg/sleep",
|
||||
"//pkg/sync",
|
||||
"//pkg/tcpip",
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/log"
|
||||
"gvisor.dev/gvisor/pkg/sync"
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/buffer"
|
||||
@@ -348,6 +349,7 @@ func (e *endpoint) GetSockOpt(opt tcpip.GettableSocketOption) tcpip.Error {
|
||||
|
||||
func send4(s *stack.Stack, ctx *network.WriteContext, ident uint16, data buffer.View, maxHeaderLength uint16) tcpip.Error {
|
||||
if len(data) < header.ICMPv4MinimumSize {
|
||||
log.Infof("len(data) is smaller than min size")
|
||||
return &tcpip.ErrInvalidEndpointState{}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user