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"
18 // IfaceOption is a function option type to set interface options
19 type IfaceOption func(i *nwIface)
28 addressIPv6 *net.IPNet
29 ipAliases []*net.IPNet
37 func (i *nwIface) SrcName() string {
44 func (i *nwIface) DstName() string {
51 func (i *nwIface) DstMaster() string {
58 func (i *nwIface) Bridge() bool {
65 func (i *nwIface) Master() string {
72 func (i *nwIface) MacAddress() net.HardwareAddr {
76 return types.GetMacCopy(i.mac)
79 func (i *nwIface) Address() *net.IPNet {
83 return types.GetIPNetCopy(i.address)
86 func (i *nwIface) AddressIPv6() *net.IPNet {
90 return types.GetIPNetCopy(i.addressIPv6)
93 func (i *nwIface) LinkLocalAddresses() []*net.IPNet {
100 func (i *nwIface) IPAliases() []*net.IPNet {
107 func (i *nwIface) Routes() []*net.IPNet {
111 routes := make([]*net.IPNet, len(i.routes))
112 for index, route := range i.routes {
113 r := types.GetIPNetCopy(route)
120 func (n *networkNamespace) Interfaces() []Interface {
124 ifaces := make([]Interface, len(n.iFaces))
126 for i, iface := range n.iFaces {
133 func (i *nwIface) Remove() error {
139 isDefault := n.isDefault
143 // Find the network interface identified by the DstName attribute.
144 iface, err := nlh.LinkByName(i.DstName())
149 // Down the interface before configuring
150 if err := nlh.LinkSetDown(iface); err != nil {
154 err = nlh.LinkSetName(iface, i.SrcName())
156 logrus.Debugf("LinkSetName failed for interface %s: %v", i.SrcName(), err)
160 // if it is a bridge just delete it.
162 if err := nlh.LinkDel(iface); err != nil {
163 return fmt.Errorf("failed deleting bridge %q: %v", i.SrcName(), err)
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)
174 for index, intf := range n.iFaces {
176 n.iFaces = append(n.iFaces[:index], n.iFaces[index+1:]...)
187 // Returns the sandbox's side veth interface statistics
188 func (i *nwIface) Statistics() (*types.InterfaceStatistics, error) {
193 l, err := n.nlHandle.LinkByName(i.DstName())
195 return nil, fmt.Errorf("failed to retrieve the statistics for %s in netns %s: %v", i.DstName(), n.path, err)
198 stats := l.Attrs().Statistics
200 return nil, fmt.Errorf("no statistics were returned")
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),
213 func (n *networkNamespace) findDst(srcName string, isBridge bool) string {
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()) {
228 func (n *networkNamespace) AddInterface(srcName, dstPrefix string, options ...IfaceOption) error {
229 i := &nwIface{srcName: srcName, dstName: dstPrefix, ns: n}
230 i.processInterfaceOptions(options...)
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",
242 i.dstName = i.srcName
244 i.dstName = fmt.Sprintf("%s%d", dstPrefix, n.nextIfIndex[dstPrefix])
245 n.nextIfIndex[dstPrefix]++
249 isDefault := n.isDefault
251 nlhHost := ns.NlHandle()
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
257 link := &netlink.Bridge{
258 LinkAttrs: netlink.LinkAttrs{
262 if err := nlh.LinkAdd(link); err != nil {
263 return fmt.Errorf("failed to create bridge %q: %v", i.srcName, err)
266 // Find the network interface identified by the SrcName attribute.
267 iface, err := nlhHost.LinkByName(i.srcName)
269 return fmt.Errorf("failed to get link by name %q: %v", i.srcName, err)
272 // Move the network interface to the destination
273 // namespace only if the namespace is not a default
276 newNs, err := netns.GetFromPath(path)
278 return fmt.Errorf("failed get network namespace %q: %v", path, err)
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)
287 // Find the network interface identified by the SrcName attribute.
288 iface, err := nlh.LinkByName(i.srcName)
290 return fmt.Errorf("failed to get link by name %q: %v", i.srcName, err)
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)
298 // Configure the interface now this is moved in the proper namespace.
299 if err := configureInterface(nlh, iface, i); err != nil {
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)
311 return fmt.Errorf("failed to set link up: %v", err)
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)
320 n.iFaces = append(n.iFaces, i)
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
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())},
343 for _, config := range ifaceConfigurators {
344 if err := config.Fn(nlh, iface, i); err != nil {
345 return fmt.Errorf("%s: %v", config.ErrMessage, err)
351 func setInterfaceMaster(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error {
352 if i.DstMaster() == "" {
356 return nlh.LinkSetMaster(iface, &netlink.Bridge{
357 LinkAttrs: netlink.LinkAttrs{Name: i.DstMaster()}})
360 func setInterfaceMAC(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error {
361 if i.MacAddress() == nil {
364 return nlh.LinkSetHardwareAddr(iface, i.MacAddress())
367 func setInterfaceIP(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error {
368 if i.Address() == nil {
371 if err := checkRouteConflict(nlh, i.Address(), netlink.FAMILY_V4); err != nil {
374 ipAddr := &netlink.Addr{IPNet: i.Address(), Label: ""}
375 return nlh.AddrAdd(iface, ipAddr)
378 func setInterfaceIPv6(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error {
379 if i.AddressIPv6() == nil {
382 if err := checkRouteConflict(nlh, i.AddressIPv6(), netlink.FAMILY_V6); err != nil {
385 if err := setIPv6(i.ns.path, i.DstName(), true); err != nil {
386 return fmt.Errorf("failed to enable ipv6: %v", err)
388 ipAddr := &netlink.Addr{IPNet: i.AddressIPv6(), Label: "", Flags: syscall.IFA_F_NODAD}
389 return nlh.AddrAdd(iface, ipAddr)
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 {
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 {
412 func setInterfaceName(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error {
413 return nlh.LinkSetName(iface, i.DstName())
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,
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).
434 netStatsFile = "/proc/net/dev"
435 base = "[ ]*%s:([ ]+[0-9]+){16}"
438 func scanInterfaceStats(data, ifName string, i *types.InterfaceStatistics) error {
444 regex := fmt.Sprintf(base, ifName)
445 re := regexp.MustCompile(regex)
446 line := re.FindString(data)
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)
455 func checkRouteConflict(nlh *netlink.Handle, address *net.IPNet, family int) error {
456 routes, err := nlh.RouteList(nil, family)
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",