1
2
3 package netlink
4
5 import (
6 "encoding/binary"
7 "errors"
8
9 "github.com/vishvananda/netlink/nl"
10 "golang.org/x/sys/unix"
11 )
12
13 const (
14 FOU_GENL_NAME = "fou"
15 )
16
17 const (
18 FOU_CMD_UNSPEC uint8 = iota
19 FOU_CMD_ADD
20 FOU_CMD_DEL
21 FOU_CMD_GET
22 FOU_CMD_MAX = FOU_CMD_GET
23 )
24
25 const (
26 FOU_ATTR_UNSPEC = iota
27 FOU_ATTR_PORT
28 FOU_ATTR_AF
29 FOU_ATTR_IPPROTO
30 FOU_ATTR_TYPE
31 FOU_ATTR_REMCSUM_NOPARTIAL
32 FOU_ATTR_MAX = FOU_ATTR_REMCSUM_NOPARTIAL
33 )
34
35 const (
36 FOU_ENCAP_UNSPEC = iota
37 FOU_ENCAP_DIRECT
38 FOU_ENCAP_GUE
39 FOU_ENCAP_MAX = FOU_ENCAP_GUE
40 )
41
42 var fouFamilyId int
43
44 func FouFamilyId() (int, error) {
45 if fouFamilyId != 0 {
46 return fouFamilyId, nil
47 }
48
49 fam, err := GenlFamilyGet(FOU_GENL_NAME)
50 if err != nil {
51 return -1, err
52 }
53
54 fouFamilyId = int(fam.ID)
55 return fouFamilyId, nil
56 }
57
58 func FouAdd(f Fou) error {
59 return pkgHandle.FouAdd(f)
60 }
61
62 func (h *Handle) FouAdd(f Fou) error {
63 fam_id, err := FouFamilyId()
64 if err != nil {
65 return err
66 }
67
68
69 if f.EncapType == FOU_ENCAP_GUE && f.Protocol != 0 {
70 return errors.New("GUE encapsulation doesn't specify an IP protocol")
71 }
72
73 req := h.newNetlinkRequest(fam_id, unix.NLM_F_ACK)
74
75
76 bp := make([]byte, 2)
77 binary.BigEndian.PutUint16(bp[0:2], uint16(f.Port))
78
79 attrs := []*nl.RtAttr{
80 nl.NewRtAttr(FOU_ATTR_PORT, bp),
81 nl.NewRtAttr(FOU_ATTR_TYPE, []byte{uint8(f.EncapType)}),
82 nl.NewRtAttr(FOU_ATTR_AF, []byte{uint8(f.Family)}),
83 nl.NewRtAttr(FOU_ATTR_IPPROTO, []byte{uint8(f.Protocol)}),
84 }
85 raw := []byte{FOU_CMD_ADD, 1, 0, 0}
86 for _, a := range attrs {
87 raw = append(raw, a.Serialize()...)
88 }
89
90 req.AddRawData(raw)
91
92 _, err = req.Execute(unix.NETLINK_GENERIC, 0)
93 return err
94 }
95
96 func FouDel(f Fou) error {
97 return pkgHandle.FouDel(f)
98 }
99
100 func (h *Handle) FouDel(f Fou) error {
101 fam_id, err := FouFamilyId()
102 if err != nil {
103 return err
104 }
105
106 req := h.newNetlinkRequest(fam_id, unix.NLM_F_ACK)
107
108
109 bp := make([]byte, 2)
110 binary.BigEndian.PutUint16(bp[0:2], uint16(f.Port))
111
112 attrs := []*nl.RtAttr{
113 nl.NewRtAttr(FOU_ATTR_PORT, bp),
114 nl.NewRtAttr(FOU_ATTR_AF, []byte{uint8(f.Family)}),
115 }
116 raw := []byte{FOU_CMD_DEL, 1, 0, 0}
117 for _, a := range attrs {
118 raw = append(raw, a.Serialize()...)
119 }
120
121 req.AddRawData(raw)
122
123 _, err = req.Execute(unix.NETLINK_GENERIC, 0)
124 if err != nil {
125 return err
126 }
127
128 return nil
129 }
130
131 func FouList(fam int) ([]Fou, error) {
132 return pkgHandle.FouList(fam)
133 }
134
135 func (h *Handle) FouList(fam int) ([]Fou, error) {
136 fam_id, err := FouFamilyId()
137 if err != nil {
138 return nil, err
139 }
140
141 req := h.newNetlinkRequest(fam_id, unix.NLM_F_DUMP)
142
143 attrs := []*nl.RtAttr{
144 nl.NewRtAttr(FOU_ATTR_AF, []byte{uint8(fam)}),
145 }
146 raw := []byte{FOU_CMD_GET, 1, 0, 0}
147 for _, a := range attrs {
148 raw = append(raw, a.Serialize()...)
149 }
150
151 req.AddRawData(raw)
152
153 msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
154 if err != nil {
155 return nil, err
156 }
157
158 fous := make([]Fou, 0, len(msgs))
159 for _, m := range msgs {
160 f, err := deserializeFouMsg(m)
161 if err != nil {
162 return fous, err
163 }
164
165 fous = append(fous, f)
166 }
167
168 return fous, nil
169 }
170
171 func deserializeFouMsg(msg []byte) (Fou, error) {
172
173 msg = msg[3:]
174 var shift int
175 fou := Fou{}
176
177 for {
178
179 if len(msg) < 4 {
180 return fou, ErrAttrHeaderTruncated
181 }
182
183 lgt := int(binary.BigEndian.Uint16(msg[0:2]))
184 if len(msg) < lgt+4 {
185 return fou, ErrAttrBodyTruncated
186 }
187 attr := binary.BigEndian.Uint16(msg[2:4])
188
189 shift = lgt + 3
190 switch attr {
191 case FOU_ATTR_AF:
192 fou.Family = int(msg[5])
193 case FOU_ATTR_PORT:
194 fou.Port = int(binary.BigEndian.Uint16(msg[5:7]))
195
196 shift = lgt + 2
197 case FOU_ATTR_IPPROTO:
198 fou.Protocol = int(msg[5])
199 case FOU_ATTR_TYPE:
200 fou.EncapType = int(msg[5])
201 }
202
203 msg = msg[shift:]
204
205 if len(msg) < 4 {
206 break
207 }
208 }
209
210 return fou, nil
211 }
212
View as plain text