@@ -3,31 +3,19 @@ package dhcp
33import (
44 "context"
55 "net"
6- "regexp"
76 "time"
87
9- "github.com/Azure/azure-container-networking/cni/log"
108 "github.com/Azure/azure-container-networking/retry"
119 "github.com/pkg/errors"
1210 "go.uber.org/zap"
1311 "golang.org/x/sys/windows"
1412)
1513
1614const (
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._\-\(\) ]*$` )
15+ retryCount = 5
16+ retryDelayMillis = 500
17+ ipAssignRetryDelayMillis = 2000
18+ socketTimeoutMillis = 1000
3119)
3220
3321type Socket struct {
@@ -91,38 +79,57 @@ func (s *Socket) Close() error {
9179 return nil
9280}
9381
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" )
82+ func (c * DHCP ) getIPv4InterfaceAddresses (ifName string ) ([]net.IP , error ) {
83+ nic , err := c .netioClient .GetNetworkInterfaceByName (ifName )
84+ if err != nil {
85+ return []net.IP {}, err
10086 }
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 )
87+ addresses , err := c .netioClient .GetNetworkInterfaceAddrs (nic )
10388 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 )))
89+ return []net.IP {}, err
90+ }
91+ ret := []net.IP {}
92+ for _ , address := range addresses {
93+ // check if the ip is ipv4 and parse it
94+ ip , _ , err := net .ParseCIDR (address .String ())
95+ if err != nil || ip .To4 () == nil {
96+ continue
97+ }
98+ ret = append (ret , ip )
10599 }
106- time .Sleep (deleteIPAddressDelay )
107100
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 )
101+ c .logger .Info ("Interface addresses found" , zap .Any ("foundIPs" , addresses ), zap .Any ("selectedIPs" , ret ))
102+ return ret , err
103+ }
104+
105+ func (c * DHCP ) verifyIPv4InterfaceAddressCount (ifName string , count , maxRuns , sleepMs int ) error {
106+ addressCountErr := retry .Do (func () error {
107+ addresses , err := c .getIPv4InterfaceAddresses (ifName )
108+ if err != nil || len (addresses ) != count {
109+ return errors .New ("address count found not equal to expected" )
110+ }
111+ return nil
112+ }, maxRuns , sleepMs )
113+ return addressCountErr
114+ }
115+
116+ // issues a dhcp discover request on an interface by finding the secondary's ip and sending on its ip
117+ func (c * DHCP ) DiscoverRequest (ctx context.Context , macAddress net.HardwareAddr , ifName string ) error {
118+ // Find the ipv4 address of the secondary interface (we're betting that this gets autoconfigured)
119+ err := c .verifyIPv4InterfaceAddressCount (ifName , 1 , retryCount , ipAssignRetryDelayMillis )
110120 if err != nil {
111- return errors .Wrap (err , "failed to add dummy ip to interface: " + ret )
121+ return errors .Wrap (err , "failed to get auto ip config assigned in apipa range in time" )
112122 }
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 )
123+ ipv4Addresses , err := c .getIPv4InterfaceAddresses (ifName )
124+ if err != nil || len (ipv4Addresses ) == 0 {
125+ return errors .Wrap (err , "failed to get ipv4 addresses on interface" )
126+ }
127+ uniqueAddress := ipv4Addresses [0 ].To4 ()
128+ if uniqueAddress == nil {
129+ return errors .New ("invalid ipv4 address" )
130+ }
131+ uniqueAddressStr := uniqueAddress .String ()
132+ c .logger .Info ("Retrieved automatic ip configuration: " , zap .Any ("ip" , uniqueAddress ), zap .String ("ipStr" , uniqueAddressStr ))
126133
127134 // now begin the dhcp request
128135 txid , err := GenerateTransactionID ()
@@ -132,7 +139,7 @@ func (c *DHCP) DiscoverRequest(ctx context.Context, macAddress net.HardwareAddr,
132139
133140 // Prepare an IP and UDP header
134141 raddr := & net.UDPAddr {IP : net .IPv4bcast , Port : dhcpServerPort }
135- laddr := & net.UDPAddr {IP : dummyIPAddress , Port : dhcpClientPort }
142+ laddr := & net.UDPAddr {IP : uniqueAddress , Port : dhcpClientPort }
136143
137144 dhcpDiscover , err := buildDHCPDiscover (macAddress , txid )
138145 if err != nil {
0 commit comments