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

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