File: filter.go

package info (click to toggle)
incus 6.0.5-8
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 26,092 kB
  • sloc: sh: 16,313; ansic: 3,121; python: 457; makefile: 337; ruby: 51; sql: 50; lisp: 6
file content (127 lines) | stat: -rw-r--r-- 2,271 bytes parent folder | download | duplicates (4)
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
package ip

import (
	"fmt"

	"github.com/vishvananda/netlink"
	"golang.org/x/sys/unix"
)

// Action represents an action in filter.
type Action interface {
	toNetlink() (netlink.Action, error)
}

// ActionPolice represents an action of 'police' type.
type ActionPolice struct {
	Rate  uint32 // in byte/s
	Burst uint32 // in byte
	Mtu   uint32 // in byte
	Drop  bool
}

func (a *ActionPolice) toNetlink() (netlink.Action, error) {
	action := netlink.NewPoliceAction()

	action.Rate = a.Rate
	action.Burst = a.Burst
	action.Mtu = a.Mtu

	if a.Drop {
		action.ExceedAction = netlink.TC_POLICE_SHOT
	} else {
		action.ExceedAction = netlink.TC_POLICE_RECLASSIFY
	}

	return action, nil
}

// Filter represents filter object.
type Filter struct {
	Dev      string
	Parent   string
	Protocol string
	Flowid   string
}

// U32Filter represents universal 32bit traffic control filter.
type U32Filter struct {
	Filter
	Value   uint32
	Mask    uint32
	Actions []Action
}

func parseProtocol(proto string) (uint16, error) {
	switch proto {
	case "all":
		return unix.ETH_P_ALL, nil
	default:
		return 0, fmt.Errorf("Unknown protocol %q", proto)
	}
}

// Add adds universal 32bit traffic control filter to a node.
func (u32 *U32Filter) Add() error {
	link, err := linkByName(u32.Dev)
	if err != nil {
		return err
	}

	proto, err := parseProtocol(u32.Protocol)
	if err != nil {
		return err
	}

	filter := &netlink.U32{
		FilterAttrs: netlink.FilterAttrs{
			LinkIndex: link.Attrs().Index,
			Protocol:  proto,
			Chain:     nil,
		},
		Sel: &netlink.TcU32Sel{
			Flags: netlink.TC_U32_TERMINAL,
			Nkeys: 1,
			Keys: []netlink.TcU32Key{
				{
					Mask: u32.Mask,
					Val:  u32.Value,
				},
			},
		},
	}

	for _, action := range u32.Actions {
		netlinkAction, err := action.toNetlink()
		if err != nil {
			return err
		}

		filter.Actions = append(filter.Actions, netlinkAction)
	}

	if u32.Parent != "" {
		parent, err := parseHandle(u32.Parent)
		if err != nil {
			return err
		}

		filter.Parent = parent
	}

	if u32.Flowid != "" {
		flowid, err := parseHandle(u32.Flowid)
		if err != nil {
			return err
		}

		filter.ClassId = flowid
	}

	err = netlink.FilterAdd(filter)
	if err != nil {
		return fmt.Errorf("Failed to add filter %v: %w", filter, err)
	}

	return nil
}