2015-07-02 05:00:48 +00:00
package osl
2015-06-05 03:21:23 +00:00
import (
2023-06-23 00:33:17 +00:00
"context"
2015-06-05 03:21:23 +00:00
"fmt"
"net"
2016-01-05 19:35:53 +00:00
"syscall"
2016-06-20 08:21:19 +00:00
"time"
2015-06-05 03:21:23 +00:00
2023-09-13 15:41:45 +00:00
"github.com/containerd/log"
2021-04-06 00:24:47 +00:00
"github.com/docker/docker/libnetwork/ns"
"github.com/docker/docker/libnetwork/types"
2015-06-05 03:21:23 +00:00
"github.com/vishvananda/netlink"
2016-05-16 18:51:40 +00:00
"github.com/vishvananda/netns"
2015-06-05 03:21:23 +00:00
)
2023-08-21 10:24:46 +00:00
// newInterface creates a new interface in the given namespace using the
// provided options.
func newInterface ( ns * Namespace , srcName , dstPrefix string , options ... IfaceOption ) ( * Interface , error ) {
i := & Interface {
srcName : srcName ,
dstName : dstPrefix ,
ns : ns ,
}
for _ , opt := range options {
if opt != nil {
// TODO(thaJeztah): use multi-error instead of returning early.
if err := opt ( i ) ; err != nil {
return nil , err
}
}
}
if i . master != "" {
i . dstMaster = ns . findDst ( i . master , true )
if i . dstMaster == "" {
return nil , fmt . Errorf ( "could not find an appropriate master %q for %q" , i . master , i . srcName )
}
}
return i , nil
}
2023-08-02 21:24:33 +00:00
// Interface represents the settings and identity of a network device.
2023-08-08 20:51:11 +00:00
// It is used as a return type for Network.Link, and it is common practice
// for the caller to use this information when moving interface SrcName from
// host namespace to DstName in a different net namespace with the appropriate
// network settings.
2023-08-02 21:24:33 +00:00
type Interface struct {
2015-06-05 03:21:23 +00:00
srcName string
dstName string
2015-06-05 06:45:04 +00:00
master string
dstMaster string
2015-10-29 07:04:08 +00:00
mac net . HardwareAddr
2015-06-05 03:21:23 +00:00
address * net . IPNet
addressIPv6 * net . IPNet
2016-05-25 03:04:49 +00:00
llAddrs [ ] * net . IPNet
2015-06-05 03:21:23 +00:00
routes [ ] * net . IPNet
2015-06-05 06:45:04 +00:00
bridge bool
2023-08-20 08:00:29 +00:00
ns * Namespace
2015-06-05 03:21:23 +00:00
}
2023-08-08 20:51:11 +00:00
// SrcName returns the name of the interface in the origin network namespace.
2023-08-02 21:24:33 +00:00
func ( i * Interface ) SrcName ( ) string {
2015-06-05 03:21:23 +00:00
return i . srcName
}
2023-08-08 20:51:11 +00:00
// DstName returns the name that will be assigned to the interface once
// moved inside a network namespace. When the caller passes in a DstName,
// it is only expected to pass a prefix. The name will be modified with an
// auto-generated suffix.
2023-08-02 21:24:33 +00:00
func ( i * Interface ) DstName ( ) string {
2015-06-05 03:21:23 +00:00
return i . dstName
}
2023-08-02 21:24:33 +00:00
func ( i * Interface ) DstMaster ( ) string {
2015-06-05 03:21:23 +00:00
return i . dstMaster
}
2023-08-08 20:51:11 +00:00
// Bridge returns true if the interface is a bridge.
2023-08-02 21:24:33 +00:00
func ( i * Interface ) Bridge ( ) bool {
2015-06-05 03:21:23 +00:00
return i . bridge
}
2023-08-02 21:24:33 +00:00
func ( i * Interface ) MacAddress ( ) net . HardwareAddr {
2015-10-29 07:04:08 +00:00
return types . GetMacCopy ( i . mac )
}
2023-08-08 20:51:11 +00:00
// Address returns the IPv4 address for the interface.
2023-08-02 21:24:33 +00:00
func ( i * Interface ) Address ( ) * net . IPNet {
2015-06-05 03:21:23 +00:00
return types . GetIPNetCopy ( i . address )
}
2023-08-08 20:51:11 +00:00
// AddressIPv6 returns the IPv6 address for the interface.
2023-08-02 21:24:33 +00:00
func ( i * Interface ) AddressIPv6 ( ) * net . IPNet {
2015-06-05 03:21:23 +00:00
return types . GetIPNetCopy ( i . addressIPv6 )
}
2023-08-08 20:51:11 +00:00
// LinkLocalAddresses returns the link-local IP addresses assigned to the
// interface.
2023-08-02 21:24:33 +00:00
func ( i * Interface ) LinkLocalAddresses ( ) [ ] * net . IPNet {
2016-05-25 03:04:49 +00:00
return i . llAddrs
}
2023-08-08 20:51:11 +00:00
// Routes returns IP routes for the interface.
2023-08-02 21:24:33 +00:00
func ( i * Interface ) Routes ( ) [ ] * net . IPNet {
2015-06-05 03:21:23 +00:00
routes := make ( [ ] * net . IPNet , len ( i . routes ) )
for index , route := range i . routes {
2023-08-02 23:45:45 +00:00
routes [ index ] = types . GetIPNetCopy ( route )
2015-06-05 03:21:23 +00:00
}
return routes
}
2023-08-08 20:51:11 +00:00
// Remove an interface from the sandbox by renaming to original name
// and moving it out of the sandbox.
2023-08-02 21:24:33 +00:00
func ( i * Interface ) Remove ( ) error {
2023-08-21 08:13:26 +00:00
nameSpace := i . ns
return nameSpace . RemoveInterface ( i )
2015-06-05 03:21:23 +00:00
}
2023-08-08 20:51:11 +00:00
// Statistics returns the sandbox's side veth interface statistics.
2023-08-02 21:24:33 +00:00
func ( i * Interface ) Statistics ( ) ( * types . InterfaceStatistics , error ) {
2023-08-02 23:45:45 +00:00
l , err := i . ns . nlHandle . LinkByName ( i . DstName ( ) )
2015-06-29 20:32:07 +00:00
if err != nil {
2023-08-02 23:45:45 +00:00
return nil , fmt . Errorf ( "failed to retrieve the statistics for %s in netns %s: %v" , i . DstName ( ) , i . ns . path , err )
2015-06-29 20:32:07 +00:00
}
2016-05-16 18:51:40 +00:00
stats := l . Attrs ( ) . Statistics
if stats == nil {
return nil , fmt . Errorf ( "no statistics were returned" )
}
return & types . InterfaceStatistics {
2021-05-28 00:15:56 +00:00
RxBytes : stats . RxBytes ,
TxBytes : stats . TxBytes ,
RxPackets : stats . RxPackets ,
TxPackets : stats . TxPackets ,
RxDropped : stats . RxDropped ,
TxDropped : stats . TxDropped ,
2016-05-16 18:51:40 +00:00
} , nil
2015-06-29 20:32:07 +00:00
}
2023-08-20 08:00:29 +00:00
func ( n * Namespace ) findDst ( srcName string , isBridge bool ) string {
2023-08-21 08:18:39 +00:00
n . mu . Lock ( )
defer n . mu . Unlock ( )
2015-06-05 03:21:23 +00:00
for _ , i := range n . iFaces {
// The master should match the srcname of the interface and the
2015-06-15 18:35:13 +00:00
// master interface should be of type bridge, if searching for a bridge type
if i . SrcName ( ) == srcName && ( ! isBridge || i . Bridge ( ) ) {
2015-06-05 03:21:23 +00:00
return i . DstName ( )
}
}
return ""
}
2023-08-20 07:30:44 +00:00
// AddInterface adds an existing Interface to the sandbox. The operation will rename
// from the Interface SrcName to DstName as it moves, and reconfigure the
// interface according to the specified settings. The caller is expected
// to only provide a prefix for DstName. The AddInterface api will auto-generate
// an appropriate suffix for the DstName to disambiguate.
2023-08-20 08:00:29 +00:00
func ( n * Namespace ) AddInterface ( srcName , dstPrefix string , options ... IfaceOption ) error {
2023-08-21 10:24:46 +00:00
i , err := newInterface ( n , srcName , dstPrefix , options ... )
if err != nil {
2023-08-20 09:19:55 +00:00
return err
}
2015-06-05 03:21:23 +00:00
2023-08-21 08:18:39 +00:00
n . mu . Lock ( )
2015-12-10 22:35:49 +00:00
if n . isDefault {
i . dstName = i . srcName
} else {
2017-02-27 22:23:12 +00:00
i . dstName = fmt . Sprintf ( "%s%d" , dstPrefix , n . nextIfIndex [ dstPrefix ] )
n . nextIfIndex [ dstPrefix ] ++
2015-12-10 22:35:49 +00:00
}
2015-06-05 03:21:23 +00:00
path := n . path
2015-12-10 22:35:49 +00:00
isDefault := n . isDefault
2016-05-16 18:51:40 +00:00
nlh := n . nlHandle
nlhHost := ns . NlHandle ( )
2023-08-21 08:18:39 +00:00
n . mu . Unlock ( )
2015-06-05 03:21:23 +00:00
2016-05-16 18:51:40 +00:00
// If it is a bridge interface we have to create the bridge inside
// the namespace so don't try to lookup the interface using srcName
if i . bridge {
2023-08-02 22:43:37 +00:00
if err := nlh . LinkAdd ( & netlink . Bridge {
2016-05-16 18:51:40 +00:00
LinkAttrs : netlink . LinkAttrs {
Name : i . srcName ,
} ,
2023-08-02 22:43:37 +00:00
} ) ; err != nil {
2016-05-16 18:51:40 +00:00
return fmt . Errorf ( "failed to create bridge %q: %v" , i . srcName , err )
}
} else {
2015-06-05 03:21:23 +00:00
// Find the network interface identified by the SrcName attribute.
2016-05-16 18:51:40 +00:00
iface , err := nlhHost . LinkByName ( i . srcName )
2015-06-05 03:21:23 +00:00
if err != nil {
return fmt . Errorf ( "failed to get link by name %q: %v" , i . srcName , err )
}
2015-12-10 22:35:49 +00:00
// Move the network interface to the destination
// namespace only if the namespace is not a default
// type
if ! isDefault {
2016-05-16 18:51:40 +00:00
newNs , err := netns . GetFromPath ( path )
if err != nil {
return fmt . Errorf ( "failed get network namespace %q: %v" , path , err )
2015-06-05 06:45:04 +00:00
}
2016-05-16 18:51:40 +00:00
defer newNs . Close ( )
if err := nlhHost . LinkSetNsFd ( iface , int ( newNs ) ) ; err != nil {
return fmt . Errorf ( "failed to set namespace on link %q: %v" , i . srcName , err )
2015-06-05 06:45:04 +00:00
}
}
2016-05-16 18:51:40 +00:00
}
2015-06-05 06:45:04 +00:00
2016-05-16 18:51:40 +00:00
// Find the network interface identified by the SrcName attribute.
iface , err := nlh . LinkByName ( i . srcName )
if err != nil {
return fmt . Errorf ( "failed to get link by name %q: %v" , i . srcName , err )
}
2015-06-05 03:21:23 +00:00
2016-05-16 18:51:40 +00:00
// Down the interface before configuring
if err := nlh . LinkSetDown ( iface ) ; err != nil {
return fmt . Errorf ( "failed to set link down: %v" , err )
}
2015-06-05 03:21:23 +00:00
2016-05-16 18:51:40 +00:00
// Configure the interface now this is moved in the proper namespace.
if err := configureInterface ( nlh , iface , i ) ; err != nil {
2017-06-10 23:51:58 +00:00
// If configuring the device fails move it back to the host namespace
// and change the name back to the source name. This allows the caller
// to properly cleanup the interface. Its important especially for
// interfaces with global attributes, ex: vni id for vxlan interfaces.
if nerr := nlh . LinkSetName ( iface , i . SrcName ( ) ) ; nerr != nil {
2023-06-23 00:33:17 +00:00
log . G ( context . TODO ( ) ) . Errorf ( "renaming interface (%s->%s) failed, %v after config error %v" , i . DstName ( ) , i . SrcName ( ) , nerr , err )
2017-06-10 23:51:58 +00:00
}
if nerr := nlh . LinkSetNsFd ( iface , ns . ParseHandlerInt ( ) ) ; nerr != nil {
2023-06-23 00:33:17 +00:00
log . G ( context . TODO ( ) ) . Errorf ( "moving interface %s to host ns failed, %v, after config error %v" , i . SrcName ( ) , nerr , err )
2017-06-10 23:51:58 +00:00
}
2016-05-16 18:51:40 +00:00
return err
}
2015-06-05 03:21:23 +00:00
2016-05-16 18:51:40 +00:00
// Up the interface.
2016-06-20 08:21:19 +00:00
cnt := 0
for err = nlh . LinkSetUp ( iface ) ; err != nil && cnt < 3 ; cnt ++ {
2023-06-23 00:33:17 +00:00
log . G ( context . TODO ( ) ) . Debugf ( "retrying link setup because of: %v" , err )
2016-06-20 08:21:19 +00:00
time . Sleep ( 10 * time . Millisecond )
2016-07-19 11:09:23 +00:00
err = nlh . LinkSetUp ( iface )
2016-06-20 08:21:19 +00:00
}
if err != nil {
2016-05-16 18:51:40 +00:00
return fmt . Errorf ( "failed to set link up: %v" , err )
}
2015-06-05 03:21:23 +00:00
2016-05-16 18:51:40 +00:00
// Set the routes on the interface. This can only be done when the interface is up.
if err := setInterfaceRoutes ( nlh , iface , i ) ; err != nil {
return fmt . Errorf ( "error setting interface %q routes to %q: %v" , iface . Attrs ( ) . Name , i . Routes ( ) , err )
}
2015-09-17 23:05:25 +00:00
2023-08-21 08:18:39 +00:00
n . mu . Lock ( )
2016-05-16 18:51:40 +00:00
n . iFaces = append ( n . iFaces , i )
2023-08-21 08:18:39 +00:00
n . mu . Unlock ( )
2015-06-05 03:21:23 +00:00
2016-02-23 21:28:14 +00:00
n . checkLoV6 ( )
2016-05-16 18:51:40 +00:00
return nil
2015-06-05 03:21:23 +00:00
}
2023-08-21 08:13:26 +00:00
// RemoveInterface removes an interface from the namespace by renaming to
// original name and moving it out of the sandbox.
func ( n * Namespace ) RemoveInterface ( i * Interface ) error {
2023-08-21 08:18:39 +00:00
n . mu . Lock ( )
2023-08-21 08:13:26 +00:00
isDefault := n . isDefault
nlh := n . nlHandle
2023-08-21 08:18:39 +00:00
n . mu . Unlock ( )
2023-08-21 08:13:26 +00:00
// Find the network interface identified by the DstName attribute.
iface , err := nlh . LinkByName ( i . DstName ( ) )
if err != nil {
return err
}
// Down the interface before configuring
if err := nlh . LinkSetDown ( iface ) ; err != nil {
return err
}
2023-09-20 10:35:03 +00:00
// 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
2023-08-21 08:13:26 +00:00
err = nlh . LinkSetName ( iface , i . SrcName ( ) )
if err != nil {
log . G ( context . TODO ( ) ) . Debugf ( "LinkSetName failed for interface %s: %v" , i . SrcName ( ) , err )
return err
}
// if it is a bridge just delete it.
if i . Bridge ( ) {
if err := nlh . LinkDel ( iface ) ; err != nil {
return fmt . Errorf ( "failed deleting bridge %q: %v" , i . SrcName ( ) , err )
}
} else if ! isDefault {
// Move the network interface to caller namespace.
2023-09-20 10:35:03 +00:00
// 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
2023-08-21 08:13:26 +00:00
if err := nlh . LinkSetNsFd ( iface , ns . ParseHandlerInt ( ) ) ; err != nil {
log . G ( context . TODO ( ) ) . Debugf ( "LinkSetNsFd failed for interface %s: %v" , i . SrcName ( ) , err )
return err
}
}
2023-08-21 08:18:39 +00:00
n . mu . Lock ( )
2023-08-21 08:13:26 +00:00
for index , intf := range i . ns . iFaces {
if intf == i {
i . ns . iFaces = append ( i . ns . iFaces [ : index ] , i . ns . iFaces [ index + 1 : ] ... )
break
}
}
2023-08-21 08:18:39 +00:00
n . mu . Unlock ( )
2023-08-21 08:13:26 +00:00
2023-09-20 10:35:03 +00:00
// 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.
2023-08-21 08:13:26 +00:00
n . checkLoV6 ( )
return nil
}
2023-08-02 21:24:33 +00:00
func configureInterface ( nlh * netlink . Handle , iface netlink . Link , i * Interface ) error {
2015-06-05 03:21:23 +00:00
ifaceName := iface . Attrs ( ) . Name
ifaceConfigurators := [ ] struct {
2023-08-02 21:24:33 +00:00
Fn func ( * netlink . Handle , netlink . Link , * Interface ) error
2015-06-05 03:21:23 +00:00
ErrMessage string
} {
{ setInterfaceName , fmt . Sprintf ( "error renaming interface %q to %q" , ifaceName , i . DstName ( ) ) } ,
2015-10-29 07:04:08 +00:00
{ setInterfaceMAC , fmt . Sprintf ( "error setting interface %q MAC to %q" , ifaceName , i . MacAddress ( ) ) } ,
2016-03-16 17:51:16 +00:00
{ setInterfaceIP , fmt . Sprintf ( "error setting interface %q IP to %v" , ifaceName , i . Address ( ) ) } ,
{ setInterfaceIPv6 , fmt . Sprintf ( "error setting interface %q IPv6 to %v" , ifaceName , i . AddressIPv6 ( ) ) } ,
2015-06-05 03:21:23 +00:00
{ setInterfaceMaster , fmt . Sprintf ( "error setting interface %q master to %q" , ifaceName , i . DstMaster ( ) ) } ,
2016-05-25 03:04:49 +00:00
{ setInterfaceLinkLocalIPs , fmt . Sprintf ( "error setting interface %q link local IPs to %v" , ifaceName , i . LinkLocalAddresses ( ) ) } ,
2015-06-05 03:21:23 +00:00
}
for _ , config := range ifaceConfigurators {
2016-05-16 18:51:40 +00:00
if err := config . Fn ( nlh , iface , i ) ; err != nil {
2015-06-05 03:21:23 +00:00
return fmt . Errorf ( "%s: %v" , config . ErrMessage , err )
}
}
return nil
}
2023-08-02 21:24:33 +00:00
func setInterfaceMaster ( nlh * netlink . Handle , iface netlink . Link , i * Interface ) error {
2015-06-05 03:21:23 +00:00
if i . DstMaster ( ) == "" {
return nil
}
2016-05-16 18:51:40 +00:00
return nlh . LinkSetMaster ( iface , & netlink . Bridge {
2022-01-20 13:07:26 +00:00
LinkAttrs : netlink . LinkAttrs { Name : i . DstMaster ( ) } ,
} )
2015-06-05 03:21:23 +00:00
}
2023-08-02 21:24:33 +00:00
func setInterfaceMAC ( nlh * netlink . Handle , iface netlink . Link , i * Interface ) error {
2015-10-29 07:04:08 +00:00
if i . MacAddress ( ) == nil {
return nil
}
2016-05-16 18:51:40 +00:00
return nlh . LinkSetHardwareAddr ( iface , i . MacAddress ( ) )
2015-10-29 07:04:08 +00:00
}
2023-08-02 21:24:33 +00:00
func setInterfaceIP ( nlh * netlink . Handle , iface netlink . Link , i * Interface ) error {
2015-06-05 03:21:23 +00:00
if i . Address ( ) == nil {
return nil
}
2016-10-13 18:14:39 +00:00
if err := checkRouteConflict ( nlh , i . Address ( ) , netlink . FAMILY_V4 ) ; err != nil {
return err
}
2015-06-05 03:21:23 +00:00
ipAddr := & netlink . Addr { IPNet : i . Address ( ) , Label : "" }
2016-05-16 18:51:40 +00:00
return nlh . AddrAdd ( iface , ipAddr )
2015-06-05 03:21:23 +00:00
}
2023-08-02 21:24:33 +00:00
func setInterfaceIPv6 ( nlh * netlink . Handle , iface netlink . Link , i * Interface ) error {
2015-06-05 03:21:23 +00:00
if i . AddressIPv6 ( ) == nil {
return nil
}
2016-10-13 18:14:39 +00:00
if err := checkRouteConflict ( nlh , i . AddressIPv6 ( ) , netlink . FAMILY_V6 ) ; err != nil {
return err
}
2016-02-23 21:28:14 +00:00
if err := setIPv6 ( i . ns . path , i . DstName ( ) , true ) ; err != nil {
return fmt . Errorf ( "failed to enable ipv6: %v" , err )
}
2016-01-05 19:35:53 +00:00
ipAddr := & netlink . Addr { IPNet : i . AddressIPv6 ( ) , Label : "" , Flags : syscall . IFA_F_NODAD }
2016-05-16 18:51:40 +00:00
return nlh . AddrAdd ( iface , ipAddr )
2015-06-05 03:21:23 +00:00
}
2023-08-02 21:24:33 +00:00
func setInterfaceLinkLocalIPs ( nlh * netlink . Handle , iface netlink . Link , i * Interface ) error {
2016-05-25 03:04:49 +00:00
for _ , llIP := range i . LinkLocalAddresses ( ) {
ipAddr := & netlink . Addr { IPNet : llIP }
2016-05-16 18:51:40 +00:00
if err := nlh . AddrAdd ( iface , ipAddr ) ; err != nil {
2016-05-25 03:04:49 +00:00
return err
}
}
return nil
}
2023-08-02 21:24:33 +00:00
func setInterfaceName ( nlh * netlink . Handle , iface netlink . Link , i * Interface ) error {
2016-05-16 18:51:40 +00:00
return nlh . LinkSetName ( iface , i . DstName ( ) )
2015-06-05 03:21:23 +00:00
}
2023-08-02 21:24:33 +00:00
func setInterfaceRoutes ( nlh * netlink . Handle , iface netlink . Link , i * Interface ) error {
2015-06-05 03:21:23 +00:00
for _ , route := range i . Routes ( ) {
2016-05-16 18:51:40 +00:00
err := nlh . RouteAdd ( & netlink . Route {
2015-06-05 03:21:23 +00:00
Scope : netlink . SCOPE_LINK ,
LinkIndex : iface . Attrs ( ) . Index ,
Dst : route ,
} )
if err != nil {
return err
}
}
return nil
}
2015-06-29 20:32:07 +00:00
2016-10-13 18:14:39 +00:00
func checkRouteConflict ( nlh * netlink . Handle , address * net . IPNet , family int ) error {
routes , err := nlh . RouteList ( nil , family )
if err != nil {
return err
}
for _ , route := range routes {
if route . Dst != nil {
if route . Dst . Contains ( address . IP ) || address . Contains ( route . Dst . IP ) {
return fmt . Errorf ( "cannot program address %v in sandbox interface because it conflicts with existing route %s" ,
address , route )
}
}
}
return nil
}