Skip to content

Commit

Permalink
Add --disable-bind
Browse files Browse the repository at this point in the history
Workaround for issue 65.

This flag disables the acceleration for `bind` syscalls,
as the current hook is not robust enough for `bind` with complicated setup.

Anyway, the performance of `bind` is not really problematic so far in the plain Rootless Containers.
So we can just keep enabling bypass4netns for `connect` and relevant syscalls, and call it for a day.

See the logs of RootlessKit CI:
https://github.com/rootless-containers/rootlesskit/actions/runs/8558692577/job/23453781376
- Benchmark: TCP Ports (network driver=slirp4netns, port driver=builtin): 34.8 Gbps, 34.7 Gbps
- Benchmark: TCP Ports (network driver=pasta, port driver=implicit):      39.3 Gbps, 39.2 Gbps
- Benchmark: UDP Ports (network driver=slirp4netns, port driver=builtin): 25.1 Gbps, 17.2 Gbps
- Benchmark: UDP Ports (network driver=pasta, port driver=implicit):      37.9 Gbps, 13.2 Gbps

Signed-off-by: Akihiro Suda <[email protected]>
  • Loading branch information
AkihiroSuda committed Apr 5, 2024
1 parent e8489c0 commit 568e202
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 13 deletions.
3 changes: 2 additions & 1 deletion cmd/bypass4netns/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ func main() {
handleC2cEnable := flag.Bool("handle-c2c-connections", false, "Handle connections between containers")
tracerEnable := flag.Bool("tracer", false, "Enable connection tracer")
multinodeEnable := flag.Bool("multinode", false, "Enable multinode communication")
disableBind := flag.Bool("disable-bind", false, "Disable bypassing bind")

// Parse arguments
flag.Parse()
Expand Down Expand Up @@ -154,7 +155,7 @@ func main() {

logrus.Infof("SocketPath: %s", socketFile)

handler := bypass4netns.NewHandler(socketFile, comSocketFile, strings.Replace(logFilePath, ".log", "-tracer.log", -1))
handler := bypass4netns.NewHandler(socketFile, comSocketFile, strings.Replace(logFilePath, ".log", "-tracer.log", -1), *disableBind)

subnets := []net.IPNet{}
var subnetsAuto bool
Expand Down
1 change: 1 addition & 0 deletions pkg/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type BypassSpec struct {
LogFilePath string `json:"logFilePath"`
PortMapping []PortSpec `json:"portMapping"`
IgnoreSubnets []string `json:"ignoreSubnets"` // CIDR or "auto"
DisableBind bool `json:"disableBind"`
}

type PortSpec struct {
Expand Down
10 changes: 8 additions & 2 deletions pkg/bypass4netns/bypass4netns.go
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,7 @@ func (h *notifHandler) registerSocket(pid int, sockfd int, syscallName string) (
defer syscall.Close(sockFdHost)

sockDomain, sockType, sockProtocol, err := getSocketArgs(sockFdHost)
sock = newSocketStatus(pid, sockfd, sockDomain, sockType, sockProtocol)
sock = newSocketStatus(pid, sockfd, sockDomain, sockType, sockProtocol, h.disableBind)
if err != nil {
// non-socket fd is not bypassable
sock.state = NotBypassable
Expand Down Expand Up @@ -629,17 +629,20 @@ type Handler struct {

// key is child port
forwardingPorts map[int]ForwardPortMapping

disableBind bool
}

// NewHandler creates new seccomp notif handler
func NewHandler(socketPath, comSocketPath, tracerAgentLogPath string) *Handler {
func NewHandler(socketPath, comSocketPath, tracerAgentLogPath string, disableBind bool) *Handler {
handler := Handler{
socketPath: socketPath,
comSocketPath: comSocketPath,
tracerAgentLogPath: tracerAgentLogPath,
ignoredSubnets: []net.IPNet{},
forwardingPorts: map[int]ForwardPortMapping{},
readyFd: -1,
disableBind: disableBind,
}

return &handler
Expand Down Expand Up @@ -711,6 +714,8 @@ type notifHandler struct {

// cache pidfd to reduce latency. key is pid.
pidInfos map[int]pidInfo

disableBind bool
}

type containerInterface struct {
Expand Down Expand Up @@ -740,6 +745,7 @@ func (h *Handler) newNotifHandler(fd uintptr, state *specs.ContainerProcessState
processes: map[int]*processStatus{},
memfds: map[int]int{},
pidInfos: map[int]pidInfo{},
disableBind: h.disableBind,
}
notifHandler.nonBypassable = nonbypassable.New(h.ignoredSubnets)
notifHandler.nonBypassableAutoUpdate = h.ignoredSubnetsAutoUpdate
Expand Down
29 changes: 19 additions & 10 deletions pkg/bypass4netns/socket.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,11 @@ type socketStatus struct {
socketOptions []socketOption
fcntlOptions []fcntlOption

logger *logrus.Entry
logger *logrus.Entry
disableBind bool
}

func newSocketStatus(pid int, sockfd int, sockDomain, sockType, sockProto int) *socketStatus {
func newSocketStatus(pid int, sockfd int, sockDomain, sockType, sockProto int, disableBind bool) *socketStatus {
return &socketStatus{
state: NotBypassed,
pid: pid,
Expand All @@ -95,6 +96,7 @@ func newSocketStatus(pid int, sockfd int, sockDomain, sockType, sockProto int) *
socketOptions: []socketOption{},
fcntlOptions: []fcntlOption{},
logger: logrus.WithFields(logrus.Fields{"pid": pid, "sockfd": sockfd}),
disableBind: disableBind,
}
}

Expand Down Expand Up @@ -166,14 +168,18 @@ func (ss *socketStatus) handleSysConnect(handler *notifHandler, ctx *context) {
connectToLoopback := false
connectToInterface := false
connectToOtherBypassedContainer := false
fwdPort, ok := handler.forwardingPorts[int(destAddr.Port)]
if ok {
if destAddr.IP.IsLoopback() {
ss.logger.Infof("destination address %v is loopback and bypassed", destAddr)
connectToLoopback = true
} else if contIf, ok := handler.containerInterfaces[destAddr.String()]; ok && contIf.containerID == handler.state.State.ID {
ss.logger.Infof("destination address %v is interface's address and bypassed", destAddr)
connectToInterface = true
var fwdPort ForwardPortMapping
if !ss.disableBind {
var ok bool
fwdPort, ok = handler.forwardingPorts[int(destAddr.Port)]
if ok {
if destAddr.IP.IsLoopback() {
ss.logger.Infof("destination address %v is loopback and bypassed", destAddr)
connectToLoopback = true
} else if contIf, ok := handler.containerInterfaces[destAddr.String()]; ok && contIf.containerID == handler.state.State.ID {
ss.logger.Infof("destination address %v is interface's address and bypassed", destAddr)
connectToInterface = true
}
}
}

Expand Down Expand Up @@ -301,6 +307,9 @@ func (ss *socketStatus) handleSysConnect(handler *notifHandler, ctx *context) {
}

func (ss *socketStatus) handleSysBind(pid int, handler *notifHandler, ctx *context) {
if ss.disableBind {
return
}
sa, err := handler.readSockaddrFromProcess(pid, ctx.req.Data.Args[1], ctx.req.Data.Args[2])
if err != nil {
ss.logger.Errorf("failed to read sockaddr from process: %q", err)
Expand Down
4 changes: 4 additions & 0 deletions pkg/bypass4netnsd/bypass4netnsd.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ func (d *Driver) StartBypass(spec *api.BypassSpec) (*api.BypassStatus, error) {
b4nnArgs = append(b4nnArgs, fmt.Sprintf("--ignore=%s", subnet))
}

if spec.DisableBind {
b4nnArgs = append(b4nnArgs, "--disable-bind")
}

b4nnArgs = append(b4nnArgs, fmt.Sprintf("--com-socket=%s", d.ComSocketPath))
if d.HandleC2CEnable {
b4nnArgs = append(b4nnArgs, "--handle-c2c-connections")
Expand Down

0 comments on commit 568e202

Please sign in to comment.