-
Notifications
You must be signed in to change notification settings - Fork 680
[Bugfix] Check if port is used in publish flag [duplicate of #2190] #4097
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
[Bugfix] Check if port is used in publish flag [duplicate of #2190] #4097
Conversation
aaeb6ce
to
af654a8
Compare
4e10732
to
65feab1
Compare
65feab1
to
002c0d4
Compare
The current implementation breaks in rootless mode which is resulting in the test failures. I am guessing this is mainly due to how Rootlesskit uses slirp4netns to create a separate net ns and possibly the port allocation information is no longer visible in /proc/net/*. We can either implement some mechanism to track the rootless state or may be add a generic port store to track all port usage. |
Rootless > 2.0 starts with a detached network namespace by default. You need to |
pkg/portutil/port_allocate_linux.go
Outdated
@@ -42,24 +42,56 @@ func filter(ss []procnet.NetworkDetail, filterFunc func(detail procnet.NetworkDe | |||
} | |||
|
|||
func portAllocate(protocol string, ip string, count uint64) (uint64, uint64, error) { | |||
netprocData, err := procnet.ReadStatsFileData(protocol) | |||
usedPort, err := getUsedPorts(ip, protocol) |
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.
usedPort, err := getUsedPorts(ip, protocol) | |
usedPorts, err := getUsedPorts(ip, protocol) |
pkg/portutil/port_allocate_linux.go
Outdated
if err != nil { | ||
return 0, 0, err | ||
} | ||
netprocItems := procnet.Parse(netprocData) | ||
|
||
start := uint64(allocateStart) |
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.
to make things simpler please declare allocateStart
and allocateEnd
with uint64
type
ping @swagatbora90 |
15c910f
to
1f3a23f
Compare
Hi @fahedouch, sorry for the late response as I was on an extended leave. I have updated the code now to use However, I found that the root cause of the rootless test failure was something different. When running in rootless mode, once a container is created with port map, we see two entries in /proc/net/tcp. Take for example the a port map of 8080 -> 80 appear as following
Line 0: 00000000000000000000000000000000:1F90 - A socket listening on port 8080 (1F90 hex) on The second connection does the network proxy to send incoming request to the container. Since in rootful mode, the runtime can directly access the host network stack, it only needs to create a single socket that forwards traffic to the container. The interesting bit here is that when we stop/remove the rootless container, I see that the 1st socket connection gets removed immediately, however the second connection moves to TIME_WAIT state with uid changing from 1000 to 0. I am not sure why but looks like standard tcp behavior. This eventually gets removed, but does take 10-20 seconds to clear.
This causes new container start/run to fail as we continue to see :8080(1F90) in the tcp stats though the state is clearly marked as waiting to be closed. To resolve the issue, I am now checking for both the ports and their state and specifically ignoring ports in TIME_WAIT and CLOSE_WAIT state as these ports are no longer in use and available to be allocated. |
f389807
to
c1a49d2
Compare
nerdctl gomodjail tests are consistently failing with errors such as
Seems unrelated to the current changes. Is this a known issue @apostasie @fahedouch ? |
My knowledge of slirp4netns is very limited, but I think it is the culprit. @AkihiroSuda, can you confirm that it is the one opening the socket on the loopback address |
This line should have Line 31 in b8c4b3d
|
The default port driver is still RootlessKit's |
ok ^^
WDYT about this. I think it is the responsibility of the |
I was thinking the same, but when I looked into the current implementation found that nerdctl is using rootlesskit portmanager to handle port adds/deletes. The proxy connection creation and deletion is handled in rootlesskit, so nerdctl does not have much control over it. |
c1a49d2
to
d49a66c
Compare
There is still some flakiness in some test. Related #4143
It appears that this test failed and perhaps there was some issue with cleanup. As a result a lot of other tests that relies on host port 8080 started failing with port already allocated errors. This does mean that with by relying on a single host port in all our test (in this case port 8080), there is a higher chance of unrelated tests failing. We can randomize the port used in the test so that it is not always 8080, but would prefer to keep it in a separate PR |
pkg/portutil/portutil.go
Outdated
@@ -59,6 +59,7 @@ func ParseFlagP(s string) ([]cni.PortMapping, error) { | |||
case 2: | |||
proto = strings.ToLower(splitBySlash[1]) | |||
switch proto { | |||
// sctp is not a supported protocol |
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.
The comment suggests SCTP
isn't supported, but it is present in the case line 63
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.
removed
Signed-off-by: Swagat Bora <[email protected]> Co-authored-by: Vishwas Siravara <[email protected]>
d49a66c
to
04f836d
Compare
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.
Thanks
@@ -27,6 +27,7 @@ import ( | |||
type NetworkDetail struct { | |||
LocalIP net.IP | |||
LocalPort uint64 | |||
State int | |||
} | |||
|
|||
func Parse(data []string) (results []NetworkDetail) { |
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.
Can we have unit tests?
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.
I can add some unit test as a follow up.
tcName := fmt.Sprintf("%+v", tc) | ||
t.Run(tcName, func(t *testing.T) { | ||
if strings.Contains(tc.containerPort, "sctp") && rootlessutil.IsRootless() { | ||
t.Skip("sctp is not supported in rootless mode") |
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 we already support sctp for rootful?
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.
Thanks
This PR continues the work from #2190 (originally by @vsiravar) which checks for used ports while allocating host port in -p/--publish. The original PR is already approved and was just waiting for a rebase form the author. Most of the comments have already been addressed.
Addressing port cleanup on stop:
The original PR had some open discussion around handling port cleanups on container stop
This is now already being addressed with this PR #2839 as network cleanup is part of both container stop and kill
Verified the fix:
Fixes: #2179
cc @fahedouch @vsiravar