addr_linux.go 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. // Copyright 2017 CNI authors
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package ip
  15. import (
  16. "fmt"
  17. "syscall"
  18. "time"
  19. "github.com/vishvananda/netlink"
  20. )
  21. const SETTLE_INTERVAL = 50 * time.Millisecond
  22. // SettleAddresses waits for all addresses on a link to leave tentative state.
  23. // This is particularly useful for ipv6, where all addresses need to do DAD.
  24. // There is no easy way to wait for this as an event, so just loop until the
  25. // addresses are no longer tentative.
  26. // If any addresses are still tentative after timeout seconds, then error.
  27. func SettleAddresses(ifName string, timeout int) error {
  28. link, err := netlink.LinkByName(ifName)
  29. if err != nil {
  30. return fmt.Errorf("failed to retrieve link: %v", err)
  31. }
  32. deadline := time.Now().Add(time.Duration(timeout) * time.Second)
  33. for {
  34. addrs, err := netlink.AddrList(link, netlink.FAMILY_ALL)
  35. if err != nil {
  36. return fmt.Errorf("could not list addresses: %v", err)
  37. }
  38. if len(addrs) == 0 {
  39. return nil
  40. }
  41. ok := true
  42. for _, addr := range addrs {
  43. if addr.Flags&(syscall.IFA_F_TENTATIVE|syscall.IFA_F_DADFAILED) > 0 {
  44. ok = false
  45. break // Break out of the `range addrs`, not the `for`
  46. }
  47. }
  48. if ok {
  49. return nil
  50. }
  51. if time.Now().After(deadline) {
  52. return fmt.Errorf("link %s still has tentative addresses after %d seconds",
  53. ifName,
  54. timeout)
  55. }
  56. time.Sleep(SETTLE_INTERVAL)
  57. }
  58. }