forked from sematext/oxdpus
-
Notifications
You must be signed in to change notification settings - Fork 0
/
hook.go
99 lines (89 loc) · 2.67 KB
/
hook.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
/*
* Copyright (c) Sematext Group, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*/
package xdp
import (
"bytes"
"errors"
"fmt"
libbpf "github.com/iovisor/gobpf/elf"
"github.com/sematext/oxdpus/pkg/xdp/prog/gen"
"net"
)
const (
progName = "xdp/xdp_ip_filter"
)
// Hook provides a set of operations that allow for managing the execution of the XDP program
// including attaching it on the network interface, harvesting various statistics or removing
// the program from the interface.
type Hook struct {
mod *libbpf.Module
}
// NewHook constructs a new instance of the XDP hook from provided XDP code.
func NewHook() (*Hook, error) {
mod := libbpf.NewModuleFromReader(bytes.NewReader(LoadXDPBytecode()))
if mod == nil {
return nil, errors.New("ELF module is not initialized")
}
if err := mod.Load(nil); err != nil {
return nil, err
}
return &Hook{mod: mod}, nil
}
// Attach loads the XDP program to specified interface with the default flags.
func (h *Hook) Attach(dev string) error {
return h.AttachWithFlags(dev, 0)
}
// AttachWithFlags loads the XDP program to specified interface
// with the provided flags (0 for none).
func (h *Hook) AttachWithFlags(dev string, flags uint32) error {
// before we proceed with attaching make sure that the
// provided device (interface) is present on the machine
ifaces, err := net.Interfaces()
if err != nil {
return fmt.Errorf("couldn't obtain the list of interfaces: %v", err)
}
ok := false
for _, i := range ifaces {
if i.Name == dev {
ok = true
break
}
}
if !ok {
return fmt.Errorf("%s interface is not present. Please run `ip a` to list available interfaces", dev)
}
// attempt attach the XDP program
if err := h.mod.AttachXDPWithFlags(dev, progName, flags); err != nil {
// TODO: translate flags to a user-friendly name
return fmt.Errorf("couldn't attach XDP program to %s interface with flags %d", dev, flags)
}
return nil
}
// Remove unloads the XDP program from the interface.
func (h *Hook) Remove(dev string) error {
if err := h.mod.RemoveXDPWithFlags(dev, 2); err != nil {
return fmt.Errorf("couldn't unload XDP program from %s interface", dev)
}
return nil
}
// Close closes the underlying eBPF module by disposing any allocated resources.
func (h *Hook) Close() error {
h.mod.Close()
return nil
}
// LoadXDPBytecode loads XDP byte code from
func LoadXDPBytecode() []byte {
b, err := gen.Asset("xdp.o")
if err != nil {
panic(fmt.Sprintf("failed to load XDP bytecode from embedded resource: %v", err))
}
return b
}