@@ -11,6 +11,7 @@ import (
11
11
"net"
12
12
"net/http"
13
13
"os"
14
+ "strconv"
14
15
"strings"
15
16
"time"
16
17
@@ -19,15 +20,22 @@ import (
19
20
"github.com/containernetworking/cni/pkg/skel"
20
21
"github.com/containernetworking/cni/pkg/types"
21
22
"github.com/containernetworking/cni/pkg/types/020"
23
+ "github.com/containernetworking/cni/pkg/types/current"
22
24
"github.com/containernetworking/cni/pkg/version"
25
+ "github.com/containernetworking/plugins/pkg/ip"
26
+ "github.com/containernetworking/plugins/pkg/ipam"
27
+ "github.com/containernetworking/plugins/pkg/ns"
28
+
29
+ "github.com/vishvananda/netlink"
23
30
)
24
31
25
32
type cniPlugin struct {
26
33
socketPath string
34
+ hostNS ns.NetNS
27
35
}
28
36
29
- func NewCNIPlugin (socketPath string ) * cniPlugin {
30
- return & cniPlugin {socketPath : socketPath }
37
+ func NewCNIPlugin (socketPath string , hostNS ns. NetNS ) * cniPlugin {
38
+ return & cniPlugin {socketPath : socketPath , hostNS : hostNS }
31
39
}
32
40
33
41
// Create and fill a CNIRequest with this plugin's environment and stdin which
@@ -63,7 +71,11 @@ func (p *cniPlugin) doCNI(url string, req *cniserver.CNIRequest) ([]byte, error)
63
71
},
64
72
}
65
73
66
- resp , err := client .Post (url , "application/json" , bytes .NewReader (data ))
74
+ var resp * http.Response
75
+ err = p .hostNS .Do (func (ns.NetNS ) error {
76
+ resp , err = client .Post (url , "application/json" , bytes .NewReader (data ))
77
+ return err
78
+ })
67
79
if err != nil {
68
80
return nil , fmt .Errorf ("failed to send CNI request: %v" , err )
69
81
}
@@ -81,10 +93,27 @@ func (p *cniPlugin) doCNI(url string, req *cniserver.CNIRequest) ([]byte, error)
81
93
return body , nil
82
94
}
83
95
96
+ func readMTU () (int , error ) {
97
+ bytes , err := ioutil .ReadFile (cniserver .CNIMTUFilePath )
98
+ if err != nil {
99
+ if os .IsNotExist (err ) {
100
+ return - 1 , fmt .Errorf ("OpenShift SDN network process is not (yet?) available" )
101
+ } else {
102
+ return - 1 , fmt .Errorf ("could not read MTU file: %v" , err )
103
+ }
104
+ }
105
+ mtu , err := strconv .ParseUint (string (bytes ), 10 , 0 )
106
+ if err != nil {
107
+ return - 1 , fmt .Errorf ("could not parse MTU value %q" , string (bytes ))
108
+ }
109
+ return int (mtu ), nil
110
+ }
111
+
84
112
// Send the ADD command environment and config to the CNI server, returning
85
113
// the IPAM result to the caller
86
- func (p * cniPlugin ) CmdAdd (args * skel.CmdArgs ) (types.Result , error ) {
87
- body , err := p .doCNI ("http://dummy/" , newCNIRequest (args ))
114
+ func (p * cniPlugin ) doCNIServerAdd (req * cniserver.CNIRequest , hostVeth string ) (types.Result , error ) {
115
+ req .Env ["OSDN_HOSTVETH" ] = hostVeth
116
+ body , err := p .doCNI ("http://dummy/" , req )
88
117
if err != nil {
89
118
return nil , err
90
119
}
@@ -99,24 +128,111 @@ func (p *cniPlugin) CmdAdd(args *skel.CmdArgs) (types.Result, error) {
99
128
return result , nil
100
129
}
101
130
102
- // Send the ADD command environment and config to the CNI server, printing
103
- // the IPAM result to stdout when called as a CNI plugin
104
- func (p * cniPlugin ) skelCmdAdd (args * skel.CmdArgs ) error {
105
- result , err := p .CmdAdd (args )
131
+ func (p * cniPlugin ) testCmdAdd (args * skel.CmdArgs ) (types.Result , error ) {
132
+ return p .doCNIServerAdd (newCNIRequest (args ), "dummy0" )
133
+ }
134
+
135
+ func (p * cniPlugin ) CmdAdd (args * skel.CmdArgs ) error {
136
+ req := newCNIRequest (args )
137
+ ifname := req .Env ["CNI_IFNAME" ]
138
+ netns := req .Env ["CNI_NETNS" ]
139
+ if ifname == "" || netns == "" {
140
+ return fmt .Errorf ("CNI request did not include required environment variables" )
141
+ }
142
+
143
+ mtu , err := readMTU ()
144
+ if err != nil {
145
+ return err
146
+ }
147
+
148
+ var hostVeth , contVeth net.Interface
149
+ err = ns .WithNetNSPath (netns , func (hostNS ns.NetNS ) error {
150
+ hostVeth , contVeth , err = ip .SetupVeth (ifname , mtu , hostNS )
151
+ if err != nil {
152
+ return fmt .Errorf ("failed to create container veth: %v" , err )
153
+ }
154
+ return nil
155
+ })
156
+ if err != nil {
157
+ return err
158
+ }
159
+ result , err := p .doCNIServerAdd (req , hostVeth .Name )
160
+ if err != nil {
161
+ return err
162
+ }
163
+
164
+ result030 , err := current .NewResultFromResult (result )
165
+ if err != nil {
166
+ return fmt .Errorf ("failed to convert IPAM result: %v" , err )
167
+ }
168
+
169
+ if len (result030 .IPs ) != 1 || result030 .IPs [0 ].Version != "4" {
170
+ return fmt .Errorf ("unexpected IPAM result from CNIServer" )
171
+ }
172
+
173
+ // Clear out gateway to prevent ConfigureIface from adding the cluster
174
+ // subnet via the gateway
175
+ result030 .IPs [0 ].Gateway = nil
176
+ // Add a sandbox interface record which ConfigureInterface expects.
177
+ // The only interface we report is the pod interface.
178
+ result030 .Interfaces = []* current.Interface {
179
+ {
180
+ Name : ifname ,
181
+ Mac : contVeth .HardwareAddr .String (),
182
+ Sandbox : netns ,
183
+ },
184
+ }
185
+ index := 0
186
+ result030 .IPs [0 ].Interface = & index
187
+
188
+ err = ns .WithNetNSPath (netns , func (ns.NetNS ) error {
189
+ // Set up eth0
190
+ if err := ip .SetHWAddrByIP (ifname , result030 .IPs [0 ].Address .IP , nil ); err != nil {
191
+ return fmt .Errorf ("failed to set pod interface MAC address: %v" , err )
192
+ }
193
+ if err := ipam .ConfigureIface (ifname , result030 ); err != nil {
194
+ return fmt .Errorf ("failed to configure container IPAM: %v" , err )
195
+ }
196
+
197
+ // Set up lo
198
+ link , err := netlink .LinkByName ("lo" )
199
+ if err == nil {
200
+ err = netlink .LinkSetUp (link )
201
+ }
202
+ if err != nil {
203
+ return fmt .Errorf ("failed to configure container loopback: %v" , err )
204
+ }
205
+
206
+ // Set up macvlan0 (if it exists)
207
+ link , err = netlink .LinkByName ("macvlan0" )
208
+ if err == nil {
209
+ err = netlink .LinkSetUp (link )
210
+ if err != nil {
211
+ return fmt .Errorf ("failed to configure macvlan device: %v" , err )
212
+ }
213
+ }
214
+
215
+ return nil
216
+ })
106
217
if err != nil {
107
218
return err
108
219
}
220
+
109
221
return result .Print ()
110
222
}
111
223
112
- // Send the DEL command environment and config to the CNI server
113
224
func (p * cniPlugin ) CmdDel (args * skel.CmdArgs ) error {
114
225
_ , err := p .doCNI ("http://dummy/" , newCNIRequest (args ))
115
226
return err
116
227
}
117
228
118
229
func main () {
119
230
rand .Seed (time .Now ().UTC ().UnixNano ())
120
- p := NewCNIPlugin (cniserver .CNIServerSocketPath )
121
- skel .PluginMain (p .skelCmdAdd , p .CmdDel , version .Legacy )
231
+ hostNS , err := ns .GetCurrentNS ()
232
+ if err != nil {
233
+ panic (fmt .Sprintf ("could not get current kernel netns: %v" , err ))
234
+ }
235
+ defer hostNS .Close ()
236
+ p := NewCNIPlugin (cniserver .CNIServerSocketPath , hostNS )
237
+ skel .PluginMain (p .CmdAdd , p .CmdDel , version .Legacy )
122
238
}
0 commit comments