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 }