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