ipv4ll_linux.go 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. package netconf
  2. import (
  3. "encoding/binary"
  4. "fmt"
  5. "math/rand"
  6. "net"
  7. log "github.com/Sirupsen/logrus"
  8. "github.com/j-keck/arping"
  9. "github.com/vishvananda/netlink"
  10. )
  11. func AssignLinkLocalIP(link netlink.Link) error {
  12. ifaceName := link.Attrs().Name
  13. iface, err := net.InterfaceByName(ifaceName)
  14. if err != nil {
  15. log.Error("could not get information about interface")
  16. return err
  17. }
  18. addrs, err := iface.Addrs()
  19. if err != nil {
  20. log.Error("Error fetching existing ip on interface")
  21. }
  22. for _, addr := range addrs {
  23. if addr.String()[:7] == "169.254" {
  24. log.Info("Link Local IP already set on interface")
  25. return nil
  26. }
  27. }
  28. randSource, err := getPseudoRandomGenerator(link.Attrs().HardwareAddr)
  29. if err != nil {
  30. return err
  31. }
  32. // try a random address upto 10 times
  33. for i := 0; i < 10; i++ {
  34. randGenerator := rand.New(*randSource)
  35. randomNum := randGenerator.Uint32()
  36. dstIP := getNewIPV4LLAddr(randomNum)
  37. if dstIP[2] == 0 || dstIP[2] == 255 {
  38. i--
  39. continue
  40. }
  41. _, _, err := arping.PingOverIfaceByName(dstIP, ifaceName)
  42. if err != nil {
  43. // this ip is not being used
  44. addr, err := netlink.ParseAddr(dstIP.String() + "/16")
  45. if err != nil {
  46. log.Errorf("error while parsing ipv4ll addr, err = %v", err)
  47. return err
  48. }
  49. if err := netlink.AddrAdd(link, addr); err != nil {
  50. log.Error("ipv4ll addr add failed")
  51. return err
  52. }
  53. log.Infof("Set %s on %s", dstIP.String(), link.Attrs().Name)
  54. return nil
  55. }
  56. }
  57. log.Error("Could not find a suitable ipv4ll")
  58. return fmt.Errorf("Could not find a suitable ipv4ll")
  59. }
  60. func getNewIPV4LLAddr(randomNum uint32) net.IP {
  61. byte1 := randomNum & 255 // use least significant 8 bits
  62. byte2 := randomNum >> 24 // use most significant 8 bits
  63. return []byte{169, 254, byte(byte1), byte(byte2)}
  64. }
  65. func getPseudoRandomGenerator(haAddr []byte) (*rand.Source, error) {
  66. seed, _ := binary.Varint(haAddr)
  67. src := rand.NewSource(seed)
  68. return &src, nil
  69. }