-
Notifications
You must be signed in to change notification settings - Fork 879
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
Support SCTP port mapping #1825
Conversation
cc @aboch @mavenugo @sanimej @fcrisciani PTAL |
also cc @aaronlehmann (moby/swarmkit#2298) |
@aboch @mavenugo @sanimej @fcrisciani @aaronlehmann Any comments? |
@ishidawataru Thanks. Does SCTP have any dependencies on kernel version ? What distro/kernel version has this been tested with ? |
@sanimej Thanks for your comment. Linux has built-in support for the SCTP since the 2.6 kernel, so I believe there is no dependency issue for docker users. |
@sanimej ping |
size := m.Size() | ||
data = make([]byte, size) | ||
n, err := m.MarshalTo(data) | ||
dAtA = make([]byte, size) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
was this a deliberate change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh, never mind this is generated code, my eye just fell on it 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@thaJeztah Thanks for your review! Do you have any other comments?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not right now; it's not really my expertise, but I was checking up on the status of this PR (as it's a requirement for your other PR's)
I'll try getting it reviewed, but the networking team is quite busy at the moment, so doing my best 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@thaJeztah Right, this needs to get merged first for the SCTP port mapping feature.
Thanks a lot for your help! I totally understand the networking team is quite busy 😅
@aboch @mavenugo @sanimej @fcrisciani @aaronlehmann @thaJeztah Any chance you can take a look and review this PR? |
ping @mavenugo (who I think was going to look into this PR) |
@ishidawataru @thaJeztah yes. I will take a look at it as soon as other higher priority activities are handled. |
@mavenugo ping 😃 |
Can we move this forward? ping libnetwork maintainers: @aboch @LK4D4 @icecrime @mavenugo @sanimej @chunchun @fcrisciani cc those who made comments in moby/moby#9689 @rickhofstede @scottstamp @duglin @thaJeztah @razaborg Anyone please take a look? 😄 |
any chance of this getting merged in the near future? |
Any update on this? :) |
@aboch @mavenugo @sanimej @fcrisciani @aaronlehmann What is the current status of this feature ? |
ping @ddebroy PTAL |
fff72eb
to
1fced67
Compare
rebased |
Codecov Report
@@ Coverage Diff @@
## master #1825 +/- ##
=========================================
Coverage ? 40.47%
=========================================
Files ? 139
Lines ? 22314
Branches ? 0
=========================================
Hits ? 9032
Misses ? 11960
Partials ? 1322
Continue to review full report at Codecov.
|
to.Close() | ||
wg.Done() | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't appear that 'dir' is used here. Should it be removed and the invocations below adjusted?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, thought the placement would show more context. I mean the "dir" parameter of the broker function 7 lines up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left some comments.
Also did not finish yet the review of the vendored files
return nil, err | ||
} | ||
// If the port in frontendAddr was 0 then ListenSCTP will have a picked | ||
// a port to listen on, hence the call to Addr to get that actual port: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do you mean that if the port is not specified is ephemeral?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes. the comment is taken from tcp_proxy.go
.
func (proxy *SCTPProxy) clientLoop(client *sctp.SCTPConn, quit chan bool) { | ||
backend, err := sctp.DialSCTP("sctp", nil, proxy.backendAddr) | ||
if err != nil { | ||
log.Printf("Can't forward traffic to backend sctp/%v: %s\n", proxy.backendAddr, err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please change this to use logrus package.
es: logrus.WithError(err).Errorf("[...]")
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently, cmd/proxy
package does not use logrus.
Not sure why, probably for reducing dependency.
for { | ||
client, err := proxy.listener.Accept() | ||
if err != nil { | ||
log.Printf("Stopping proxy on sctp/%v for sctp/%v (%s)", proxy.frontendAddr, proxy.backendAddr, err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here use logrus
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As above, cmd/proxy
looks intentionally avoiding using logrus.
cmd/proxy/sctp_proxy.go
Outdated
backendC := sctp.NewSCTPSndRcvInfoWrappedConn(backend) | ||
|
||
var wg sync.WaitGroup | ||
var broker = func(to, from net.Conn, dir bool) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dir is unused, please remove it
portmapper/mapper.go
Outdated
} | ||
|
||
if useProxy { | ||
m.userlandProxy, err = newProxy(proto, hostIP, allocatedHostPort, container.(*sctp.SCTPAddr).IP[0], container.(*sctp.SCTPAddr).Port, pm.proxyPath) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
before accessing the first element should you check the len?
portmapper/proxy.go
Outdated
addr := &sctp.SCTPAddr{IP: []net.IP{hostIP}, Port: hostPort} | ||
return &dummyProxy{addr: addr} | ||
default: | ||
panic(fmt.Errorf("Unknown addr type: %s", proto)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also here better to use logrus
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also wonder if a panic is correct here?
return buf.Bytes() | ||
} | ||
|
||
func htons(h uint16) uint16 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do you need to redefine this? why not using the standard: binary.BigEndian.PutUint16
? Network order is bigendian
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I chose to let binary.Write()
to serialize each field of golang structures, we need htons()
which returns big endian format of uint16
to put to the structures.
If we serialize each field of the structure by hand, we can use binary.BigEndian.PutUint16()
as you suggest.
sndRcvInfoSize = unsafe.Sizeof(info) | ||
} | ||
|
||
func toBuf(v interface{}) []byte { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
following the comment below, if you make sure that the network format is respected, this function will have to simply read bigEndian format and the machine itself will take care of storing it with the proper endianess allowing you to delete all the dependency with the endianess discovery and data manipulation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
toBuf()
is not used for endian handling but for serializing golang structure to []byte
.
I chose to use binary.Write()
instead of using unsafe
or serializing each field by hand using PutUint8()
etc.
} | ||
|
||
func (a *SCTPAddr) ToRawSockAddrBuf() []byte { | ||
buf := []byte{} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's better here to have a defined length, not doing so will create a lot of following allocation for every append.
From the code looks like the worst case the size will be len(a.IP) * 16Bytes (ipv6 len). If you think that the IPv6 case is not so common, maybe you can allocate at least the space for the IPv4 so that the append to them won't require any extra allocation during the append
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We (@ishidawataru and me) believe this overhead is negligible, as a.IP
should not contain so many entries.
So we'd like to keep the current code for simplicity.
|
||
for n, i := range a.IP { | ||
if a.IP[n].To4() != nil { | ||
b.WriteRune('/') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
from the documentation of net.Addr looks like the format that they are suggesting in the example is like: (for example, "192.0.2.1:25", "[2001:db8::1]:80")
this does not seem to match the suggested format
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://golang.org/pkg/net/#Addr
The two methods Network and String conventionally return strings that can be passed as the arguments to Dial, but the exact form and meaning of the strings is up to the implementation.
I think this SCTP-specific form is ok.
@ishidawataru WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe I missed something, but I think that this looks like the same form as suggested by net.Addr. The difference is that this is a list of addresses instead of a single address and so they get separated by '/'s. Until I saw the last line of the function I didn't realize however, that the leading '/' that gets put in the buffer gets omitted from the final string.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
opened ishidawataru/sctp#10 for improving readability
return nil, fmt.Errorf("invalid input: %s", addrs) | ||
} | ||
ipaddrs := make([]net.IP, 0, len(elems)) | ||
for _, e := range elems[:len(elems)-1] { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't this start from 1? from above looks like the string starts with /
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See above. The starting '/' built in the string gets trimmed.
|
||
func (c *SCTPConn) SubscribeEvents(flags int) error { | ||
var d, a, ad, sf, p, sh, pa, ada, au, se uint8 | ||
if flags&SCTP_EVENT_DATA_IO > 0 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what if you remove all these if and you merge everything in the init down like:
param := EventSubscribe{
DataIO: uint8(flags&SCTP_EVENT_DATA_IO > 0),
Association: uint8(flags&SCTP_EVENT_ASSOCIATION > 0),
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Go doesn't allow conversion from bool to int by cast. From what I can see on the mailing lists it was requested around go 1.5, but declined. Pity...
@@ -48,6 +50,9 @@ func parseHostContainerAddrs() (host net.Addr, container net.Addr) { | |||
case "udp": | |||
host = &net.UDPAddr{IP: net.ParseIP(*hostIP), Port: *hostPort} | |||
container = &net.UDPAddr{IP: net.ParseIP(*containerIP), Port: *containerPort} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: should probably update the comment at the start of the function to include SCTP.
cmd/proxy/network_proxy_test.go
Outdated
if err != nil { | ||
t.Fatal(err) | ||
} | ||
server = &TCPEchoServer{listener: listener, testCtx: t} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Should this structure be renamed now? It's no longer just a "TCP" echo server. Maybe "StreamEchoServer"...
|
||
for n, i := range a.IP { | ||
if a.IP[n].To4() != nil { | ||
b.WriteRune('/') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe I missed something, but I think that this looks like the same form as suggested by net.Addr. The difference is that this is a list of addresses instead of a single address and so they get separated by '/'s. Until I saw the last line of the function I didn't realize however, that the leading '/' that gets put in the buffer gets omitted from the final string.
return nil, fmt.Errorf("invalid input: %s", addrs) | ||
} | ||
ipaddrs := make([]net.IP, 0, len(elems)) | ||
for _, e := range elems[:len(elems)-1] { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See above. The starting '/' built in the string gets trimmed.
|
||
func (c *SCTPConn) SubscribeEvents(flags int) error { | ||
var d, a, ad, sf, p, sh, pa, ada, au, se uint8 | ||
if flags&SCTP_EVENT_DATA_IO > 0 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Go doesn't allow conversion from bool to int by cast. From what I can see on the mailing lists it was requested around go 1.5, but declined. Pity...
} | ||
|
||
func resolveFromRawAddr(ptr unsafe.Pointer, n int) (*SCTPAddr, error) { | ||
addr := &SCTPAddr{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not checking the boundary of the underlying buffer makes me a bit nervous on principle, but I suppose we generally trust the kernel.
"net" | ||
) | ||
|
||
var ErrUnsupported = errors.New("operation unsupported") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems like a perfectly reasonable discipline for building cleanly on other platforms in general. But from the docker/libnetwork perspective, I'm concerned about two things:
- This error message is way too generic -- if libnetwork just returns this and the caller prints the string there's no context to say what isn't supported. At the very least perhaps the string should be changed to "SCTP not supported on this platform" or some such.
- This file is fairly deep in the call stack to be flagging lack of support as far as libnetwork goes. Ideally either libnetwork or moby itself should flag early that an SCTP operation isn't supported by "this version" on "this platform". It kind of seems wrong to, for example, try to create an SCTP proxy thinking this is perfectly valid up until we attempt to bind a listening socket. Maybe I'm just being overly cautious on this one though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
opened ishidawataru/sctp#11
Signed-off-by: Wataru Ishida <ishida.wataru@lab.ntt.co.jp> Signed-off-by: Akihiro Suda <suda.akihiro@lab.ntt.co.jp>
Thank you a lot for reviewing this PR. Addressed the comments. PTAL. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They addressed all of my concerns completely: LGTM.
(note: sorry for the confusion, but the "ghost" comments on this PR were mine. Switched accounts mid-review.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Thanks for merging! |
@AkihiroSuda thanks for contributing and addressing the comments |
updated moby-side PR moby/moby#33922 |
@mavenugo I am new to docker support for SCTP apps. Can you please point me to some documentation on how docker supports SCTP apps? |
@verizonold see moby/moby#9689 (comment) for links to all related PR's (including some docs) |
I am very much looking for the SCTP support on docker. I am following this thread from long. can anybody give info on when it will be available with docker installation or if I clone this source code how can it be used in my system so that I can test SCTP support |
@Vishesh-GIT SCTP support is added to the latest Docker release 18.03.0-ce, just update and use it. |
so is this for port mapping? we can now map tcp/udp/sctp ports? Can you
please provide an example?
…On Fri, Mar 23, 2018 at 6:11 AM, Peter-eid ***@***.***> wrote:
@Vishesh-GIT <https://github.com/vishesh-git> SCTP support is added to
the latest Docker release 18.03.0-ce
<https://docs.docker.com/release-notes/docker-ce/#stable-releases>, just
update and use it.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#1825 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AjVVDY4HRgD914L07lYCTTWcJgWE7xc4ks5thPRxgaJpZM4OI5nn>
.
|
Introducing support for SCTP(Stream Control Transmission Protocol) port mapping.
SCTP support is necessary to run S1AP and Diameter applications in docker containers.
Related issue : moby/moby#9689