/
family_linux.go
83 lines (69 loc) · 2.41 KB
/
family_linux.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
//go:build linux
// +build linux
package genltest
import (
"fmt"
"github.com/mdlayher/genetlink"
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
// serveFamily is the Linux implementation of ServeFamily.
func serveFamily(f genetlink.Family, fn Func) Func {
return func(greq genetlink.Message, nreq netlink.Message) ([]genetlink.Message, error) {
// Only intercept "get family" commands to the generic netlink controller.
if nreq.Header.Type != unix.GENL_ID_CTRL || greq.Header.Command != unix.CTRL_CMD_GETFAMILY {
return fn(greq, nreq)
}
ad, err := netlink.NewAttributeDecoder(greq.Data)
if err != nil {
return nil, fmt.Errorf("genltest: failed to parse get family request attributes: %v", err)
}
// Ensure this request is for the family provided by f.
for ad.Next() {
if want, got := unix.CTRL_ATTR_FAMILY_NAME, int(ad.Type()); want != got {
return nil, fmt.Errorf("genltest: unexpected get family request attribute: %d, want: %d", got, want)
}
if want, got := f.Name, ad.String(); want != got {
return nil, fmt.Errorf("genltest: unexpected get family request value: %q, want: %q", got, want)
}
}
if err := ad.Err(); err != nil {
return nil, fmt.Errorf("genltest: unexpected error decoding get family request: %v", err)
}
// Return the family information for f.
ae := netlink.NewAttributeEncoder()
ae.Uint16(unix.CTRL_ATTR_FAMILY_ID, f.ID)
ae.String(unix.CTRL_ATTR_FAMILY_NAME, f.Name)
ae.Uint32(unix.CTRL_ATTR_VERSION, uint32(f.Version))
// Encode multicast group attributes if applicable.
if len(f.Groups) > 0 {
ae.Nested(unix.CTRL_ATTR_MCAST_GROUPS, encodeGroups(f.Groups))
}
attrb, err := ae.Encode()
if err != nil {
return nil, err
}
return []genetlink.Message{{
Header: genetlink.Header{
Command: unix.CTRL_CMD_NEWFAMILY,
// TODO(mdlayher): constant nlctrl version number?
Version: 2,
},
Data: attrb,
}}, nil
}
}
// encodeGroups encodes multicast groups as packed netlink attributes.
func encodeGroups(groups []genetlink.MulticastGroup) func(ae *netlink.AttributeEncoder) error {
return func(ae *netlink.AttributeEncoder) error {
// Groups are a netlink "array" of nested attributes.
for i, g := range groups {
ae.Nested(uint16(i), func(nae *netlink.AttributeEncoder) error {
nae.String(unix.CTRL_ATTR_MCAST_GRP_NAME, g.Name)
nae.Uint32(unix.CTRL_ATTR_MCAST_GRP_ID, g.ID)
return nil
})
}
return nil
}
}