github.com/rawahars/moby@v24.0.4+incompatible/libnetwork/osl/interface_linux.go (about) 1 package osl 2 3 import ( 4 "fmt" 5 "net" 6 "sync" 7 "syscall" 8 "time" 9 10 "github.com/docker/docker/libnetwork/ns" 11 "github.com/docker/docker/libnetwork/types" 12 "github.com/sirupsen/logrus" 13 "github.com/vishvananda/netlink" 14 "github.com/vishvananda/netns" 15 ) 16 17 type nwIface struct { 18 srcName string 19 dstName string 20 master string 21 dstMaster string 22 mac net.HardwareAddr 23 address *net.IPNet 24 addressIPv6 *net.IPNet 25 llAddrs []*net.IPNet 26 routes []*net.IPNet 27 bridge bool 28 ns *networkNamespace 29 sync.Mutex 30 } 31 32 func (i *nwIface) SrcName() string { 33 i.Lock() 34 defer i.Unlock() 35 36 return i.srcName 37 } 38 39 func (i *nwIface) DstName() string { 40 i.Lock() 41 defer i.Unlock() 42 43 return i.dstName 44 } 45 46 func (i *nwIface) DstMaster() string { 47 i.Lock() 48 defer i.Unlock() 49 50 return i.dstMaster 51 } 52 53 func (i *nwIface) Bridge() bool { 54 i.Lock() 55 defer i.Unlock() 56 57 return i.bridge 58 } 59 60 func (i *nwIface) Master() string { 61 i.Lock() 62 defer i.Unlock() 63 64 return i.master 65 } 66 67 func (i *nwIface) MacAddress() net.HardwareAddr { 68 i.Lock() 69 defer i.Unlock() 70 71 return types.GetMacCopy(i.mac) 72 } 73 74 func (i *nwIface) Address() *net.IPNet { 75 i.Lock() 76 defer i.Unlock() 77 78 return types.GetIPNetCopy(i.address) 79 } 80 81 func (i *nwIface) AddressIPv6() *net.IPNet { 82 i.Lock() 83 defer i.Unlock() 84 85 return types.GetIPNetCopy(i.addressIPv6) 86 } 87 88 func (i *nwIface) LinkLocalAddresses() []*net.IPNet { 89 i.Lock() 90 defer i.Unlock() 91 92 return i.llAddrs 93 } 94 95 func (i *nwIface) Routes() []*net.IPNet { 96 i.Lock() 97 defer i.Unlock() 98 99 routes := make([]*net.IPNet, len(i.routes)) 100 for index, route := range i.routes { 101 r := types.GetIPNetCopy(route) 102 routes[index] = r 103 } 104 105 return routes 106 } 107 108 func (n *networkNamespace) Interfaces() []Interface { 109 n.Lock() 110 defer n.Unlock() 111 112 ifaces := make([]Interface, len(n.iFaces)) 113 114 for i, iface := range n.iFaces { 115 ifaces[i] = iface 116 } 117 118 return ifaces 119 } 120 121 func (i *nwIface) Remove() error { 122 i.Lock() 123 n := i.ns 124 i.Unlock() 125 126 n.Lock() 127 isDefault := n.isDefault 128 nlh := n.nlHandle 129 n.Unlock() 130 131 // Find the network interface identified by the DstName attribute. 132 iface, err := nlh.LinkByName(i.DstName()) 133 if err != nil { 134 return err 135 } 136 137 // Down the interface before configuring 138 if err := nlh.LinkSetDown(iface); err != nil { 139 return err 140 } 141 142 err = nlh.LinkSetName(iface, i.SrcName()) 143 if err != nil { 144 logrus.Debugf("LinkSetName failed for interface %s: %v", i.SrcName(), err) 145 return err 146 } 147 148 // if it is a bridge just delete it. 149 if i.Bridge() { 150 if err := nlh.LinkDel(iface); err != nil { 151 return fmt.Errorf("failed deleting bridge %q: %v", i.SrcName(), err) 152 } 153 } else if !isDefault { 154 // Move the network interface to caller namespace. 155 if err := nlh.LinkSetNsFd(iface, ns.ParseHandlerInt()); err != nil { 156 logrus.Debugf("LinkSetNsPid failed for interface %s: %v", i.SrcName(), err) 157 return err 158 } 159 } 160 161 n.Lock() 162 for index, intf := range n.iFaces { 163 if intf == i { 164 n.iFaces = append(n.iFaces[:index], n.iFaces[index+1:]...) 165 break 166 } 167 } 168 n.Unlock() 169 170 n.checkLoV6() 171 172 return nil 173 } 174 175 // Returns the sandbox's side veth interface statistics 176 func (i *nwIface) Statistics() (*types.InterfaceStatistics, error) { 177 i.Lock() 178 n := i.ns 179 i.Unlock() 180 181 l, err := n.nlHandle.LinkByName(i.DstName()) 182 if err != nil { 183 return nil, fmt.Errorf("failed to retrieve the statistics for %s in netns %s: %v", i.DstName(), n.path, err) 184 } 185 186 stats := l.Attrs().Statistics 187 if stats == nil { 188 return nil, fmt.Errorf("no statistics were returned") 189 } 190 191 return &types.InterfaceStatistics{ 192 RxBytes: stats.RxBytes, 193 TxBytes: stats.TxBytes, 194 RxPackets: stats.RxPackets, 195 TxPackets: stats.TxPackets, 196 RxDropped: stats.RxDropped, 197 TxDropped: stats.TxDropped, 198 }, nil 199 } 200 201 func (n *networkNamespace) findDst(srcName string, isBridge bool) string { 202 n.Lock() 203 defer n.Unlock() 204 205 for _, i := range n.iFaces { 206 // The master should match the srcname of the interface and the 207 // master interface should be of type bridge, if searching for a bridge type 208 if i.SrcName() == srcName && (!isBridge || i.Bridge()) { 209 return i.DstName() 210 } 211 } 212 213 return "" 214 } 215 216 func (n *networkNamespace) AddInterface(srcName, dstPrefix string, options ...IfaceOption) error { 217 i := &nwIface{srcName: srcName, dstName: dstPrefix, ns: n} 218 i.processInterfaceOptions(options...) 219 220 if i.master != "" { 221 i.dstMaster = n.findDst(i.master, true) 222 if i.dstMaster == "" { 223 return fmt.Errorf("could not find an appropriate master %q for %q", 224 i.master, i.srcName) 225 } 226 } 227 228 n.Lock() 229 if n.isDefault { 230 i.dstName = i.srcName 231 } else { 232 i.dstName = fmt.Sprintf("%s%d", dstPrefix, n.nextIfIndex[dstPrefix]) 233 n.nextIfIndex[dstPrefix]++ 234 } 235 236 path := n.path 237 isDefault := n.isDefault 238 nlh := n.nlHandle 239 nlhHost := ns.NlHandle() 240 n.Unlock() 241 242 // If it is a bridge interface we have to create the bridge inside 243 // the namespace so don't try to lookup the interface using srcName 244 if i.bridge { 245 link := &netlink.Bridge{ 246 LinkAttrs: netlink.LinkAttrs{ 247 Name: i.srcName, 248 }, 249 } 250 if err := nlh.LinkAdd(link); err != nil { 251 return fmt.Errorf("failed to create bridge %q: %v", i.srcName, err) 252 } 253 } else { 254 // Find the network interface identified by the SrcName attribute. 255 iface, err := nlhHost.LinkByName(i.srcName) 256 if err != nil { 257 return fmt.Errorf("failed to get link by name %q: %v", i.srcName, err) 258 } 259 260 // Move the network interface to the destination 261 // namespace only if the namespace is not a default 262 // type 263 if !isDefault { 264 newNs, err := netns.GetFromPath(path) 265 if err != nil { 266 return fmt.Errorf("failed get network namespace %q: %v", path, err) 267 } 268 defer newNs.Close() 269 if err := nlhHost.LinkSetNsFd(iface, int(newNs)); err != nil { 270 return fmt.Errorf("failed to set namespace on link %q: %v", i.srcName, err) 271 } 272 } 273 } 274 275 // Find the network interface identified by the SrcName attribute. 276 iface, err := nlh.LinkByName(i.srcName) 277 if err != nil { 278 return fmt.Errorf("failed to get link by name %q: %v", i.srcName, err) 279 } 280 281 // Down the interface before configuring 282 if err := nlh.LinkSetDown(iface); err != nil { 283 return fmt.Errorf("failed to set link down: %v", err) 284 } 285 286 // Configure the interface now this is moved in the proper namespace. 287 if err := configureInterface(nlh, iface, i); err != nil { 288 // If configuring the device fails move it back to the host namespace 289 // and change the name back to the source name. This allows the caller 290 // to properly cleanup the interface. Its important especially for 291 // interfaces with global attributes, ex: vni id for vxlan interfaces. 292 if nerr := nlh.LinkSetName(iface, i.SrcName()); nerr != nil { 293 logrus.Errorf("renaming interface (%s->%s) failed, %v after config error %v", i.DstName(), i.SrcName(), nerr, err) 294 } 295 if nerr := nlh.LinkSetNsFd(iface, ns.ParseHandlerInt()); nerr != nil { 296 logrus.Errorf("moving interface %s to host ns failed, %v, after config error %v", i.SrcName(), nerr, err) 297 } 298 return err 299 } 300 301 // Up the interface. 302 cnt := 0 303 for err = nlh.LinkSetUp(iface); err != nil && cnt < 3; cnt++ { 304 logrus.Debugf("retrying link setup because of: %v", err) 305 time.Sleep(10 * time.Millisecond) 306 err = nlh.LinkSetUp(iface) 307 } 308 if err != nil { 309 return fmt.Errorf("failed to set link up: %v", err) 310 } 311 312 // Set the routes on the interface. This can only be done when the interface is up. 313 if err := setInterfaceRoutes(nlh, iface, i); err != nil { 314 return fmt.Errorf("error setting interface %q routes to %q: %v", iface.Attrs().Name, i.Routes(), err) 315 } 316 317 n.Lock() 318 n.iFaces = append(n.iFaces, i) 319 n.Unlock() 320 321 n.checkLoV6() 322 323 return nil 324 } 325 326 func configureInterface(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error { 327 ifaceName := iface.Attrs().Name 328 ifaceConfigurators := []struct { 329 Fn func(*netlink.Handle, netlink.Link, *nwIface) error 330 ErrMessage string 331 }{ 332 {setInterfaceName, fmt.Sprintf("error renaming interface %q to %q", ifaceName, i.DstName())}, 333 {setInterfaceMAC, fmt.Sprintf("error setting interface %q MAC to %q", ifaceName, i.MacAddress())}, 334 {setInterfaceIP, fmt.Sprintf("error setting interface %q IP to %v", ifaceName, i.Address())}, 335 {setInterfaceIPv6, fmt.Sprintf("error setting interface %q IPv6 to %v", ifaceName, i.AddressIPv6())}, 336 {setInterfaceMaster, fmt.Sprintf("error setting interface %q master to %q", ifaceName, i.DstMaster())}, 337 {setInterfaceLinkLocalIPs, fmt.Sprintf("error setting interface %q link local IPs to %v", ifaceName, i.LinkLocalAddresses())}, 338 } 339 340 for _, config := range ifaceConfigurators { 341 if err := config.Fn(nlh, iface, i); err != nil { 342 return fmt.Errorf("%s: %v", config.ErrMessage, err) 343 } 344 } 345 return nil 346 } 347 348 func setInterfaceMaster(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error { 349 if i.DstMaster() == "" { 350 return nil 351 } 352 353 return nlh.LinkSetMaster(iface, &netlink.Bridge{ 354 LinkAttrs: netlink.LinkAttrs{Name: i.DstMaster()}}) 355 } 356 357 func setInterfaceMAC(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error { 358 if i.MacAddress() == nil { 359 return nil 360 } 361 return nlh.LinkSetHardwareAddr(iface, i.MacAddress()) 362 } 363 364 func setInterfaceIP(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error { 365 if i.Address() == nil { 366 return nil 367 } 368 if err := checkRouteConflict(nlh, i.Address(), netlink.FAMILY_V4); err != nil { 369 return err 370 } 371 ipAddr := &netlink.Addr{IPNet: i.Address(), Label: ""} 372 return nlh.AddrAdd(iface, ipAddr) 373 } 374 375 func setInterfaceIPv6(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error { 376 if i.AddressIPv6() == nil { 377 return nil 378 } 379 if err := checkRouteConflict(nlh, i.AddressIPv6(), netlink.FAMILY_V6); err != nil { 380 return err 381 } 382 if err := setIPv6(i.ns.path, i.DstName(), true); err != nil { 383 return fmt.Errorf("failed to enable ipv6: %v", err) 384 } 385 ipAddr := &netlink.Addr{IPNet: i.AddressIPv6(), Label: "", Flags: syscall.IFA_F_NODAD} 386 return nlh.AddrAdd(iface, ipAddr) 387 } 388 389 func setInterfaceLinkLocalIPs(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error { 390 for _, llIP := range i.LinkLocalAddresses() { 391 ipAddr := &netlink.Addr{IPNet: llIP} 392 if err := nlh.AddrAdd(iface, ipAddr); err != nil { 393 return err 394 } 395 } 396 return nil 397 } 398 399 func setInterfaceName(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error { 400 return nlh.LinkSetName(iface, i.DstName()) 401 } 402 403 func setInterfaceRoutes(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error { 404 for _, route := range i.Routes() { 405 err := nlh.RouteAdd(&netlink.Route{ 406 Scope: netlink.SCOPE_LINK, 407 LinkIndex: iface.Attrs().Index, 408 Dst: route, 409 }) 410 if err != nil { 411 return err 412 } 413 } 414 return nil 415 } 416 417 func checkRouteConflict(nlh *netlink.Handle, address *net.IPNet, family int) error { 418 routes, err := nlh.RouteList(nil, family) 419 if err != nil { 420 return err 421 } 422 for _, route := range routes { 423 if route.Dst != nil { 424 if route.Dst.Contains(address.IP) || address.Contains(route.Dst.IP) { 425 return fmt.Errorf("cannot program address %v in sandbox interface because it conflicts with existing route %s", 426 address, route) 427 } 428 } 429 } 430 return nil 431 }