From c17ea8c6e20f58510b063f064d45608792a014e4 Mon Sep 17 00:00:00 2001 From: Sepehr Raissian Date: Fri, 28 Sep 2018 10:59:21 -0700 Subject: Block for link address resolution Previously, if address resolution for UDP or Ping sockets required sending packets using Write in Transport layer, Resolve would return ErrWouldBlock and Write would return ErrNoLinkAddress. Meanwhile startAddressResolution would run in background. Further calls to Write using same address would also return ErrNoLinkAddress until resolution has been completed successfully. Since Write is not allowed to block and System Calls need to be interruptible in System Call layer, the caller to Write is responsible for blocking upon return of ErrWouldBlock. Now, when startAddressResolution is called a notification channel for the completion of the address resolution is returned. The channel will traverse up to the calling function of Write as well as ErrNoLinkAddress. Once address resolution is complete (success or not) the channel is closed. The caller would call Write again to send packets and check if address resolution was compeleted successfully or not. Fixes google/gvisor#5 Change-Id: Idafaf31982bee1915ca084da39ae7bd468cebd93 PiperOrigin-RevId: 214962200 --- pkg/dhcp/client.go | 17 +++++++++++++++-- pkg/dhcp/server.go | 15 ++++++++++++++- 2 files changed, 29 insertions(+), 3 deletions(-) (limited to 'pkg/dhcp') diff --git a/pkg/dhcp/client.go b/pkg/dhcp/client.go index cf8472c5f..92c634a14 100644 --- a/pkg/dhcp/client.go +++ b/pkg/dhcp/client.go @@ -195,10 +195,23 @@ func (c *Client) Request(ctx context.Context, requestedAddr tcpip.Address) (cfg wopts := tcpip.WriteOptions{ To: serverAddr, } - if _, err := ep.Write(tcpip.SlicePayload(h), wopts); err != nil { + var resCh <-chan struct{} + if _, resCh, err = ep.Write(tcpip.SlicePayload(h), wopts); err != nil && resCh == nil { return Config{}, fmt.Errorf("dhcp discovery write: %v", err) } + if resCh != nil { + select { + case <-resCh: + case <-ctx.Done(): + return Config{}, fmt.Errorf("dhcp client address resolution: %v", tcpip.ErrAborted) + } + + if _, _, err := ep.Write(tcpip.SlicePayload(h), wopts); err != nil { + return Config{}, fmt.Errorf("dhcp discovery write: %v", err) + } + } + we, ch := waiter.NewChannelEntry(nil) wq.EventRegister(&we, waiter.EventIn) defer wq.EventUnregister(&we) @@ -289,7 +302,7 @@ func (c *Client) Request(ctx context.Context, requestedAddr tcpip.Address) (cfg reqOpts = append(reqOpts, option{optClientID, clientID}) } h.setOptions(reqOpts) - if _, err := ep.Write(tcpip.SlicePayload(h), wopts); err != nil { + if _, _, err := ep.Write(tcpip.SlicePayload(h), wopts); err != nil { return Config{}, fmt.Errorf("dhcp discovery write: %v", err) } diff --git a/pkg/dhcp/server.go b/pkg/dhcp/server.go index 003e272b2..26700bdbc 100644 --- a/pkg/dhcp/server.go +++ b/pkg/dhcp/server.go @@ -95,9 +95,22 @@ func (c *epConn) Read() (buffer.View, tcpip.FullAddress, error) { } func (c *epConn) Write(b []byte, addr *tcpip.FullAddress) error { - if _, err := c.ep.Write(tcpip.SlicePayload(b), tcpip.WriteOptions{To: addr}); err != nil { + _, resCh, err := c.ep.Write(tcpip.SlicePayload(b), tcpip.WriteOptions{To: addr}) + if err != nil && resCh == nil { return fmt.Errorf("write: %v", err) } + + if resCh != nil { + select { + case <-resCh: + case <-c.ctx.Done(): + return fmt.Errorf("dhcp server address resolution: %v", tcpip.ErrAborted) + } + + if _, _, err := c.ep.Write(tcpip.SlicePayload(b), tcpip.WriteOptions{To: addr}); err != nil { + return fmt.Errorf("write: %v", err) + } + } return nil } -- cgit v1.2.3