-
Notifications
You must be signed in to change notification settings - Fork 243
/
ovs.go
145 lines (115 loc) · 3.79 KB
/
ovs.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
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// Copyright 2020 Nokia
// Licensed under the BSD 3-Clause License.
// SPDX-License-Identifier: BSD-3-Clause
package ovs
import (
"context"
"fmt"
"github.com/containernetworking/plugins/pkg/ns"
goOvs "github.com/digitalocean/go-openvswitch/ovs"
log "github.com/sirupsen/logrus"
cExec "github.com/srl-labs/containerlab/clab/exec"
"github.com/srl-labs/containerlab/internal/slices"
"github.com/srl-labs/containerlab/links"
"github.com/srl-labs/containerlab/nodes"
"github.com/srl-labs/containerlab/nodes/state"
"github.com/srl-labs/containerlab/runtime"
"github.com/srl-labs/containerlab/types"
"github.com/vishvananda/netlink"
)
var kindnames = []string{"ovs-bridge"}
// Register registers the node in the NodeRegistry.
func Register(r *nodes.NodeRegistry) {
r.Register(kindnames, func() nodes.Node {
return new(ovs)
}, nil)
}
type ovs struct {
nodes.DefaultNode
}
func (n *ovs) Init(cfg *types.NodeConfig, opts ...nodes.NodeOption) error {
// Init DefaultNode
n.DefaultNode = *nodes.NewDefaultNode(n)
n.Cfg = cfg
for _, o := range opts {
o(n)
}
n.Cfg.IsRootNamespaceBased = true
return nil
}
func (n *ovs) CheckDeploymentConditions(_ context.Context) error {
// check if ovs bridge exists
c := goOvs.New(
// Prepend "sudo" to all commands.
goOvs.Sudo(),
)
// We were previously doing c.VSwitch.Get.Bridge() but it doesn't work
// when the bridge has a protocol version higher than 1.0
// So listing the bridges is safer
bridges, err := c.VSwitch.ListBridges()
if err != nil {
return fmt.Errorf("error while listing ovs bridges: %v", err)
}
if !slices.Contains(bridges, n.Cfg.ShortName) {
return fmt.Errorf("could not find ovs bridge %q", n.Cfg.ShortName)
}
return nil
}
func (n *ovs) Deploy(_ context.Context, _ *nodes.DeployParams) error {
n.SetState(state.Deployed)
return nil
}
func (*ovs) PullImage(_ context.Context) error { return nil }
func (*ovs) GetImages(_ context.Context) map[string]string { return map[string]string{} }
func (n *ovs) Delete(_ context.Context) error {
c := goOvs.New(
// Prepend "sudo" to all commands.
goOvs.Sudo(),
)
for _, ep := range n.GetEndpoints() {
// Under the hood, this is called with "--if-exists", so it will handle the case where it doesn't exist for some reason.
if err := c.VSwitch.DeletePort(n.Cfg.ShortName, ep.GetIfaceName()); err != nil {
log.Errorf("Could not remove OVS port %q from bridge %q", ep.GetIfaceName(), n.Config().ShortName)
}
}
return nil
}
func (*ovs) DeleteNetnsSymlink() (err error) { return nil }
// UpdateConfigWithRuntimeInfo is a noop for bridges.
func (*ovs) UpdateConfigWithRuntimeInfo(_ context.Context) error { return nil }
// GetContainers is a noop for bridges.
func (*ovs) GetContainers(_ context.Context) ([]runtime.GenericContainer, error) { return nil, nil }
// RunExec is noop for ovs kind.
func (n *ovs) RunExec(_ context.Context, _ *cExec.ExecCmd) (*cExec.ExecResult, error) {
log.Warnf("Exec operation is not implemented for kind %q", n.Config().Kind)
return nil, cExec.ErrRunExecNotSupported
}
func (n *ovs) AddLinkToContainer(ctx context.Context, link netlink.Link, f func(ns.NetNS) error) error {
// retrieve the namespace handle
ns, err := ns.GetCurrentNS()
if err != nil {
return err
}
// execute the given function
err = ns.Do(f)
if err != nil {
return err
}
c := goOvs.New(
// Prepend "sudo" to all commands.
goOvs.Sudo(),
)
// need to reread the link, due to the changed the function f might have applied to
// the link. Usually it renames the link to its final name.
link, err = netlink.LinkByIndex(link.Attrs().Index)
if err != nil {
return err
}
if err := c.VSwitch.AddPort(n.Cfg.ShortName, link.Attrs().Name); err != nil {
return err
}
return nil
}
func (m *ovs) GetLinkEndpointType() links.LinkEndpointType {
return links.LinkEndpointTypeBridge
}