github.com/rawahars/moby@v24.0.4+incompatible/libnetwork/osl/interface_linux.go (about)

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