github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/mergeCode/libnetwork/drivers/bridge/netlink_deprecated_linux.go (about)

     1  package bridge
     2  
     3  import (
     4  	"fmt"
     5  	"math/rand"
     6  	"net"
     7  	"syscall"
     8  	"time"
     9  	"unsafe"
    10  
    11  	"github.com/docker/libnetwork/netutils"
    12  )
    13  
    14  const (
    15  	ifNameSize   = 16
    16  	ioctlBrAdd   = 0x89a0
    17  	ioctlBrAddIf = 0x89a2
    18  )
    19  
    20  type ifreqIndex struct {
    21  	IfrnName  [ifNameSize]byte
    22  	IfruIndex int32
    23  }
    24  
    25  type ifreqHwaddr struct {
    26  	IfrnName   [ifNameSize]byte
    27  	IfruHwaddr syscall.RawSockaddr
    28  }
    29  
    30  var rnd = rand.New(rand.NewSource(time.Now().UnixNano()))
    31  
    32  // THIS CODE DOES NOT COMMUNICATE WITH KERNEL VIA RTNETLINK INTERFACE
    33  // IT IS HERE FOR BACKWARDS COMPATIBILITY WITH OLDER LINUX KERNELS
    34  // WHICH SHIP WITH OLDER NOT ENTIRELY FUNCTIONAL VERSION OF NETLINK
    35  func getIfSocket() (fd int, err error) {
    36  	for _, socket := range []int{
    37  		syscall.AF_INET,
    38  		syscall.AF_PACKET,
    39  		syscall.AF_INET6,
    40  	} {
    41  		if fd, err = syscall.Socket(socket, syscall.SOCK_DGRAM, 0); err == nil {
    42  			break
    43  		}
    44  	}
    45  	if err == nil {
    46  		return fd, nil
    47  	}
    48  	return -1, err
    49  }
    50  
    51  func ifIoctBridge(iface, master *net.Interface, op uintptr) error {
    52  	if len(master.Name) >= ifNameSize {
    53  		return fmt.Errorf("Interface name %s too long", master.Name)
    54  	}
    55  
    56  	s, err := getIfSocket()
    57  	if err != nil {
    58  		return err
    59  	}
    60  	defer syscall.Close(s)
    61  
    62  	ifr := ifreqIndex{}
    63  	copy(ifr.IfrnName[:len(ifr.IfrnName)-1], master.Name)
    64  	ifr.IfruIndex = int32(iface.Index)
    65  
    66  	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(s), op, uintptr(unsafe.Pointer(&ifr))); err != 0 {
    67  		return err
    68  	}
    69  
    70  	return nil
    71  }
    72  
    73  // Add a slave to a bridge device.  This is more backward-compatible than
    74  // netlink.NetworkSetMaster and works on RHEL 6.
    75  func ioctlAddToBridge(iface, master *net.Interface) error {
    76  	return ifIoctBridge(iface, master, ioctlBrAddIf)
    77  }
    78  
    79  func ioctlSetMacAddress(name, addr string) error {
    80  	if len(name) >= ifNameSize {
    81  		return fmt.Errorf("Interface name %s too long", name)
    82  	}
    83  
    84  	hw, err := net.ParseMAC(addr)
    85  	if err != nil {
    86  		return err
    87  	}
    88  
    89  	s, err := getIfSocket()
    90  	if err != nil {
    91  		return err
    92  	}
    93  	defer syscall.Close(s)
    94  
    95  	ifr := ifreqHwaddr{}
    96  	ifr.IfruHwaddr.Family = syscall.ARPHRD_ETHER
    97  	copy(ifr.IfrnName[:len(ifr.IfrnName)-1], name)
    98  
    99  	for i := 0; i < 6; i++ {
   100  		ifr.IfruHwaddr.Data[i] = ifrDataByte(hw[i])
   101  	}
   102  
   103  	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(s), syscall.SIOCSIFHWADDR, uintptr(unsafe.Pointer(&ifr))); err != 0 {
   104  		return err
   105  	}
   106  	return nil
   107  }
   108  
   109  func ioctlCreateBridge(name string, setMacAddr bool) error {
   110  	if len(name) >= ifNameSize {
   111  		return fmt.Errorf("Interface name %s too long", name)
   112  	}
   113  
   114  	s, err := getIfSocket()
   115  	if err != nil {
   116  		return err
   117  	}
   118  	defer syscall.Close(s)
   119  
   120  	nameBytePtr, err := syscall.BytePtrFromString(name)
   121  	if err != nil {
   122  		return err
   123  	}
   124  	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(s), ioctlBrAdd, uintptr(unsafe.Pointer(nameBytePtr))); err != 0 {
   125  		return err
   126  	}
   127  	if setMacAddr {
   128  		return ioctlSetMacAddress(name, netutils.GenerateRandomMAC().String())
   129  	}
   130  	return nil
   131  }