Skip to content
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

proposal: net: Allow a socket to be created in a Linux network namespace #62581

Closed
cwmos opened this issue Sep 11, 2023 · 6 comments
Closed

proposal: net: Allow a socket to be created in a Linux network namespace #62581

cwmos opened this issue Sep 11, 2023 · 6 comments
Labels
Milestone

Comments

@cwmos
Copy link

cwmos commented Sep 11, 2023

In Linux, a socket can be created in a network namespace as follows:

  • Save current namespace for the current thread
  • Set current namespace for the current thread to the namespace to create the socket in
  • Create the socket using the socket(2) call
  • Restore the current namespace for the thread

There seems to be no good way to do this with the Go runtime:

  • The Dialer.Control and ListenConfig.Control seem like good candidates. Unfortunately, these only allow you to tweak the socket after it has been created.
  • An alternative is to create your own socket, connect it, and then use os.NewFile and net.FileConn to create a net.Conn. Unfortunately, if you do this, you have to connect the socket yourself. You cannot use Dial or Listen functions from the net package.

It has been proposed to set the network namespace before calling Dial #46932, #44922. However, that seems like a somewhat fragile approach and it does not support all use cases as also pointed out in these issues.

It is not immediately clear to me what a good way to implement this feature would be. Perhaps syscall.RawConn could have a function to set the file descriptor?

@cwmos cwmos added the Proposal label Sep 11, 2023
@gopherbot gopherbot added this to the Proposal milestone Sep 11, 2023
@ianlancetaylor
Copy link
Contributor

Can you expand on what use cases are not handled by setting the namespace yourself? It's not obvious to me from glancing at the issues you mention. Thanks.

I agree that creating a new socket in a different namespace is not simple, but it is also something that very few programs need to do. As long as it is possible to do this, it seems to me that this is a better fit for an external third party package than for the standard library. https://go.dev/doc/faq#x_in_std

@thediveo
Copy link

thediveo commented Sep 12, 2023

Namespace discoverer here: it's actually much more involved, not least considering proper error handling and the multiple forms that namespace references might take on before they turn into some fd. And don't get us started on talking about the correct lifecycle handling of open fds...

I can only second @ianlancetaylor that this isn't something for the std lib, especially as it is very, very Linux-specific.

Also, why just supporting network namespaces and dial, and not the other namespace types?

I basically know of these two 3rd party libs that act as the namespace-switching building block to wrap the dial part:

@cwmos
Copy link
Author

cwmos commented Sep 13, 2023

The use case is to dial or listen in another network namespace by using the standard library and hooks provided by the standard library.

Is this supported today? Sort of. You can do the following:

  • Call runtime.LockOSThread
  • Set the namespace of the current thread
  • Invoke a dial or listen in the standard library and wait for them to return
  • Revert the namespace of the current thread
  • Call runtime.UnlockOSThread

You can further optimize a bit on this: You can install a Control object in the dialer/listener. As soon as it is indicated to the Control object that a socket has been created, you can go ahead and revert the namespace and call runtime.UnlockOSThread.

I see two problems with it, though:

  1. It does not support the happy eyeballs algorithm when dialing
  2. It kind of just happens to work due to the way the standard library happens to be implemented. For example, that the dialer and listener happen to not create new go routines.

Is this good enough? Maybe, but I do not think it is ideal.

I do agree with @thediveo that the standard library should not support Linux namespaces directly. It should provide hooks so that you can support them reliably with mechanisms like the one outlined above.

@thediveo
Copy link

@cwmos which hooks (extension points) would you expect?

@cwmos
Copy link
Author

cwmos commented Sep 29, 2023

I guess I do not have any super good suggestions for how to change the API. So I will close this issue.

@cwmos cwmos closed this as completed Sep 29, 2023
@leonshaw
Copy link

@cwmos Have a look at #54314 maybe.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: Incoming
Development

No branches or pull requests

5 participants