github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/libnetwork/osl/interface_linux.go (about)

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