Tizen_4.0 base
[platform/upstream/docker-engine.git] / vendor / github.com / docker / libnetwork / osl / interface_linux.go
1 package osl
2
3 import (
4         "fmt"
5         "net"
6         "regexp"
7         "sync"
8         "syscall"
9         "time"
10
11         "github.com/Sirupsen/logrus"
12         "github.com/docker/libnetwork/ns"
13         "github.com/docker/libnetwork/types"
14         "github.com/vishvananda/netlink"
15         "github.com/vishvananda/netns"
16 )
17
18 // IfaceOption is a function option type to set interface options
19 type IfaceOption func(i *nwIface)
20
21 type nwIface struct {
22         srcName     string
23         dstName     string
24         master      string
25         dstMaster   string
26         mac         net.HardwareAddr
27         address     *net.IPNet
28         addressIPv6 *net.IPNet
29         ipAliases   []*net.IPNet
30         llAddrs     []*net.IPNet
31         routes      []*net.IPNet
32         bridge      bool
33         ns          *networkNamespace
34         sync.Mutex
35 }
36
37 func (i *nwIface) SrcName() string {
38         i.Lock()
39         defer i.Unlock()
40
41         return i.srcName
42 }
43
44 func (i *nwIface) DstName() string {
45         i.Lock()
46         defer i.Unlock()
47
48         return i.dstName
49 }
50
51 func (i *nwIface) DstMaster() string {
52         i.Lock()
53         defer i.Unlock()
54
55         return i.dstMaster
56 }
57
58 func (i *nwIface) Bridge() bool {
59         i.Lock()
60         defer i.Unlock()
61
62         return i.bridge
63 }
64
65 func (i *nwIface) Master() string {
66         i.Lock()
67         defer i.Unlock()
68
69         return i.master
70 }
71
72 func (i *nwIface) MacAddress() net.HardwareAddr {
73         i.Lock()
74         defer i.Unlock()
75
76         return types.GetMacCopy(i.mac)
77 }
78
79 func (i *nwIface) Address() *net.IPNet {
80         i.Lock()
81         defer i.Unlock()
82
83         return types.GetIPNetCopy(i.address)
84 }
85
86 func (i *nwIface) AddressIPv6() *net.IPNet {
87         i.Lock()
88         defer i.Unlock()
89
90         return types.GetIPNetCopy(i.addressIPv6)
91 }
92
93 func (i *nwIface) LinkLocalAddresses() []*net.IPNet {
94         i.Lock()
95         defer i.Unlock()
96
97         return i.llAddrs
98 }
99
100 func (i *nwIface) IPAliases() []*net.IPNet {
101         i.Lock()
102         defer i.Unlock()
103
104         return i.ipAliases
105 }
106
107 func (i *nwIface) Routes() []*net.IPNet {
108         i.Lock()
109         defer i.Unlock()
110
111         routes := make([]*net.IPNet, len(i.routes))
112         for index, route := range i.routes {
113                 r := types.GetIPNetCopy(route)
114                 routes[index] = r
115         }
116
117         return routes
118 }
119
120 func (n *networkNamespace) Interfaces() []Interface {
121         n.Lock()
122         defer n.Unlock()
123
124         ifaces := make([]Interface, len(n.iFaces))
125
126         for i, iface := range n.iFaces {
127                 ifaces[i] = iface
128         }
129
130         return ifaces
131 }
132
133 func (i *nwIface) Remove() error {
134         i.Lock()
135         n := i.ns
136         i.Unlock()
137
138         n.Lock()
139         isDefault := n.isDefault
140         nlh := n.nlHandle
141         n.Unlock()
142
143         // Find the network interface identified by the DstName attribute.
144         iface, err := nlh.LinkByName(i.DstName())
145         if err != nil {
146                 return err
147         }
148
149         // Down the interface before configuring
150         if err := nlh.LinkSetDown(iface); err != nil {
151                 return err
152         }
153
154         err = nlh.LinkSetName(iface, i.SrcName())
155         if err != nil {
156                 logrus.Debugf("LinkSetName failed for interface %s: %v", i.SrcName(), err)
157                 return err
158         }
159
160         // if it is a bridge just delete it.
161         if i.Bridge() {
162                 if err := nlh.LinkDel(iface); err != nil {
163                         return fmt.Errorf("failed deleting bridge %q: %v", i.SrcName(), err)
164                 }
165         } else if !isDefault {
166                 // Move the network interface to caller namespace.
167                 if err := nlh.LinkSetNsFd(iface, ns.ParseHandlerInt()); err != nil {
168                         logrus.Debugf("LinkSetNsPid failed for interface %s: %v", i.SrcName(), err)
169                         return err
170                 }
171         }
172
173         n.Lock()
174         for index, intf := range n.iFaces {
175                 if intf == i {
176                         n.iFaces = append(n.iFaces[:index], n.iFaces[index+1:]...)
177                         break
178                 }
179         }
180         n.Unlock()
181
182         n.checkLoV6()
183
184         return nil
185 }
186
187 // Returns the sandbox's side veth interface statistics
188 func (i *nwIface) Statistics() (*types.InterfaceStatistics, error) {
189         i.Lock()
190         n := i.ns
191         i.Unlock()
192
193         l, err := n.nlHandle.LinkByName(i.DstName())
194         if err != nil {
195                 return nil, fmt.Errorf("failed to retrieve the statistics for %s in netns %s: %v", i.DstName(), n.path, err)
196         }
197
198         stats := l.Attrs().Statistics
199         if stats == nil {
200                 return nil, fmt.Errorf("no statistics were returned")
201         }
202
203         return &types.InterfaceStatistics{
204                 RxBytes:   uint64(stats.RxBytes),
205                 TxBytes:   uint64(stats.TxBytes),
206                 RxPackets: uint64(stats.RxPackets),
207                 TxPackets: uint64(stats.TxPackets),
208                 RxDropped: uint64(stats.RxDropped),
209                 TxDropped: uint64(stats.TxDropped),
210         }, nil
211 }
212
213 func (n *networkNamespace) findDst(srcName string, isBridge bool) string {
214         n.Lock()
215         defer n.Unlock()
216
217         for _, i := range n.iFaces {
218                 // The master should match the srcname of the interface and the
219                 // master interface should be of type bridge, if searching for a bridge type
220                 if i.SrcName() == srcName && (!isBridge || i.Bridge()) {
221                         return i.DstName()
222                 }
223         }
224
225         return ""
226 }
227
228 func (n *networkNamespace) AddInterface(srcName, dstPrefix string, options ...IfaceOption) error {
229         i := &nwIface{srcName: srcName, dstName: dstPrefix, ns: n}
230         i.processInterfaceOptions(options...)
231
232         if i.master != "" {
233                 i.dstMaster = n.findDst(i.master, true)
234                 if i.dstMaster == "" {
235                         return fmt.Errorf("could not find an appropriate master %q for %q",
236                                 i.master, i.srcName)
237                 }
238         }
239
240         n.Lock()
241         if n.isDefault {
242                 i.dstName = i.srcName
243         } else {
244                 i.dstName = fmt.Sprintf("%s%d", dstPrefix, n.nextIfIndex[dstPrefix])
245                 n.nextIfIndex[dstPrefix]++
246         }
247
248         path := n.path
249         isDefault := n.isDefault
250         nlh := n.nlHandle
251         nlhHost := ns.NlHandle()
252         n.Unlock()
253
254         // If it is a bridge interface we have to create the bridge inside
255         // the namespace so don't try to lookup the interface using srcName
256         if i.bridge {
257                 link := &netlink.Bridge{
258                         LinkAttrs: netlink.LinkAttrs{
259                                 Name: i.srcName,
260                         },
261                 }
262                 if err := nlh.LinkAdd(link); err != nil {
263                         return fmt.Errorf("failed to create bridge %q: %v", i.srcName, err)
264                 }
265         } else {
266                 // Find the network interface identified by the SrcName attribute.
267                 iface, err := nlhHost.LinkByName(i.srcName)
268                 if err != nil {
269                         return fmt.Errorf("failed to get link by name %q: %v", i.srcName, err)
270                 }
271
272                 // Move the network interface to the destination
273                 // namespace only if the namespace is not a default
274                 // type
275                 if !isDefault {
276                         newNs, err := netns.GetFromPath(path)
277                         if err != nil {
278                                 return fmt.Errorf("failed get network namespace %q: %v", path, err)
279                         }
280                         defer newNs.Close()
281                         if err := nlhHost.LinkSetNsFd(iface, int(newNs)); err != nil {
282                                 return fmt.Errorf("failed to set namespace on link %q: %v", i.srcName, err)
283                         }
284                 }
285         }
286
287         // Find the network interface identified by the SrcName attribute.
288         iface, err := nlh.LinkByName(i.srcName)
289         if err != nil {
290                 return fmt.Errorf("failed to get link by name %q: %v", i.srcName, err)
291         }
292
293         // Down the interface before configuring
294         if err := nlh.LinkSetDown(iface); err != nil {
295                 return fmt.Errorf("failed to set link down: %v", err)
296         }
297
298         // Configure the interface now this is moved in the proper namespace.
299         if err := configureInterface(nlh, iface, i); err != nil {
300                 return err
301         }
302
303         // Up the interface.
304         cnt := 0
305         for err = nlh.LinkSetUp(iface); err != nil && cnt < 3; cnt++ {
306                 logrus.Debugf("retrying link setup because of: %v", err)
307                 time.Sleep(10 * time.Millisecond)
308                 err = nlh.LinkSetUp(iface)
309         }
310         if err != nil {
311                 return fmt.Errorf("failed to set link up: %v", err)
312         }
313
314         // Set the routes on the interface. This can only be done when the interface is up.
315         if err := setInterfaceRoutes(nlh, iface, i); err != nil {
316                 return fmt.Errorf("error setting interface %q routes to %q: %v", iface.Attrs().Name, i.Routes(), err)
317         }
318
319         n.Lock()
320         n.iFaces = append(n.iFaces, i)
321         n.Unlock()
322
323         n.checkLoV6()
324
325         return nil
326 }
327
328 func configureInterface(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error {
329         ifaceName := iface.Attrs().Name
330         ifaceConfigurators := []struct {
331                 Fn         func(*netlink.Handle, netlink.Link, *nwIface) error
332                 ErrMessage string
333         }{
334                 {setInterfaceName, fmt.Sprintf("error renaming interface %q to %q", ifaceName, i.DstName())},
335                 {setInterfaceMAC, fmt.Sprintf("error setting interface %q MAC to %q", ifaceName, i.MacAddress())},
336                 {setInterfaceIP, fmt.Sprintf("error setting interface %q IP to %#v", ifaceName, i.Address())},
337                 {setInterfaceIPv6, fmt.Sprintf("error setting interface %q IPv6 to %#v", ifaceName, i.AddressIPv6())},
338                 {setInterfaceMaster, fmt.Sprintf("error setting interface %q master to %q", ifaceName, i.DstMaster())},
339                 {setInterfaceLinkLocalIPs, fmt.Sprintf("error setting interface %q link local IPs to %v", ifaceName, i.LinkLocalAddresses())},
340                 {setInterfaceIPAliases, fmt.Sprintf("error setting interface %q IP Aliases to %v", ifaceName, i.IPAliases())},
341         }
342
343         for _, config := range ifaceConfigurators {
344                 if err := config.Fn(nlh, iface, i); err != nil {
345                         return fmt.Errorf("%s: %v", config.ErrMessage, err)
346                 }
347         }
348         return nil
349 }
350
351 func setInterfaceMaster(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error {
352         if i.DstMaster() == "" {
353                 return nil
354         }
355
356         return nlh.LinkSetMaster(iface, &netlink.Bridge{
357                 LinkAttrs: netlink.LinkAttrs{Name: i.DstMaster()}})
358 }
359
360 func setInterfaceMAC(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error {
361         if i.MacAddress() == nil {
362                 return nil
363         }
364         return nlh.LinkSetHardwareAddr(iface, i.MacAddress())
365 }
366
367 func setInterfaceIP(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error {
368         if i.Address() == nil {
369                 return nil
370         }
371         if err := checkRouteConflict(nlh, i.Address(), netlink.FAMILY_V4); err != nil {
372                 return err
373         }
374         ipAddr := &netlink.Addr{IPNet: i.Address(), Label: ""}
375         return nlh.AddrAdd(iface, ipAddr)
376 }
377
378 func setInterfaceIPv6(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error {
379         if i.AddressIPv6() == nil {
380                 return nil
381         }
382         if err := checkRouteConflict(nlh, i.AddressIPv6(), netlink.FAMILY_V6); err != nil {
383                 return err
384         }
385         if err := setIPv6(i.ns.path, i.DstName(), true); err != nil {
386                 return fmt.Errorf("failed to enable ipv6: %v", err)
387         }
388         ipAddr := &netlink.Addr{IPNet: i.AddressIPv6(), Label: "", Flags: syscall.IFA_F_NODAD}
389         return nlh.AddrAdd(iface, ipAddr)
390 }
391
392 func setInterfaceLinkLocalIPs(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error {
393         for _, llIP := range i.LinkLocalAddresses() {
394                 ipAddr := &netlink.Addr{IPNet: llIP}
395                 if err := nlh.AddrAdd(iface, ipAddr); err != nil {
396                         return err
397                 }
398         }
399         return nil
400 }
401
402 func setInterfaceIPAliases(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error {
403         for _, si := range i.IPAliases() {
404                 ipAddr := &netlink.Addr{IPNet: si}
405                 if err := nlh.AddrAdd(iface, ipAddr); err != nil {
406                         return err
407                 }
408         }
409         return nil
410 }
411
412 func setInterfaceName(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error {
413         return nlh.LinkSetName(iface, i.DstName())
414 }
415
416 func setInterfaceRoutes(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error {
417         for _, route := range i.Routes() {
418                 err := nlh.RouteAdd(&netlink.Route{
419                         Scope:     netlink.SCOPE_LINK,
420                         LinkIndex: iface.Attrs().Index,
421                         Dst:       route,
422                 })
423                 if err != nil {
424                         return err
425                 }
426         }
427         return nil
428 }
429
430 // In older kernels (like the one in Centos 6.6 distro) sysctl does not have netns support. Therefore
431 // we cannot gather the statistics from /sys/class/net/<dev>/statistics/<counter> files. Per-netns stats
432 // are naturally found in /proc/net/dev in kernels which support netns (ifconfig relies on that).
433 const (
434         netStatsFile = "/proc/net/dev"
435         base         = "[ ]*%s:([ ]+[0-9]+){16}"
436 )
437
438 func scanInterfaceStats(data, ifName string, i *types.InterfaceStatistics) error {
439         var (
440                 bktStr string
441                 bkt    uint64
442         )
443
444         regex := fmt.Sprintf(base, ifName)
445         re := regexp.MustCompile(regex)
446         line := re.FindString(data)
447
448         _, err := fmt.Sscanf(line, "%s %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
449                 &bktStr, &i.RxBytes, &i.RxPackets, &i.RxErrors, &i.RxDropped, &bkt, &bkt, &bkt,
450                 &bkt, &i.TxBytes, &i.TxPackets, &i.TxErrors, &i.TxDropped, &bkt, &bkt, &bkt, &bkt)
451
452         return err
453 }
454
455 func checkRouteConflict(nlh *netlink.Handle, address *net.IPNet, family int) error {
456         routes, err := nlh.RouteList(nil, family)
457         if err != nil {
458                 return err
459         }
460         for _, route := range routes {
461                 if route.Dst != nil {
462                         if route.Dst.Contains(address.IP) || address.Contains(route.Dst.IP) {
463                                 return fmt.Errorf("cannot program address %v in sandbox interface because it conflicts with existing route %s",
464                                         address, route)
465                         }
466                 }
467         }
468         return nil
469 }