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 }