示例#1
0
// testVM sets up a Go BPF VM, and if available, a native OS BPF VM
// for integration testing.
func testVM(t *testing.T, filter []bpf.Instruction) (virtualMachine, func(), error) {
	goVM, err := bpf.NewVM(filter)
	if err != nil {
		// Some tests expect an error, so this error must be returned
		// instead of fatally exiting the test
		return nil, nil, err
	}

	mvm := &multiVirtualMachine{
		goVM: goVM,

		t: t,
	}

	// If available, add the OS VM for tests which verify that both the Go
	// VM and OS VM have exactly the same output for the same input program
	// and packet.
	done := func() {}
	if canUseOSVM() {
		osVM, osVMDone := testOSVM(t, filter)
		done = func() { osVMDone() }
		mvm.osVM = osVM
	}

	return mvm, done, nil
}
// testBPFProgram builds a BPF program for the input server and compares the
// output of the program against the input AoE header, returning whether or
// not the header was accepted by the filter.
func testBPFProgram(t *testing.T, s *Server, h *aoe.Header) bool {
	filter, ok := bpf.Disassemble(s.mustAssembleBPF(testMTU))
	if !ok {
		t.Fatal("failed to decode all BPF instructions")
	}

	vm, err := bpf.NewVM(filter)
	if !ok {
		t.Fatalf("failed to load BPF program: %v", err)
	}

	// Fill in empty AoE header fields not relevant to this test
	h.Version = aoe.Version
	h.Command = aoe.CommandQueryConfigInformation
	h.Arg = &aoe.ConfigArg{
		Command: aoe.ConfigCommandRead,
	}

	hb, err := h.MarshalBinary()
	if err != nil {
		t.Fatalf("failed to marshal AoE header to binary: %v", err)
	}

	f := &ethernet.Frame{
		EtherType: aoe.EtherType,
		Payload:   hb,
	}
	fb, err := f.MarshalBinary()
	if err != nil {
		t.Fatalf("failed to marshal Ethernet frame to binary: %v", err)
	}

	out, err := vm.Run(fb)
	if err != nil {
		t.Fatalf("failed to run BPF program: %v", err)
	}

	return out > 0
}
示例#3
0
// ExampleNewVM demonstrates usage of a VM, using an Ethernet frame
// as input and checking its EtherType to determine if it should be accepted.
func ExampleNewVM() {
	// Offset | Length | Comment
	// -------------------------
	//   00   |   06   | Ethernet destination MAC address
	//   06   |   06   | Ethernet source MAC address
	//   12   |   02   | Ethernet EtherType
	const (
		etOff = 12
		etLen = 2

		etARP = 0x0806
	)

	// Set up a VM to filter traffic based on if its EtherType
	// matches the ARP EtherType.
	vm, err := bpf.NewVM([]bpf.Instruction{
		// Load EtherType value from Ethernet header
		bpf.LoadAbsolute{
			Off:  etOff,
			Size: etLen,
		},
		// If EtherType is equal to the ARP EtherType, jump to allow
		// packet to be accepted
		bpf.JumpIf{
			Cond:     bpf.JumpEqual,
			Val:      etARP,
			SkipTrue: 1,
		},
		// EtherType does not match the ARP EtherType
		bpf.RetConstant{
			Val: 0,
		},
		// EtherType matches the ARP EtherType, accept up to 1500
		// bytes of packet
		bpf.RetConstant{
			Val: 1500,
		},
	})
	if err != nil {
		panic(fmt.Sprintf("failed to load BPF program: %v", err))
	}

	// Create an Ethernet frame with the ARP EtherType for testing
	frame := []byte{
		0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
		0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
		0x08, 0x06,
		// Payload omitted for brevity
	}

	// Run our VM's BPF program using the Ethernet frame as input
	out, err := vm.Run(frame)
	if err != nil {
		panic(fmt.Sprintf("failed to accept Ethernet frame: %v", err))
	}

	// BPF VM can return a byte count greater than the number of input
	// bytes, so trim the output to match the input byte length
	if out > len(frame) {
		out = len(frame)
	}

	fmt.Printf("out: %d bytes", out)

	// Output:
	// out: 14 bytes
}