forked from milosgajdos/tenus
/
macvlan_linux.go
189 lines (159 loc) · 5.22 KB
/
macvlan_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
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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
package tenus
import (
"fmt"
"net"
"github.com/docker/libcontainer/netlink"
)
// Default MacVlan mode
const (
default_mode = "bridge"
)
// Supported macvlan modes by tenus package
var MacVlanModes = map[string]bool{
"private": true,
"vepa": true,
"bridge": true,
}
// MacVlanOptions allows you to specify some options for macvlan link.
type MacVlanOptions struct {
// macvlan device name
Dev string
// macvlan mode
Mode string
// MAC address
MacAddr string
}
// MacVlaner embeds Linker interface and adds few more functions.
type MacVlaner interface {
// Linker interface
Linker
// MasterNetInterface returns macvlan master network device
MasterNetInterface() *net.Interface
// Mode returns macvlan link's network mode
Mode() string
}
// MacVlanLink is Link which has a master network device and operates in
// a given network mode. It implements MacVlaner interface.
type MacVlanLink struct {
Link
// Master device logical network interface
masterIfc *net.Interface
// macvlan operatio nmode
mode string
}
// NewMacVlanLink creates macvlan network link
//
// It is equivalent of running:
// ip link add name mc${RANDOM STRING} link ${master interface} type macvlan
// NewMacVlanLink returns MacVlaner which is initialized to a pointer of type MacVlanLink if the
// macvlan link was created successfully on the Linux host. Newly created link is assigned
// a random name starting with "mc". It sets the macvlan mode to "bridge" mode which is a default.
// It returns error if the link could not be created.
func NewMacVlanLink(masterDev string) (MacVlaner, error) {
macVlanDev := makeNetInterfaceName("mc")
if ok, err := NetInterfaceNameValid(masterDev); !ok {
return nil, err
}
if _, err := net.InterfaceByName(masterDev); err != nil {
return nil, fmt.Errorf("Master MAC VLAN device %s does not exist on the host", masterDev)
}
if err := netlink.NetworkLinkAddMacVlan(masterDev, macVlanDev, default_mode); err != nil {
return nil, err
}
macVlanIfc, err := net.InterfaceByName(macVlanDev)
if err != nil {
return nil, fmt.Errorf("Could not find the new interface: %s", err)
}
masterIfc, err := net.InterfaceByName(masterDev)
if err != nil {
return nil, fmt.Errorf("Could not find the new interface: %s", err)
}
return &MacVlanLink{
Link: Link{
ifc: macVlanIfc,
},
masterIfc: masterIfc,
mode: default_mode,
}, nil
}
// NewMacVlanLinkWithOptions creates macvlan network link and sets som of its network parameters
// passed in as MacVlanOptions.
//
// It is equivalent of running:
// ip link add name ${macvlan name} link ${master interface} address ${macaddress} type macvlan mode ${mode}
// NewMacVlanLinkWithOptions returns MacVlaner which is initialized to a pointer of type MacVlanLink if the
// macvlan link was created successfully on the Linux host. If particular option is empty, it sets default value if possible.
// It returns error if the macvlan link could not be created or if incorrect options have been passed.
func NewMacVlanLinkWithOptions(masterDev string, opts MacVlanOptions) (MacVlaner, error) {
if ok, err := NetInterfaceNameValid(masterDev); !ok {
return nil, err
}
if _, err := net.InterfaceByName(masterDev); err != nil {
return nil, fmt.Errorf("Master MAC VLAN device %s does not exist on the host", masterDev)
}
if err := validateMacVlanOptions(&opts); err != nil {
return nil, err
}
if err := netlink.NetworkLinkAddMacVlan(masterDev, opts.Dev, opts.Mode); err != nil {
return nil, err
}
macVlanIfc, err := net.InterfaceByName(opts.Dev)
if err != nil {
return nil, fmt.Errorf("Could not find the new interface: %s", err)
}
if opts.MacAddr != "" {
if err := netlink.NetworkSetMacAddress(macVlanIfc, opts.MacAddr); err != nil {
if errDel := DeleteLink(macVlanIfc.Name); errDel != nil {
return nil, fmt.Errorf("Incorrect options specified. Attempt to delete the link failed: %s", errDel)
}
}
}
masterIfc, err := net.InterfaceByName(masterDev)
if err != nil {
return nil, fmt.Errorf("Could not find the new interface: %s", err)
}
return &MacVlanLink{
Link: Link{
ifc: macVlanIfc,
},
masterIfc: masterIfc,
mode: opts.Mode,
}, nil
}
// NetInterface returns macvlan link's network interface
func (macvln *MacVlanLink) NetInterface() *net.Interface {
return macvln.ifc
}
// MasterNetInterface returns macvlan link's master network interface
func (macvln *MacVlanLink) MasterNetInterface() *net.Interface {
return macvln.masterIfc
}
// Mode returns macvlan link's network operation mode
func (macvln *MacVlanLink) Mode() string {
return macvln.mode
}
func validateMacVlanOptions(opts *MacVlanOptions) error {
if opts.Dev != "" {
if ok, err := NetInterfaceNameValid(opts.Dev); !ok {
return err
}
if _, err := net.InterfaceByName(opts.Dev); err == nil {
return fmt.Errorf("MAC VLAN device %s already assigned on the host", opts.Dev)
}
} else {
opts.Dev = makeNetInterfaceName("mc")
}
if opts.Mode != "" {
if _, ok := MacVlanModes[opts.Mode]; !ok {
return fmt.Errorf("Unsupported MacVlan mode specified: %s", opts.Mode)
}
} else {
opts.Mode = default_mode
}
if opts.MacAddr != "" {
if _, err := net.ParseMAC(opts.MacAddr); err == nil {
return fmt.Errorf("Incorrect MAC ADDRESS specified: %s", opts.MacAddr)
}
}
return nil
}