Skip to content

feat: query host to check if dhcp rehydration feature is enabled before issuing dhcp request #3318

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions dhcp/dhcp_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (
"encoding/binary"
"io"
"net"
"net/http"
"strings"
"time"

"github.com/pkg/errors"
Expand Down Expand Up @@ -37,6 +39,9 @@ const (
hops = 0
secs = 0
flags = 0x8000 // Broadcast flag

nmAgentSupportedApisURL = "http://168.63.129.16/machine/plugins/?comp=nmagent&type=GetSupportedApis"
dhcpRehydrationAPIStr = "SwiftV2DhcpRehydrationFromGoalState" // Set value provided by host
)

// TransactionID represents a 4-byte DHCP transaction ID as defined in RFC 951,
Expand All @@ -49,6 +54,8 @@ var (
magicCookie = []byte{0x63, 0x82, 0x53, 0x63} // DHCP magic cookie
DefaultReadTimeout = 3 * time.Second
DefaultTimeout = 3 * time.Second

errResponseNotOK = errors.New("not ok http status")
)

type DHCP struct {
Expand Down Expand Up @@ -459,3 +466,37 @@ func (c *DHCP) DiscoverRequest(ctx context.Context, mac net.HardwareAddr, ifname
res := c.receiveDHCPResponse(ctx, reader, txid)
return res
}

// DHCPRehydrationFeatureOnHost queries the host to check if a particular API is supported,
// and if so, returns true; if we are unable to determine if the feature is enabled, an error
// is returned
func (c *DHCP) DHCPRehydrationFeatureOnHost(ctx context.Context) (bool, error) {
var (
resp *http.Response
httpClient = &http.Client{Timeout: DefaultTimeout}
)
req, err := http.NewRequestWithContext(ctx, http.MethodGet, nmAgentSupportedApisURL, http.NoBody)
if err != nil {
return false, errors.Wrap(err, "failed to create http request")
}
req.Header.Add("Metadata", "true")
req.Header.Add("x-ms-version", "2012-11-30")
resp, err = httpClient.Do(req)
if err != nil {
return false, errors.Wrap(err, "error issuing http request")
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return false, errResponseNotOK
}
readBytes, err := io.ReadAll(resp.Body)
if err != nil {
return false, errors.Wrap(err, "failed to read response body")
}
str := string(readBytes)
if !strings.Contains(str, dhcpRehydrationAPIStr) {
return false, nil
}

return true, nil
}
4 changes: 4 additions & 0 deletions dhcp/dhcp_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,7 @@ func New(logger *zap.Logger) *DHCP {
func (c *DHCP) DiscoverRequest(_ context.Context, _ net.HardwareAddr, _ string) error {
return nil
}

func (c *DHCP) DHCPRehydrationFeatureOnHost(_ context.Context) (bool, error) {
return false, nil
}
7 changes: 6 additions & 1 deletion network/dhcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,15 @@ import (

type dhcpClient interface {
DiscoverRequest(context.Context, net.HardwareAddr, string) error
DHCPRehydrationFeatureOnHost(context.Context) (bool, error)
}

type mockDHCP struct{}

func (netns *mockDHCP) DiscoverRequest(context.Context, net.HardwareAddr, string) error {
func (d *mockDHCP) DiscoverRequest(context.Context, net.HardwareAddr, string) error {
return nil
}

func (d *mockDHCP) DHCPRehydrationFeatureOnHost(context.Context) (bool, error) {
return false, nil
}
15 changes: 12 additions & 3 deletions network/secondary_endpoint_client_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,10 +138,19 @@ func (client *SecondaryEndpointClient) ConfigureContainerInterfacesAndRoutes(epI
timeout := time.Duration(numSecs) * time.Second
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(timeout))
defer cancel()
logger.Info("Sending DHCP packet", zap.Any("macAddress", epInfo.MacAddress), zap.String("ifName", epInfo.IfName))
err := client.dhcpClient.DiscoverRequest(ctx, epInfo.MacAddress, epInfo.IfName)

// check if the permanent fix on the host has already rolled out
dhcpRehydrationFeatureEnabled, err := client.dhcpClient.DHCPRehydrationFeatureOnHost(ctx)
if err != nil {
return errors.Wrapf(err, "failed to issue dhcp discover packet to create mapping in host")
return errors.Wrap(err, "could not determine if dhcp rehydration feature enabled on host")
}
// only send the dhcp packet if the host does not have the permanent fix
if !dhcpRehydrationFeatureEnabled {
logger.Info("Sending DHCP packet", zap.Any("macAddress", epInfo.MacAddress), zap.String("ifName", epInfo.IfName))
err := client.dhcpClient.DiscoverRequest(ctx, epInfo.MacAddress, epInfo.IfName)
if err != nil {
return errors.Wrap(err, "failed to issue dhcp discover packet to create mapping in host")
}
}
logger.Info("Finished configuring container interfaces and routes for secondary endpoint client")

Expand Down
Loading