github.com/pwn-term/docker@v0.0.0-20210616085119-6e977cce2565/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 nlh.NeighDel(nlnh) 106 } 107 } 108 109 n.Lock() 110 for i, nh := range n.neighbors { 111 if nh.dstIP.Equal(dstIP) && bytes.Equal(nh.dstMac, dstMac) { 112 n.neighbors = append(n.neighbors[:i], n.neighbors[i+1:]...) 113 break 114 } 115 } 116 n.Unlock() 117 logrus.Debugf("Neighbor entry deleted for IP %v, mac %v osDelete:%t", dstIP, dstMac, osDelete) 118 119 return nil 120 } 121 122 func (n *networkNamespace) AddNeighbor(dstIP net.IP, dstMac net.HardwareAddr, force bool, options ...NeighOption) error { 123 var ( 124 iface netlink.Link 125 err error 126 neighborAlreadyPresent bool 127 ) 128 129 // If the namespace already has the neighbor entry but the AddNeighbor is called 130 // because of a miss notification (force flag) program the kernel anyway. 131 nh := n.findNeighbor(dstIP, dstMac) 132 if nh != nil { 133 neighborAlreadyPresent = true 134 logrus.Warnf("Neighbor entry already present for IP %v, mac %v neighbor:%+v forceUpdate:%t", dstIP, dstMac, nh, force) 135 if !force { 136 return NeighborSearchError{dstIP, dstMac, true} 137 } 138 } 139 140 nh = &neigh{ 141 dstIP: dstIP, 142 dstMac: dstMac, 143 } 144 145 nh.processNeighOptions(options...) 146 147 if nh.linkName != "" { 148 nh.linkDst = n.findDst(nh.linkName, false) 149 if nh.linkDst == "" { 150 return fmt.Errorf("could not find the interface with name %s", nh.linkName) 151 } 152 } 153 154 n.Lock() 155 nlh := n.nlHandle 156 n.Unlock() 157 158 if nh.linkDst != "" { 159 iface, err = nlh.LinkByName(nh.linkDst) 160 if err != nil { 161 return fmt.Errorf("could not find interface with destination name %s: %v", nh.linkDst, err) 162 } 163 } 164 165 nlnh := &netlink.Neigh{ 166 IP: dstIP, 167 HardwareAddr: dstMac, 168 State: netlink.NUD_PERMANENT, 169 Family: nh.family, 170 } 171 172 if nlnh.Family > 0 { 173 nlnh.Flags = netlink.NTF_SELF 174 } 175 176 if nh.linkDst != "" { 177 nlnh.LinkIndex = iface.Attrs().Index 178 } 179 180 if err := nlh.NeighSet(nlnh); err != nil { 181 return fmt.Errorf("could not add neighbor entry:%+v error:%v", nlnh, err) 182 } 183 184 if neighborAlreadyPresent { 185 return nil 186 } 187 188 n.Lock() 189 n.neighbors = append(n.neighbors, nh) 190 n.Unlock() 191 logrus.Debugf("Neighbor entry added for IP:%v, mac:%v on ifc:%s", dstIP, dstMac, nh.linkName) 192 193 return nil 194 }