git » go-net » commit 7c71ca7

bpf: implement LoadExtension and ExtLen for VM

author Matt Layher
2016-06-20 20:30:30 UTC
committer Mikio Hara
2016-06-20 21:42:44 UTC
parent 8bf2b39827dbadfd566c4fae7a8790d12be8b23c

bpf: implement LoadExtension and ExtLen for VM

Change-Id: I29487b0c1fdea97b5c35d22b4f7c23e11e7ceeed
Reviewed-on: https://go-review.googlesource.com/24272
Reviewed-by: David Anderson <danderson@google.com>
Reviewed-by: Mikio Hara <mikioh.mikioh@gmail.com>
Run-TryBot: Mikio Hara <mikioh.mikioh@gmail.com>

bpf/vm.go +9 -3
bpf/vm_extension_test.go +49 -0
bpf/vm_instructions.go +9 -0

diff --git a/bpf/vm.go b/bpf/vm.go
index 957c95d..4c656f1 100644
--- a/bpf/vm.go
+++ b/bpf/vm.go
@@ -45,6 +45,13 @@ func NewVM(filter []Instruction) (*VM, error) {
 			case ALUOpDiv, ALUOpMod:
 				return nil, errors.New("cannot divide by zero using ALUOpConstant")
 			}
+		// Check for unknown extensions
+		case LoadExtension:
+			switch ins.Num {
+			case ExtLen:
+			default:
+				return nil, fmt.Errorf("extension %d not implemented", ins.Num)
+			}
 		}
 	}
 
@@ -84,9 +91,6 @@ func (v *VM) Run(in []byte) (int, error) {
 	// - NegateA:
 	//   - would require a change from uint32 registers to int32
 	//     registers
-	// - Extension:
-	//   - implement extensions that do not depend on kernel-specific
-	//     functionality, such as 'rand'
 
 	// TODO(mdlayher): add interop tests that check signedness of ALU
 	// operations against kernel implementation, and make sure Go
@@ -109,6 +113,8 @@ func (v *VM) Run(in []byte) (int, error) {
 			regA, ok = loadAbsolute(ins, in)
 		case LoadConstant:
 			regA, regX = loadConstant(ins, regA, regX)
+		case LoadExtension:
+			regA = loadExtension(ins, in)
 		case LoadIndirect:
 			regA, ok = loadIndirect(ins, in, regX)
 		case LoadMemShift:
diff --git a/bpf/vm_extension_test.go b/bpf/vm_extension_test.go
new file mode 100644
index 0000000..7a48c82
--- /dev/null
+++ b/bpf/vm_extension_test.go
@@ -0,0 +1,49 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bpf_test
+
+import (
+	"testing"
+
+	"golang.org/x/net/bpf"
+)
+
+func TestVMLoadExtensionNotImplemented(t *testing.T) {
+	_, _, err := testVM(t, []bpf.Instruction{
+		bpf.LoadExtension{
+			Num: 100,
+		},
+		bpf.RetA{},
+	})
+	if errStr(err) != "extension 100 not implemented" {
+		t.Fatalf("unexpected error: %v", err)
+	}
+}
+
+func TestVMLoadExtensionExtLen(t *testing.T) {
+	vm, done, err := testVM(t, []bpf.Instruction{
+		bpf.LoadExtension{
+			Num: bpf.ExtLen,
+		},
+		bpf.RetA{},
+	})
+	if err != nil {
+		t.Fatalf("failed to load BPF program: %v", err)
+	}
+	defer done()
+
+	out, err := vm.Run([]byte{
+		0xff, 0xff, 0xff, 0xff,
+		0xff, 0xff, 0xff, 0xff,
+		0, 1, 2, 3,
+	})
+	if err != nil {
+		t.Fatalf("unexpected error while running program: %v", err)
+	}
+	if want, got := 4, out; want != got {
+		t.Fatalf("unexpected number of output bytes:\n- want: %d\n-  got: %d",
+			want, got)
+	}
+}
diff --git a/bpf/vm_instructions.go b/bpf/vm_instructions.go
index 7507923..516f946 100644
--- a/bpf/vm_instructions.go
+++ b/bpf/vm_instructions.go
@@ -103,6 +103,15 @@ func loadConstant(ins LoadConstant, regA uint32, regX uint32) (uint32, uint32) {
 	return regA, regX
 }
 
+func loadExtension(ins LoadExtension, in []byte) uint32 {
+	switch ins.Num {
+	case ExtLen:
+		return uint32(len(in))
+	default:
+		panic(fmt.Sprintf("unimplemented extension: %d", ins.Num))
+	}
+}
+
 func loadIndirect(ins LoadIndirect, in []byte, regX uint32) (uint32, bool) {
 	offset := int(ins.Off) + int(regX)
 	size := int(ins.Size)