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