...
1 package netlink
2
3 import (
4 "errors"
5 "fmt"
6 "syscall"
7
8 "github.com/vishvananda/netlink/nl"
9 "golang.org/x/sys/unix"
10 )
11
12 const (
13 sizeofXDPSocketRequest = 1 + 1 + 2 + 4 + 4 + 2*4
14 sizeofXDPSocket = 0x10
15 )
16
17
18 type xdpSocketRequest struct {
19 Family uint8
20 Protocol uint8
21 pad uint16
22 Ino uint32
23 Show uint32
24 Cookie [2]uint32
25 }
26
27 func (r *xdpSocketRequest) Serialize() []byte {
28 b := writeBuffer{Bytes: make([]byte, sizeofSocketRequest)}
29 b.Write(r.Family)
30 b.Write(r.Protocol)
31 native.PutUint16(b.Next(2), r.pad)
32 native.PutUint32(b.Next(4), r.Ino)
33 native.PutUint32(b.Next(4), r.Show)
34 native.PutUint32(b.Next(4), r.Cookie[0])
35 native.PutUint32(b.Next(4), r.Cookie[1])
36 return b.Bytes
37 }
38
39 func (r *xdpSocketRequest) Len() int { return sizeofXDPSocketRequest }
40
41 func (s *XDPSocket) deserialize(b []byte) error {
42 if len(b) < sizeofXDPSocket {
43 return fmt.Errorf("XDP socket data short read (%d); want %d", len(b), sizeofXDPSocket)
44 }
45 rb := readBuffer{Bytes: b}
46 s.Family = rb.Read()
47 s.Type = rb.Read()
48 s.pad = native.Uint16(rb.Next(2))
49 s.Ino = native.Uint32(rb.Next(4))
50 s.Cookie[0] = native.Uint32(rb.Next(4))
51 s.Cookie[1] = native.Uint32(rb.Next(4))
52 return nil
53 }
54
55
56
57 func SocketXDPGetInfo(ino uint32, cookie uint64) (*XDPDiagInfoResp, error) {
58
59
60
61 xsks, err := SocketDiagXDP()
62 if err != nil {
63 return nil, err
64 }
65 checkCookie := cookie != SOCK_ANY_COOKIE && cookie != 0
66 crumblingCookie := [2]uint32{uint32(cookie), uint32(cookie >> 32)}
67 checkIno := ino != 0
68 var xskinfo *XDPDiagInfoResp
69 for _, xsk := range xsks {
70 if checkIno && xsk.XDPDiagMsg.Ino != ino {
71 continue
72 }
73 if checkCookie && xsk.XDPDiagMsg.Cookie != crumblingCookie {
74 continue
75 }
76 if xskinfo != nil {
77 return nil, errors.New("multiple matching XDP sockets")
78 }
79 xskinfo = xsk
80 }
81 if xskinfo == nil {
82 return nil, errors.New("no matching XDP socket")
83 }
84 return xskinfo, nil
85 }
86
87
88 func SocketDiagXDP() ([]*XDPDiagInfoResp, error) {
89 var result []*XDPDiagInfoResp
90 err := socketDiagXDPExecutor(func(m syscall.NetlinkMessage) error {
91 sockInfo := &XDPSocket{}
92 if err := sockInfo.deserialize(m.Data); err != nil {
93 return err
94 }
95 attrs, err := nl.ParseRouteAttr(m.Data[sizeofXDPSocket:])
96 if err != nil {
97 return err
98 }
99
100 res, err := attrsToXDPDiagInfoResp(attrs, sockInfo)
101 if err != nil {
102 return err
103 }
104
105 result = append(result, res)
106 return nil
107 })
108 if err != nil {
109 return nil, err
110 }
111 return result, nil
112 }
113
114
115 func socketDiagXDPExecutor(receiver func(syscall.NetlinkMessage) error) error {
116 s, err := nl.Subscribe(unix.NETLINK_INET_DIAG)
117 if err != nil {
118 return err
119 }
120 defer s.Close()
121
122 req := nl.NewNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP)
123 req.AddData(&xdpSocketRequest{
124 Family: unix.AF_XDP,
125 Show: XDP_SHOW_INFO | XDP_SHOW_RING_CFG | XDP_SHOW_UMEM | XDP_SHOW_STATS,
126 })
127 if err := s.Send(req); err != nil {
128 return err
129 }
130
131 loop:
132 for {
133 msgs, from, err := s.Receive()
134 if err != nil {
135 return err
136 }
137 if from.Pid != nl.PidKernel {
138 return fmt.Errorf("Wrong sender portid %d, expected %d", from.Pid, nl.PidKernel)
139 }
140 if len(msgs) == 0 {
141 return errors.New("no message nor error from netlink")
142 }
143
144 for _, m := range msgs {
145 switch m.Header.Type {
146 case unix.NLMSG_DONE:
147 break loop
148 case unix.NLMSG_ERROR:
149 error := int32(native.Uint32(m.Data[0:4]))
150 return syscall.Errno(-error)
151 }
152 if err := receiver(m); err != nil {
153 return err
154 }
155 }
156 }
157 return nil
158 }
159
160 func attrsToXDPDiagInfoResp(attrs []syscall.NetlinkRouteAttr, sockInfo *XDPSocket) (*XDPDiagInfoResp, error) {
161 resp := &XDPDiagInfoResp{
162 XDPDiagMsg: sockInfo,
163 XDPInfo: &XDPInfo{},
164 }
165 for _, a := range attrs {
166 switch a.Attr.Type {
167 case XDP_DIAG_INFO:
168 resp.XDPInfo.Ifindex = native.Uint32(a.Value[0:4])
169 resp.XDPInfo.QueueID = native.Uint32(a.Value[4:8])
170 case XDP_DIAG_UID:
171 resp.XDPInfo.UID = native.Uint32(a.Value[0:4])
172 case XDP_DIAG_RX_RING:
173 resp.XDPInfo.RxRingEntries = native.Uint32(a.Value[0:4])
174 case XDP_DIAG_TX_RING:
175 resp.XDPInfo.TxRingEntries = native.Uint32(a.Value[0:4])
176 case XDP_DIAG_UMEM_FILL_RING:
177 resp.XDPInfo.UmemFillRingEntries = native.Uint32(a.Value[0:4])
178 case XDP_DIAG_UMEM_COMPLETION_RING:
179 resp.XDPInfo.UmemCompletionRingEntries = native.Uint32(a.Value[0:4])
180 case XDP_DIAG_UMEM:
181 umem := &XDPDiagUmem{}
182 if err := umem.deserialize(a.Value); err != nil {
183 return nil, err
184 }
185 resp.XDPInfo.Umem = umem
186 case XDP_DIAG_STATS:
187 stats := &XDPDiagStats{}
188 if err := stats.deserialize(a.Value); err != nil {
189 return nil, err
190 }
191 resp.XDPInfo.Stats = stats
192 }
193 }
194 return resp, nil
195 }
196
View as plain text