ipv4ll_linux.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. package netconf
  2. import (
  3. "encoding/binary"
  4. "fmt"
  5. "math/rand"
  6. "net"
  7. "github.com/rancher/os/log"
  8. "github.com/j-keck/arping"
  9. "github.com/vishvananda/netlink"
  10. "github.com/vishvananda/netlink/nl"
  11. )
  12. func AssignLinkLocalIP(link netlink.Link) error {
  13. ifaceName := link.Attrs().Name
  14. addrs, err := getLinkAddrs(link)
  15. if err != nil {
  16. return err
  17. }
  18. for _, addr := range addrs {
  19. if addr.String()[:7] == "169.254" {
  20. log.Info("Link Local IP already set on interface")
  21. return nil
  22. }
  23. }
  24. randSource, err := getPseudoRandomGenerator(link.Attrs().HardwareAddr)
  25. if err != nil {
  26. return err
  27. }
  28. // try a random address upto 10 times
  29. for i := 0; i < 10; i++ {
  30. randGenerator := rand.New(*randSource)
  31. randomNum := randGenerator.Uint32()
  32. dstIP := getNewIPV4LLAddr(randomNum)
  33. if dstIP[2] == 0 || dstIP[2] == 255 {
  34. i--
  35. continue
  36. }
  37. _, _, err := arping.PingOverIfaceByName(dstIP, ifaceName)
  38. if err != nil {
  39. // this ip is not being used
  40. addr, err := netlink.ParseAddr(dstIP.String() + "/16")
  41. if err != nil {
  42. log.Errorf("error while parsing ipv4ll addr, err = %v", err)
  43. return err
  44. }
  45. if err := netlink.AddrAdd(link, addr); err != nil {
  46. log.Error("ipv4ll addr add failed")
  47. return err
  48. }
  49. log.Infof("Set %s on %s", dstIP.String(), link.Attrs().Name)
  50. return nil
  51. }
  52. }
  53. log.Error("Could not find a suitable ipv4ll")
  54. return fmt.Errorf("Could not find a suitable ipv4ll")
  55. }
  56. func RemoveLinkLocalIP(link netlink.Link) error {
  57. addrs, err := getLinkAddrs(link)
  58. if err != nil {
  59. return err
  60. }
  61. for _, addr := range addrs {
  62. if addr.String()[:7] == "169.254" {
  63. if err := netlink.AddrDel(link, &addr); err != nil {
  64. log.Error("ipv4ll addr del failed")
  65. return err
  66. }
  67. log.Infof("Removed LinkLocal %s from %s", addr.String(), link.Attrs().Name)
  68. return nil
  69. }
  70. }
  71. return nil
  72. }
  73. func getNewIPV4LLAddr(randomNum uint32) net.IP {
  74. byte1 := randomNum & 255 // use least significant 8 bits
  75. byte2 := randomNum >> 24 // use most significant 8 bits
  76. return []byte{169, 254, byte(byte1), byte(byte2)}
  77. }
  78. func getPseudoRandomGenerator(haAddr []byte) (*rand.Source, error) {
  79. seed, _ := binary.Varint(haAddr)
  80. src := rand.NewSource(seed)
  81. return &src, nil
  82. }
  83. func getLinkAddrs(link netlink.Link) ([]netlink.Addr, error) {
  84. addrs, err := netlink.AddrList(link, nl.FAMILY_ALL)
  85. if err != nil {
  86. log.Error("Error fetching existing ip on interface, %s", err)
  87. err = nil // atm, we ignore this, as the link may not have one?
  88. }
  89. return addrs, err
  90. }