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 }