@@ -3,31 +3,18 @@ package dhcp
33import (
44 "context"
55 "net"
6- "regexp"
7- "time"
86
9- "github.com/Azure/azure-container-networking/cni/log"
107 "github.com/Azure/azure-container-networking/retry"
118 "github.com/pkg/errors"
129 "go.uber.org/zap"
1310 "golang.org/x/sys/windows"
1411)
1512
1613const (
17- dummyIPAddressStr = "169.254.128.10"
18- dummySubnetMask = "255.255.128.0"
19- addIPAddressDelay = 4 * time .Second
20- deleteIPAddressDelay = 2 * time .Second
21- returnDelay = 8 * time .Second // time to wait before returning from DiscoverRequest
22- retryCount = 5
23- retryDelayMillis = 500
24- socketTimeoutMillis = 1000
25- )
26-
27- var (
28- dummyIPAddress = net .IPv4 (169 , 254 , 128 , 10 ) // nolint
29- // matches if the string fully consists of zero or more alphanumeric, dots, dashes, parentheses, spaces, or underscores
30- allowedInput = regexp .MustCompile (`^[a-zA-Z0-9._\-\(\) ]*$` )
14+ retryCount = 5
15+ retryDelayMillis = 500
16+ ipAssignRetryDelayMillis = 2000
17+ socketTimeoutMillis = 1000
3118)
3219
3320type Socket struct {
@@ -91,38 +78,57 @@ func (s *Socket) Close() error {
9178 return nil
9279}
9380
94- // issues a dhcp discover request on an interface by assigning an ip to that interface
95- // then, sends a packet with that interface's dummy ip, and then unassigns the dummy ip
96- func (c * DHCP ) DiscoverRequest (ctx context.Context , macAddress net.HardwareAddr , ifName string ) error {
97- // validate interface name
98- if ! allowedInput .MatchString (ifName ) {
99- return errors .New ("invalid dhcp discover request interface name" )
81+ func (c * DHCP ) getIPv4InterfaceAddresses (ifName string ) ([]net.IP , error ) {
82+ nic , err := c .netioClient .GetNetworkInterfaceByName (ifName )
83+ if err != nil {
84+ return []net.IP {}, err
10085 }
101- // delete dummy ip off the interface if it already exists
102- ret , err := c .execClient .ExecuteCommand (ctx , "netsh" , "interface" , "ipv4" , "delete" , "address" , ifName , dummyIPAddressStr )
86+ addresses , err := c .netioClient .GetNetworkInterfaceAddrs (nic )
10387 if err != nil {
104- c .logger .Info ("Could not remove dummy ip, likely because it doesn't exist" , zap .String ("output" , ret ), zap .Error (log .NewErrorWithoutStackTrace (err )))
88+ return []net.IP {}, err
89+ }
90+ ret := []net.IP {}
91+ for _ , address := range addresses {
92+ // check if the ip is ipv4 and parse it
93+ ip , _ , err := net .ParseCIDR (address .String ())
94+ if err != nil || ip .To4 () == nil {
95+ continue
96+ }
97+ ret = append (ret , ip )
10598 }
106- time .Sleep (deleteIPAddressDelay )
10799
108- // create dummy ip so we can direct the packet to the correct interface
109- ret , err = c .execClient .ExecuteCommand (ctx , "netsh" , "interface" , "ipv4" , "add" , "address" , ifName , dummyIPAddressStr , dummySubnetMask )
100+ c .logger .Info ("Interface addresses found" , zap .Any ("foundIPs" , addresses ), zap .Any ("selectedIPs" , ret ))
101+ return ret , err
102+ }
103+
104+ func (c * DHCP ) verifyIPv4InterfaceAddressCount (ifName string , count , maxRuns , sleepMs int ) error {
105+ addressCountErr := retry .Do (func () error {
106+ addresses , err := c .getIPv4InterfaceAddresses (ifName )
107+ if err != nil || len (addresses ) != count {
108+ return errors .New ("address count found not equal to expected" )
109+ }
110+ return nil
111+ }, maxRuns , sleepMs )
112+ return addressCountErr
113+ }
114+
115+ // issues a dhcp discover request on an interface by finding the secondary's ip and sending on its ip
116+ func (c * DHCP ) DiscoverRequest (ctx context.Context , macAddress net.HardwareAddr , ifName string ) error {
117+ // Find the ipv4 address of the secondary interface (we're betting that this gets autoconfigured)
118+ err := c .verifyIPv4InterfaceAddressCount (ifName , 1 , retryCount , ipAssignRetryDelayMillis )
110119 if err != nil {
111- return errors .Wrap (err , "failed to add dummy ip to interface: " + ret )
120+ return errors .Wrap (err , "failed to get auto ip config assigned in apipa range in time" )
112121 }
113- // ensure we always remove the dummy ip we added from the interface
114- defer func () {
115- // we always want to try to remove the dummy ip, even if the deadline was reached
116- // so we have context.Background()
117- ret , cleanupErr := c .execClient .ExecuteCommand (context .Background (), "netsh" , "interface" , "ipv4" , "delete" , "address" , ifName , dummyIPAddressStr )
118- if cleanupErr != nil {
119- c .logger .Info ("Failed to remove dummy ip on leaving function" , zap .String ("output" , ret ), zap .Error (err ))
120- }
121- // wait for nic to retrieve autoconfiguration ip
122- time .Sleep (returnDelay )
123- }()
124- // it takes time for the address to be assigned
125- time .Sleep (addIPAddressDelay )
122+ ipv4Addresses , err := c .getIPv4InterfaceAddresses (ifName )
123+ if err != nil || len (ipv4Addresses ) == 0 {
124+ return errors .Wrap (err , "failed to get ipv4 addresses on interface" )
125+ }
126+ uniqueAddress := ipv4Addresses [0 ].To4 ()
127+ if uniqueAddress == nil {
128+ return errors .New ("invalid ipv4 address" )
129+ }
130+ uniqueAddressStr := uniqueAddress .String ()
131+ c .logger .Info ("Retrieved automatic ip configuration: " , zap .Any ("ip" , uniqueAddress ), zap .String ("ipStr" , uniqueAddressStr ))
126132
127133 // now begin the dhcp request
128134 txid , err := GenerateTransactionID ()
@@ -132,7 +138,7 @@ func (c *DHCP) DiscoverRequest(ctx context.Context, macAddress net.HardwareAddr,
132138
133139 // Prepare an IP and UDP header
134140 raddr := & net.UDPAddr {IP : net .IPv4bcast , Port : dhcpServerPort }
135- laddr := & net.UDPAddr {IP : dummyIPAddress , Port : dhcpClientPort }
141+ laddr := & net.UDPAddr {IP : uniqueAddress , Port : dhcpClientPort }
136142
137143 dhcpDiscover , err := buildDHCPDiscover (macAddress , txid )
138144 if err != nil {
0 commit comments