Add support for virtio net headers in sharedmem endpoint.

PiperOrigin-RevId: 416221825
This commit is contained in:
Bhasker Hariharan
2021-12-13 23:39:05 -08:00
committed by gVisor bot
parent 9b56ce185a
commit c06c9deb1c
11 changed files with 177 additions and 13 deletions
+4 -1
View File
@@ -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",
+1
View File
@@ -26,6 +26,7 @@ go_library(
"ndpoptionidentifier_string.go",
"tcp.go",
"udp.go",
"virtionet.go",
],
visibility = ["//visibility:public"],
deps = [
+94
View File
@@ -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)
}
+3 -1
View File
@@ -14,7 +14,9 @@ go_library(
"sharedmem_unsafe.go",
"tx.go",
],
visibility = ["//visibility:public"],
visibility = [
"//visibility:public",
],
deps = [
"//pkg/cleanup",
"//pkg/eventfd",
+35 -5
View File
@@ -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 != "" {
+1
View File
@@ -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()
+6 -5
View File
@@ -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}
+10 -1
View File
@@ -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{
+1
View File
@@ -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",
+2
View File
@@ -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{}
}