forked from dropbox/goebpf
-
Notifications
You must be signed in to change notification settings - Fork 0
/
program_xdp.go
149 lines (126 loc) · 3.74 KB
/
program_xdp.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// Copyright (c) 2019 Dropbox, Inc.
// Full license can be found in the LICENSE file.
package goebpf
//#include "bpf_helpers.h"
import "C"
import (
"errors"
"fmt"
"github.com/vishvananda/netlink"
)
// XdpResult is eBPF program return code enum
type XdpResult int
// XDP program return codes
const (
XdpAborted XdpResult = C.XDP_ABORTED
XdpDrop XdpResult = C.XDP_DROP
XdpPass XdpResult = C.XDP_PASS
XdpTx XdpResult = C.XDP_TX
XdpRedirect XdpResult = C.XDP_REDIRECT
)
// XdpAttachMode selects a way how XDP program will be attached to interface
type XdpAttachMode int
const (
// XdpAttachModeNone stands for "best effort" - kernel automatically
// selects best mode (would try Drv first, then fallback to Generic).
// NOTE: Kernel will not fallback to Generic XDP if NIC driver failed
// to install XDP program.
XdpAttachModeNone XdpAttachMode = 0
// XdpAttachModeSkb is "generic", kernel mode, less performant comparing to native,
// but does not requires driver support.
XdpAttachModeSkb XdpAttachMode = (1 << 1)
// XdpAttachModeDrv is native, driver mode (support from driver side required)
XdpAttachModeDrv XdpAttachMode = (1 << 2)
// XdpAttachModeHw suitable for NICs with hardware XDP support
XdpAttachModeHw XdpAttachMode = (1 << 3)
)
// XdpAttachParams used to pass parameters to Attach() call.
type XdpAttachParams struct {
// Interface is string name of interface to attach program to
Interface string
// Mode is one of XdpAttachMode.
Mode XdpAttachMode
}
func (t XdpResult) String() string {
switch t {
case XdpAborted:
return "XDP_ABORTED"
case XdpDrop:
return "XDP_DROP"
case XdpPass:
return "XDP_PASS"
case XdpTx:
return "XDP_TX"
case XdpRedirect:
return "XDP_REDIRECT"
}
return "UNKNOWN"
}
// XDP eBPF program (implements Program interface)
type xdpProgram struct {
BaseProgram
// Interface name and attach mode
ifname string
mode XdpAttachMode
}
func newXdpProgram(bp BaseProgram) Program {
bp.programType = ProgramTypeXdp
return &xdpProgram{
BaseProgram: bp,
}
}
// Attach attaches eBPF(XDP) program to network interface.
// There are 2 possible ways to do that:
//
// 1. Pass interface name as parameter, e.g.
// xdpProgram.Attach("eth0")
//
// 2. Using XdpAttachParams structure:
// xdpProgram.Attach(
// &XdpAttachParams{Mode: XdpAttachModeSkb, Interface: "eth0"
// })
func (p *xdpProgram) Attach(data interface{}) error {
var ifaceName string
var attachMode = XdpAttachModeNone // AutoSelect
switch x := data.(type) {
case string:
ifaceName = x
case *XdpAttachParams:
ifaceName = x.Interface
attachMode = x.Mode
default:
return fmt.Errorf("%T is not supported for Attach()", data)
}
// Lookup interface by given name, we need to extract iface index
link, err := netlink.LinkByName(ifaceName)
if err != nil {
// Most likely no such interface
return fmt.Errorf("LinkByName() failed: %v", err)
}
// Attach program
if err := netlink.LinkSetXdpFdWithFlags(link, p.fd, int(attachMode)); err != nil {
return fmt.Errorf("LinkSetXdpFd() failed: %v", err)
}
p.ifname = ifaceName
p.mode = attachMode
return nil
}
// Detach detaches program from network interface
// Must be previously attached by Attach() call.
func (p *xdpProgram) Detach() error {
if p.ifname == "" {
return errors.New("Program isn't attached")
}
// Lookup interface by given name, we need to extract iface index
link, err := netlink.LinkByName(p.ifname)
if err != nil {
// Most likely no such interface
return fmt.Errorf("LinkByName() failed: %v", err)
}
// Setting eBPF program with FD -1 actually removes it from interface
if err := netlink.LinkSetXdpFdWithFlags(link, -1, int(p.mode)); err != nil {
return fmt.Errorf("LinkSetXdpFd() failed: %v", err)
}
p.ifname = ""
return nil
}