You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

144 lines
3.3 KiB

  1. // Copyright 2016 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package bpf_test
  5. import (
  6. "fmt"
  7. "testing"
  8. "golang.org/x/net/bpf"
  9. )
  10. var _ bpf.Instruction = unknown{}
  11. type unknown struct{}
  12. func (unknown) Assemble() (bpf.RawInstruction, error) {
  13. return bpf.RawInstruction{}, nil
  14. }
  15. func TestVMUnknownInstruction(t *testing.T) {
  16. vm, done, err := testVM(t, []bpf.Instruction{
  17. bpf.LoadConstant{
  18. Dst: bpf.RegA,
  19. Val: 100,
  20. },
  21. // Should terminate the program with an error immediately
  22. unknown{},
  23. bpf.RetA{},
  24. })
  25. if err != nil {
  26. t.Fatalf("unexpected error: %v", err)
  27. }
  28. defer done()
  29. _, err = vm.Run([]byte{
  30. 0xff, 0xff, 0xff, 0xff,
  31. 0xff, 0xff, 0xff, 0xff,
  32. 0x00, 0x00,
  33. })
  34. if errStr(err) != "unknown Instruction at index 1: bpf_test.unknown" {
  35. t.Fatalf("unexpected error while running program: %v", err)
  36. }
  37. }
  38. func TestVMNoReturnInstruction(t *testing.T) {
  39. _, _, err := testVM(t, []bpf.Instruction{
  40. bpf.LoadConstant{
  41. Dst: bpf.RegA,
  42. Val: 1,
  43. },
  44. })
  45. if errStr(err) != "BPF program must end with RetA or RetConstant" {
  46. t.Fatalf("unexpected error: %v", err)
  47. }
  48. }
  49. func TestVMNoInputInstructions(t *testing.T) {
  50. _, _, err := testVM(t, []bpf.Instruction{})
  51. if errStr(err) != "one or more Instructions must be specified" {
  52. t.Fatalf("unexpected error: %v", err)
  53. }
  54. }
  55. // ExampleNewVM demonstrates usage of a VM, using an Ethernet frame
  56. // as input and checking its EtherType to determine if it should be accepted.
  57. func ExampleNewVM() {
  58. // Offset | Length | Comment
  59. // -------------------------
  60. // 00 | 06 | Ethernet destination MAC address
  61. // 06 | 06 | Ethernet source MAC address
  62. // 12 | 02 | Ethernet EtherType
  63. const (
  64. etOff = 12
  65. etLen = 2
  66. etARP = 0x0806
  67. )
  68. // Set up a VM to filter traffic based on if its EtherType
  69. // matches the ARP EtherType.
  70. vm, err := bpf.NewVM([]bpf.Instruction{
  71. // Load EtherType value from Ethernet header
  72. bpf.LoadAbsolute{
  73. Off: etOff,
  74. Size: etLen,
  75. },
  76. // If EtherType is equal to the ARP EtherType, jump to allow
  77. // packet to be accepted
  78. bpf.JumpIf{
  79. Cond: bpf.JumpEqual,
  80. Val: etARP,
  81. SkipTrue: 1,
  82. },
  83. // EtherType does not match the ARP EtherType
  84. bpf.RetConstant{
  85. Val: 0,
  86. },
  87. // EtherType matches the ARP EtherType, accept up to 1500
  88. // bytes of packet
  89. bpf.RetConstant{
  90. Val: 1500,
  91. },
  92. })
  93. if err != nil {
  94. panic(fmt.Sprintf("failed to load BPF program: %v", err))
  95. }
  96. // Create an Ethernet frame with the ARP EtherType for testing
  97. frame := []byte{
  98. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  99. 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
  100. 0x08, 0x06,
  101. // Payload omitted for brevity
  102. }
  103. // Run our VM's BPF program using the Ethernet frame as input
  104. out, err := vm.Run(frame)
  105. if err != nil {
  106. panic(fmt.Sprintf("failed to accept Ethernet frame: %v", err))
  107. }
  108. // BPF VM can return a byte count greater than the number of input
  109. // bytes, so trim the output to match the input byte length
  110. if out > len(frame) {
  111. out = len(frame)
  112. }
  113. fmt.Printf("out: %d bytes", out)
  114. // Output:
  115. // out: 14 bytes
  116. }
  117. // errStr returns the string representation of an error, or
  118. // "<nil>" if it is nil.
  119. func errStr(err error) string {
  120. if err == nil {
  121. return "<nil>"
  122. }
  123. return err.Error()
  124. }