blob: 5c8613c70a8019bf9e3917a9217f69b5060ebd00 [file] [log] [blame]
Filip Tehlar229f5fc2022-08-09 14:44:47 +00001package main
2
3import (
4 "errors"
5 "fmt"
6 "os/exec"
Maros Ondrejickaffa3f602023-01-26 10:07:29 +01007 "strings"
8
9 "go.fd.io/govpp/binapi/ethernet_types"
10 "go.fd.io/govpp/binapi/interface_types"
11 "go.fd.io/govpp/binapi/ip_types"
Filip Tehlar229f5fc2022-08-09 14:44:47 +000012)
13
Maros Ondrejickaffa3f602023-01-26 10:07:29 +010014type (
Maros Ondrejicka40cba402023-02-23 13:19:15 +010015 Cmd = exec.Cmd
Maros Ondrejicka7550dd22023-02-07 20:40:27 +010016 MacAddress = ethernet_types.MacAddress
17 AddressWithPrefix = ip_types.AddressWithPrefix
18 IP4AddressWithPrefix = ip_types.IP4AddressWithPrefix
19 InterfaceIndex = interface_types.InterfaceIndex
Maros Ondrejicka2908f8c2023-02-02 08:58:04 +010020
21 NetConfig interface {
22 Configure() error
23 Unconfigure()
24 Name() string
25 Type() string
26 }
Maros Ondrejickaffa3f602023-01-26 10:07:29 +010027
28 NetConfigBase struct {
29 name string
30 category string // what else to call this when `type` is reserved?
31 }
32
Maros Ondrejicka40cba402023-02-23 13:19:15 +010033 NetInterface struct {
Maros Ondrejickaffa3f602023-01-26 10:07:29 +010034 NetConfigBase
Maros Ondrejicka300f70d2023-02-21 10:53:20 +010035 addresser *Addresser
36 ip4Address string // this will have form 10.10.10.1/24
37 index InterfaceIndex
38 hwAddress MacAddress
39 networkNamespace string
40 networkNumber int
Maros Ondrejicka40cba402023-02-23 13:19:15 +010041 peer *NetInterface
Maros Ondrejickaffa3f602023-01-26 10:07:29 +010042 }
43
44 NetworkNamespace struct {
45 NetConfigBase
46 }
47
48 NetworkBridge struct {
49 NetConfigBase
50 networkNamespace string
51 interfaces []string
52 }
53)
Filip Tehlar229f5fc2022-08-09 14:44:47 +000054
55const (
Maros Ondrejickaffa3f602023-01-26 10:07:29 +010056 NetNs string = "netns"
57 Veth string = "veth"
58 Tap string = "tap"
59 Bridge string = "bridge"
Filip Tehlar229f5fc2022-08-09 14:44:47 +000060)
61
Maros Ondrejicka40cba402023-02-23 13:19:15 +010062type InterfaceAdder func(n *NetInterface) *Cmd
63
64var (
65 ipCommandMap = map[string]InterfaceAdder{
66 Veth: func(n *NetInterface) *Cmd {
67 return exec.Command("ip", "link", "add", n.name, "type", "veth", "peer", "name", n.peer.name)
68 },
69 Tap: func(n *NetInterface) *Cmd {
70 return exec.Command("ip", "tuntap", "add", n.name, "mode", "tap")
71 },
72 }
73)
74
75func NewNetworkInterface(cfg NetDevConfig, a *Addresser) (*NetInterface, error) {
76 var newInterface *NetInterface = &NetInterface{}
77 var err error
78 newInterface.addresser = a
79 newInterface.name = cfg["name"].(string)
80 newInterface.networkNumber = defaultNetworkNumber
81
82 if interfaceType, ok := cfg["type"]; ok {
83 newInterface.category = interfaceType.(string)
84 }
85
86 if presetHwAddress, ok := cfg["preset-hw-address"]; ok {
87 newInterface.hwAddress, err = ethernet_types.ParseMacAddress(presetHwAddress.(string))
88 if err != nil {
89 return &NetInterface{}, err
90 }
91 }
92
93 if netns, ok := cfg["netns"]; ok {
94 newInterface.networkNamespace = netns.(string)
95 }
96
97 if ip, ok := cfg["ip4"]; ok {
98 if n, ok := ip.(NetDevConfig)["network"]; ok {
99 newInterface.networkNumber = n.(int)
100 }
101 newInterface.ip4Address, err = newInterface.addresser.NewIp4Address(
102 newInterface.networkNumber,
103 )
104 if err != nil {
105 return &NetInterface{}, err
106 }
107 }
108
109 if _, ok := cfg["peer"]; !ok {
110 return newInterface, nil
111 }
112
113 peer := cfg["peer"].(NetDevConfig)
114
115 if newInterface.peer, err = NewNetworkInterface(peer, a); err != nil {
116 return &NetInterface{}, err
117 }
118
119 return newInterface, nil
120}
121
122func (n *NetInterface) ConfigureUpState() error {
123 err := SetDevUp(n.Name(), "")
124 if err != nil {
125 return fmt.Errorf("set link up failed: %v", err)
126 }
127 return nil
128}
129
130func (n *NetInterface) ConfigureNetworkNamespace() error {
131 if n.networkNamespace != "" {
132 err := LinkSetNetns(n.name, n.networkNamespace)
133 if err != nil {
134 return err
135 }
136 }
137 return nil
138}
139
140func (n *NetInterface) ConfigureAddress() error {
141 if n.ip4Address != "" {
142 if err := AddAddress(
143 n.Name(),
144 n.ip4Address,
145 n.networkNamespace,
146 ); err != nil {
147 return err
148 }
149
150 }
151 return nil
152}
153
154func (n *NetInterface) Configure() error {
155 cmd := ipCommandMap[n.Type()](n)
156 _, err := cmd.CombinedOutput()
157 if err != nil {
158 return fmt.Errorf("creating interface '%v' failed: %v", n.Name(), err)
159 }
160
161 if err := n.ConfigureUpState(); err != nil {
162 return err
163 }
164
165 if err := n.ConfigureNetworkNamespace(); err != nil {
166 return err
167 }
168
169 if err := n.ConfigureAddress(); err != nil {
170 return err
171 }
172
173 if n.peer != nil && n.peer.name != "" {
174 if err := n.Peer().ConfigureUpState(); err != nil {
175 return err
176 }
177
178 if err := n.Peer().ConfigureNetworkNamespace(); err != nil {
179 return err
180 }
181
182 if err := n.Peer().ConfigureAddress(); err != nil {
183 return err
184 }
185 }
186
187 return nil
188}
189
190func (n *NetInterface) Unconfigure() {
191 DelLink(n.name)
192}
193
194func (n *NetInterface) Name() string {
195 return n.name
196}
197
198func (n *NetInterface) Type() string {
199 return n.category
200}
201
202func (n *NetInterface) SetAddress(address string) {
203 n.ip4Address = address
204}
205
206func (n *NetInterface) SetIndex(index InterfaceIndex) {
207 n.index = index
208}
209
210func (n *NetInterface) Index() InterfaceIndex {
211 return n.index
212}
213
214func (n *NetInterface) AddressWithPrefix() AddressWithPrefix {
215 address, _ := ip_types.ParseAddressWithPrefix(n.ip4Address)
216 return address
217}
218
219func (n *NetInterface) IP4AddressWithPrefix() IP4AddressWithPrefix {
220 ip4Prefix, _ := ip_types.ParseIP4Prefix(n.ip4Address)
221 ip4AddressWithPrefix := ip_types.IP4AddressWithPrefix(ip4Prefix)
222 return ip4AddressWithPrefix
223}
224
225func (n *NetInterface) IP4AddressString() string {
226 return strings.Split(n.ip4Address, "/")[0]
227}
228
229func (n *NetInterface) HwAddress() MacAddress {
230 return n.hwAddress
231}
232
233func (n *NetInterface) Peer() *NetInterface {
234 return n.peer
235}
236
Maros Ondrejicka2908f8c2023-02-02 08:58:04 +0100237func (b *NetConfigBase) Name() string {
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100238 return b.name
Filip Tehlar229f5fc2022-08-09 14:44:47 +0000239}
240
Maros Ondrejicka2908f8c2023-02-02 08:58:04 +0100241func (b *NetConfigBase) Type() string {
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100242 return b.category
243}
244
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100245func NewNetNamespace(cfg NetDevConfig) (NetworkNamespace, error) {
246 var networkNamespace NetworkNamespace
247 networkNamespace.name = cfg["name"].(string)
Maros Ondrejicka40cba402023-02-23 13:19:15 +0100248 networkNamespace.category = NetNs
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100249 return networkNamespace, nil
250}
251
252func (ns *NetworkNamespace) Configure() error {
253 return addDelNetns(ns.name, true)
254}
255
256func (ns *NetworkNamespace) Unconfigure() {
257 addDelNetns(ns.name, false)
258}
259
260func NewBridge(cfg NetDevConfig) (NetworkBridge, error) {
261 var bridge NetworkBridge
262 bridge.name = cfg["name"].(string)
Maros Ondrejicka40cba402023-02-23 13:19:15 +0100263 bridge.category = Bridge
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100264 for _, v := range cfg["interfaces"].([]interface{}) {
265 bridge.interfaces = append(bridge.interfaces, v.(string))
266 }
Maros Ondrejicka300f70d2023-02-21 10:53:20 +0100267
268 bridge.networkNamespace = ""
269 if netns, ok := cfg["netns"]; ok {
270 bridge.networkNamespace = netns.(string)
271 }
Maros Ondrejicka7550dd22023-02-07 20:40:27 +0100272 return bridge, nil
273}
274
275func (b *NetworkBridge) Configure() error {
276 return AddBridge(b.name, b.interfaces, b.networkNamespace)
277}
278
279func (b *NetworkBridge) Unconfigure() {
280 DelBridge(b.name, b.networkNamespace)
281}
282
Filip Tehlar229f5fc2022-08-09 14:44:47 +0000283func DelBridge(brName, ns string) error {
284 err := SetDevDown(brName, ns)
Maros Ondrejickab5c73172023-03-01 09:43:24 +0100285 if err != nil {
Filip Tehlar229f5fc2022-08-09 14:44:47 +0000286 return err
287 }
288
289 err = addDelBridge(brName, ns, false)
290 if err != nil {
291 return err
292 }
293
294 return nil
295}
296
Filip Tehlar229f5fc2022-08-09 14:44:47 +0000297func SetDevUp(dev, ns string) error {
298 return setDevUpDown(dev, ns, true)
299}
300
301func SetDevDown(dev, ns string) error {
302 return setDevUpDown(dev, ns, false)
303}
304
Filip Tehlar229f5fc2022-08-09 14:44:47 +0000305func DelLink(ifName string) {
306 cmd := exec.Command("ip", "link", "del", ifName)
307 cmd.Run()
308}
309
310func setDevUpDown(dev, ns string, isUp bool) error {
311 var op string
312 if isUp {
313 op = "up"
314 } else {
315 op = "down"
316 }
317 c := []string{"ip", "link", "set", "dev", dev, op}
318 cmd := appendNetns(c, ns)
319 err := cmd.Run()
320 if err != nil {
321 s := fmt.Sprintf("error bringing %s device %s!", dev, op)
322 return errors.New(s)
323 }
324 return nil
325}
326
Filip Tehlar229f5fc2022-08-09 14:44:47 +0000327func addDelNetns(name string, isAdd bool) error {
328 var op string
329 if isAdd {
330 op = "add"
331 } else {
332 op = "del"
333 }
334 cmd := exec.Command("ip", "netns", op, name)
335 _, err := cmd.CombinedOutput()
336 if err != nil {
337 return errors.New("add/del netns failed")
338 }
339 return nil
340}
341
342func AddNetns(nsName string) error {
343 return addDelNetns(nsName, true)
344}
345
346func DelNetns(nsName string) error {
347 return addDelNetns(nsName, false)
348}
349
350func LinkSetNetns(ifName, ns string) error {
351 cmd := exec.Command("ip", "link", "set", "dev", ifName, "up", "netns", ns)
352 err := cmd.Run()
353 if err != nil {
354 return fmt.Errorf("error setting device '%s' to netns '%s: %v", ifName, ns, err)
355 }
356 return nil
357}
358
359func NewCommand(s []string, ns string) *exec.Cmd {
360 return appendNetns(s, ns)
361}
362
363func appendNetns(s []string, ns string) *exec.Cmd {
364 var cmd *exec.Cmd
365 if ns == "" {
366 // use default namespace
367 cmd = exec.Command(s[0], s[1:]...)
368 } else {
369 var args = []string{"netns", "exec", ns}
370 args = append(args, s[:]...)
371 cmd = exec.Command("ip", args...)
372 }
373 return cmd
374}
375
376func addDelBridge(brName, ns string, isAdd bool) error {
377 var op string
378 if isAdd {
379 op = "addbr"
380 } else {
381 op = "delbr"
382 }
383 var c = []string{"brctl", op, brName}
384 cmd := appendNetns(c, ns)
385 err := cmd.Run()
386 if err != nil {
387 s := fmt.Sprintf("%s %s failed!", op, brName)
388 return errors.New(s)
389 }
390 return nil
391}
392
393func AddBridge(brName string, ifs []string, ns string) error {
394 err := addDelBridge(brName, ns, true)
395 if err != nil {
396 return err
397 }
398
399 for _, v := range ifs {
400 c := []string{"brctl", "addif", brName, v}
401 cmd := appendNetns(c, ns)
402 err = cmd.Run()
403 if err != nil {
404 s := fmt.Sprintf("error adding %s to bridge %s: %v", v, brName, err)
405 return errors.New(s)
406 }
407 }
408 err = SetDevUp(brName, ns)
409 if err != nil {
410 return err
411 }
412 return nil
413}