Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ indent_size = 4
[*.go]
indent_style = tab
tab_width = 4
indent_size = 4
indent_size = 4
65 changes: 65 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
name: CI

on:
push:
branches:
- main
pull_request:

permissions:
contents: read

jobs:
pre-commit:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Install Golang
uses: actions/setup-go@v6
with:
go-version-file: go.mod
- name: Run pre-commit
uses: pre-commit/action@v3.0.1

test:
runs-on: ubuntu-latest
container:
image: ghcr.io/aibor/virtrun-test:${{ matrix.arch }}
strategy:
matrix:
arch:
- amd64
- arm64
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Install Golang
uses: actions/setup-go@v6
with:
go-version-file: go.mod
- name: Download kernel modules
working-directory: /kernel
# Downloading not only the modules but also the kernel again to make
# sure they stem from the exact same version.
run: |
apk fetch --arch ${{ matrix.arch }} --no-cache --allow-untrusted linux-virt
tar xf linux-virt-*.apk --wildcards --transform='s,.*/,,' \
'boot/vmlinuz-virt' \
'lib/modules/*/kernel/drivers/net/tap.ko.gz' \
'lib/modules/*/kernel/drivers/vhost/vhost_iotlb.ko.gz' \
'lib/modules/*/kernel/drivers/vhost/vhost.ko.gz' \
'lib/modules/*/kernel/drivers/vhost/vhost_net.ko.gz'
rm linux-virt-*.apk
- name: Run tests
env:
GOARCH: ${{ matrix.arch }}
VIRTRUN_ARGS: >
-kernel /kernel/vmlinuz-virt
-addModule /kernel/tap.ko.gz
-addModule /kernel/vhost_iotlb.ko.gz
-addModule /kernel/vhost.ko.gz
-addModule /kernel/vhost_net.ko.gz
-transport pci
-verbose
run: go test -v -exec "go tool virtrun" ./...
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,4 @@ go.work.sum
!.vscode/*.code-snippets

# Ignore all IntelliJ/GoLand project files for now
.idea/
.idea/
118 changes: 118 additions & 0 deletions .golangci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
version: "2"

run:
timeout: 5m

linters:
default: all
disable:
- cyclop
- depguard
- dupword
- exhaustruct
- forcetypeassert
- funcorder
- funlen
- gochecknoglobals
- gocognit
- goconst
- gocyclo
- godox
- gomoddirectives
- gosec
- iface
- inamedparam
- interfacebloat
- ireturn
- maintidx
- mnd
- musttag
- nestif
- nilnil
- nlreturn
- noinlineerr
- nonamedreturns
- paralleltest
- recvcheck
- tagliatelle
- testifylint
- varnamelen
- wsl
- wsl_v5
settings:
exhaustive:
default-signifies-exhaustive: true
godot:
exclude:
- "^.*:"
gomodguard:
blocked:
modules:
- github.com/tj/assert:
recommendations:
- github.com/stretchr/testify
reason: testify provides more assertions and one is enough
- gotest.tools/v3/assert:
recommendations:
- github.com/stretchr/testify
reason: testify provides more assertions and one is enough
govet:
disable:
# This linter produces false positives for memory not managed by Go.
- unsafeptr
lll:
line-length: 120
tab-width: 4
misspell:
locale: US
perfsprint:
strconcat: false
revive:
rules:
- name: atomic
disabled: false
- name: defer
disabled: false
- name: exported
disabled: false
- name: if-return
disabled: false
- name: struct-tag
disabled: false
arguments:
- "json,inline"
- "bson,outline,gnu"
staticcheck:
checks:
- all
- -ST1000
- -ST1003
- -ST1016
- -ST1020
- -ST1021
- -ST1022
wrapcheck:
ignore-sigs:
- .Errorf(
- errors.New(
- errors.Unwrap(
- errors.Join(
- .Wrap(
- .Wrapf(
- .WithMessage(
- .WithMessagef(
- .WithStack(
ignore-sig-regexps:
- \.New.*Error\(

formatters:
enable:
- gci
- gofmt
- gofumpt
- goimports
- golines
settings:
golines:
max-len: 120
tab-len: 4
39 changes: 39 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
hooks:
- id: check-added-large-files
- id: check-case-conflict
- id: check-executables-have-shebangs
- id: check-shebang-scripts-are-executable
- id: check-symlinks
- id: destroyed-symlinks

- id: check-json
- id: check-yaml
- id: check-toml

- id: check-merge-conflict
- id: end-of-file-fixer
- id: mixed-line-ending
args: [--fix=lf]
- id: trailing-whitespace

- repo: local
hooks:
- id: go-mod-tidy
name: go mod tidy
language: golang
entry: go mod tidy
pass_filenames: false

- id: go-generate
name: go generate
language: golang
entry: go generate ./...
pass_filenames: false

- repo: https://github.com/golangci/golangci-lint
rev: v2.5.0
hooks:
- id: golangci-lint-full
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
SOFTWARE.
3 changes: 3 additions & 0 deletions internal/testsupport/packet.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,14 @@ import (
// PrependPacket encodes the given [virtio.NetHdr], puts it in front of the
// given packet slice and returns the new slice.
func PrependPacket(tb testing.TB, vnethdr virtio.NetHdr, pkt []byte) []byte {
tb.Helper()

result := make([]byte, virtio.NetHdrSize+len(pkt))
if err := vnethdr.Encode(result); err != nil {
tb.Fatalf("Encode vnethdr: %v", err)
}
copy(result[virtio.NetHdrSize:], pkt)

return result
}

Expand Down
2 changes: 1 addition & 1 deletion tuntap/device.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func NewDevice(options ...Option) (_ *Device, err error) {

// Get a file descriptor. The device will exist as long as we keep this
// file descriptor open.
fd, err := unix.Open("/dev/net/tun", os.O_RDWR, 0666)
fd, err := unix.Open("/dev/net/tun", os.O_RDWR, 0o666)
if err != nil {
return nil, fmt.Errorf("access tuntap driver: %w", err)
}
Expand Down
1 change: 1 addition & 0 deletions tuntap/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ func (o *optionValues) apply(options []Option) {
}
}

//nolint:err113 // Allow errors.New for validation functions.
func (o *optionValues) validate() error {
if len(o.name) >= unix.IFNAMSIZ {
return errors.New("name must not be longer that 15 characters")
Expand Down
10 changes: 7 additions & 3 deletions vhostnet/device.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ func NewDevice(options ...Option) (_ *Device, err error) {

// Retrieve a new control file descriptor. This will be used to configure
// the vhost networking device in the kernel.
dev.controlFD, err = unix.Open("/dev/vhost-net", os.O_RDWR, 0666)
dev.controlFD, err = unix.Open("/dev/vhost-net", os.O_RDWR, 0o666)
if err != nil {
return nil, fmt.Errorf("get control file descriptor: %w", err)
}
Expand Down Expand Up @@ -172,6 +172,8 @@ func (dev *Device) monitorTransmitQueue() {
// transmit the packet. This method will not return before the packet was
// transmitted and the device notifies that it has used the packet buffer.
func (dev *Device) TransmitPacket(vnethdr virtio.NetHdr, packet []byte) error {
dev.ensureInitialized()

// Prepend the packet with its virtio-net header.
vnethdrBuf := make([]byte, virtio.NetHdrSize)
if err := vnethdr.Encode(vnethdrBuf); err != nil {
Expand Down Expand Up @@ -203,6 +205,8 @@ func (dev *Device) TransmitPacket(vnethdr virtio.NetHdr, packet []byte) error {
// broken state which this implementation cannot recover from. The caller should
// close the device and not attempt any additional receives.
func (dev *Device) ReceivePacket() (virtio.NetHdr, []byte, error) {
dev.ensureInitialized()

var (
chainHeads []uint16

Expand Down Expand Up @@ -400,13 +404,13 @@ func truncateBuffers(buffers [][]byte, length int) (out [][]byte) {
for _, buffer := range buffers {
if length < len(buffer) {
out = append(out, buffer[:length])
return
return out
}
out = append(out, buffer)
length -= len(buffer)
}
if length > 0 {
panic("length exceeds the combined length of all buffers")
}
return
return out
}
1 change: 1 addition & 0 deletions vhostnet/device_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ type TestFixture struct {
}

func NewTestFixture(t *testing.T) *TestFixture {
t.Helper()
testsupport.VirtrunOnly(t)

// In case something doesn't work, some more debug logging from the kernel
Expand Down
2 changes: 2 additions & 0 deletions vhostnet/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@ func (o *optionValues) apply(options []Option) {
}
}

//nolint:err113 // Allow errors.New for validation functions.
func (o *optionValues) validate() error {
if o.queueSize == -1 {
return errors.New("queue size is required")
}
if err := virtqueue.CheckQueueSize(o.queueSize); err != nil {
//nolint:wrapcheck // Error is already descriptive enough.
return err
}
if o.backendFD == -1 {
Expand Down
11 changes: 6 additions & 5 deletions virtio/net_hdr_test.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
package virtio
package virtio_test

import (
"testing"
"unsafe"

"github.com/hetznercloud/virtio-go/virtio"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/sys/unix"
)

func TestNetHdr_Size(t *testing.T) {
assert.EqualValues(t, NetHdrSize, unsafe.Sizeof(NetHdr{}))
assert.EqualValues(t, virtio.NetHdrSize, unsafe.Sizeof(virtio.NetHdr{}))
}

func TestNetHdr_Encoding(t *testing.T) {
vnethdr := NetHdr{
vnethdr := virtio.NetHdr{
Flags: unix.VIRTIO_NET_HDR_F_NEEDS_CSUM,
GSOType: unix.VIRTIO_NET_HDR_GSO_UDP_L4,
HdrLen: 42,
Expand All @@ -24,7 +25,7 @@ func TestNetHdr_Encoding(t *testing.T) {
NumBuffers: 16,
}

buf := make([]byte, NetHdrSize)
buf := make([]byte, virtio.NetHdrSize)
require.NoError(t, vnethdr.Encode(buf))

assert.Equal(t, []byte{
Expand All @@ -36,7 +37,7 @@ func TestNetHdr_Encoding(t *testing.T) {
0x10, 0x00,
}, buf)

var decoded NetHdr
var decoded virtio.NetHdr
require.NoError(t, decoded.Decode(buf))

assert.Equal(t, vnethdr, decoded)
Expand Down
2 changes: 1 addition & 1 deletion virtqueue/available_ring.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const (
// availableRingFlagNoInterrupt is used by the guest to advise the host to
// not interrupt it when consuming a buffer. It's unreliable, so it's simply
// an optimization.
availableRingFlagNoInterrupt availableRingFlag = 1 << iota
availableRingFlagNoInterrupt availableRingFlag = 1 << iota //nolint:unused
)

// availableRingSize is the number of bytes needed to store an [AvailableRing]
Expand Down
Loading
Loading