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