github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/libnetwork/osl/neigh_linux.go (about)

     1  package osl
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"net"
     7  
     8  	"github.com/sirupsen/logrus"
     9  	"github.com/vishvananda/netlink"
    10  )
    11  
    12  // NeighborSearchError indicates that the neighbor is already present
    13  type NeighborSearchError struct {
    14  	ip      net.IP
    15  	mac     net.HardwareAddr
    16  	present bool
    17  }
    18  
    19  func (n NeighborSearchError) Error() string {
    20  	return fmt.Sprintf("Search neighbor failed for IP %v, mac %v, present in db:%t", n.ip, n.mac, n.present)
    21  }
    22  
    23  // NeighOption is a function option type to set interface options
    24  type NeighOption func(nh *neigh)
    25  
    26  type neigh struct {
    27  	dstIP    net.IP
    28  	dstMac   net.HardwareAddr
    29  	linkName string
    30  	linkDst  string
    31  	family   int
    32  }
    33  
    34  func (n *networkNamespace) findNeighbor(dstIP net.IP, dstMac net.HardwareAddr) *neigh {
    35  	n.Lock()
    36  	defer n.Unlock()
    37  
    38  	for _, nh := range n.neighbors {
    39  		if nh.dstIP.Equal(dstIP) && bytes.Equal(nh.dstMac, dstMac) {
    40  			return nh
    41  		}
    42  	}
    43  
    44  	return nil
    45  }
    46  
    47  func (n *networkNamespace) DeleteNeighbor(dstIP net.IP, dstMac net.HardwareAddr, osDelete bool) error {
    48  	var (
    49  		iface netlink.Link
    50  		err   error
    51  	)
    52  
    53  	nh := n.findNeighbor(dstIP, dstMac)
    54  	if nh == nil {
    55  		return NeighborSearchError{dstIP, dstMac, false}
    56  	}
    57  
    58  	if osDelete {
    59  		n.Lock()
    60  		nlh := n.nlHandle
    61  		n.Unlock()
    62  
    63  		if nh.linkDst != "" {
    64  			iface, err = nlh.LinkByName(nh.linkDst)
    65  			if err != nil {
    66  				return fmt.Errorf("could not find interface with destination name %s: %v",
    67  					nh.linkDst, err)
    68  			}
    69  		}
    70  
    71  		nlnh := &netlink.Neigh{
    72  			IP:     dstIP,
    73  			State:  netlink.NUD_PERMANENT,
    74  			Family: nh.family,
    75  		}
    76  
    77  		if nlnh.Family > 0 {
    78  			nlnh.HardwareAddr = dstMac
    79  			nlnh.Flags = netlink.NTF_SELF
    80  		}
    81  
    82  		if nh.linkDst != "" {
    83  			nlnh.LinkIndex = iface.Attrs().Index
    84  		}
    85  
    86  		// If the kernel deletion fails for the neighbor entry still remote it
    87  		// from the namespace cache. Otherwise if the neighbor moves back to the
    88  		// same host again, kernel update can fail.
    89  		if err := nlh.NeighDel(nlnh); err != nil {
    90  			logrus.Warnf("Deleting neighbor IP %s, mac %s failed, %v", dstIP, dstMac, err)
    91  		}
    92  
    93  		// Delete the dynamic entry in the bridge
    94  		if nlnh.Family > 0 {
    95  			nlnh := &netlink.Neigh{
    96  				IP:     dstIP,
    97  				Family: nh.family,
    98  			}
    99  
   100  			nlnh.HardwareAddr = dstMac
   101  			nlnh.Flags = netlink.NTF_MASTER
   102  			if nh.linkDst != "" {
   103  				nlnh.LinkIndex = iface.Attrs().Index
   104  			}
   105  			if err := nlh.NeighDel(nlnh); err != nil {
   106  				logrus.WithError(err).Warn("error while deleting neighbor entry")
   107  			}
   108  		}
   109  	}
   110  
   111  	n.Lock()
   112  	for i, nh := range n.neighbors {
   113  		if nh.dstIP.Equal(dstIP) && bytes.Equal(nh.dstMac, dstMac) {
   114  			n.neighbors = append(n.neighbors[:i], n.neighbors[i+1:]...)
   115  			break
   116  		}
   117  	}
   118  	n.Unlock()
   119  	logrus.Debugf("Neighbor entry deleted for IP %v, mac %v osDelete:%t", dstIP, dstMac, osDelete)
   120  
   121  	return nil
   122  }
   123  
   124  func (n *networkNamespace) AddNeighbor(dstIP net.IP, dstMac net.HardwareAddr, force bool, options ...NeighOption) error {
   125  	var (
   126  		iface                  netlink.Link
   127  		err                    error
   128  		neighborAlreadyPresent bool
   129  	)
   130  
   131  	// If the namespace already has the neighbor entry but the AddNeighbor is called
   132  	// because of a miss notification (force flag) program the kernel anyway.
   133  	nh := n.findNeighbor(dstIP, dstMac)
   134  	if nh != nil {
   135  		neighborAlreadyPresent = true
   136  		logrus.Warnf("Neighbor entry already present for IP %v, mac %v neighbor:%+v forceUpdate:%t", dstIP, dstMac, nh, force)
   137  		if !force {
   138  			return NeighborSearchError{dstIP, dstMac, true}
   139  		}
   140  	}
   141  
   142  	nh = &neigh{
   143  		dstIP:  dstIP,
   144  		dstMac: dstMac,
   145  	}
   146  
   147  	nh.processNeighOptions(options...)
   148  
   149  	if nh.linkName != "" {
   150  		nh.linkDst = n.findDst(nh.linkName, false)
   151  		if nh.linkDst == "" {
   152  			return fmt.Errorf("could not find the interface with name %s", nh.linkName)
   153  		}
   154  	}
   155  
   156  	n.Lock()
   157  	nlh := n.nlHandle
   158  	n.Unlock()
   159  
   160  	if nh.linkDst != "" {
   161  		iface, err = nlh.LinkByName(nh.linkDst)
   162  		if err != nil {
   163  			return fmt.Errorf("could not find interface with destination name %s: %v", nh.linkDst, err)
   164  		}
   165  	}
   166  
   167  	nlnh := &netlink.Neigh{
   168  		IP:           dstIP,
   169  		HardwareAddr: dstMac,
   170  		State:        netlink.NUD_PERMANENT,
   171  		Family:       nh.family,
   172  	}
   173  
   174  	if nlnh.Family > 0 {
   175  		nlnh.Flags = netlink.NTF_SELF
   176  	}
   177  
   178  	if nh.linkDst != "" {
   179  		nlnh.LinkIndex = iface.Attrs().Index
   180  	}
   181  
   182  	if err := nlh.NeighSet(nlnh); err != nil {
   183  		return fmt.Errorf("could not add neighbor entry:%+v error:%v", nlnh, err)
   184  	}
   185  
   186  	if neighborAlreadyPresent {
   187  		return nil
   188  	}
   189  
   190  	n.Lock()
   191  	n.neighbors = append(n.neighbors, nh)
   192  	n.Unlock()
   193  	logrus.Debugf("Neighbor entry added for IP:%v, mac:%v on ifc:%s", dstIP, dstMac, nh.linkName)
   194  
   195  	return nil
   196  }