Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/contributors.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,6 @@ users:
Chennamma-Hotkar:
name: Chennamma Hotkar
email: channuhotkar@gmail.com
alimx07:
name: Ali Mohamed
email: amx746@gmail.com
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ URUNC_SRC += $(wildcard $(CURDIR)/pkg/unikontainers/unikernels/*.go)
URUNC_SRC += $(wildcard $(CURDIR)/pkg/unikontainers/types/*.go)
URUNC_SRC += $(wildcard $(CURDIR)/pkg/unikontainers/initrd/*.go)
URUNC_SRC += $(wildcard $(CURDIR)/pkg/network/*.go)
URUNC_SRC += $(wildcard $(CURDIR)/pkg/network/localhost/*.go)
SHIM_SRC := $(wildcard $(CURDIR)/cmd/containerd-shim-urunc-v2/*.go)
SHIM_SRC += $(wildcard $(CURDIR)/pkg/containerd-shim/*.go)
SHIM_SRC += $(wildcard $(CURDIR)/pkg/containerd-shim/containerd/*.go)
Expand Down
5 changes: 3 additions & 2 deletions internal/constants/network_constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const (
StaticNetworkTapIP = "172.16.1.1"
StaticNetworkUnikernelIP = "172.16.1.2"
// TODO: Experiment with DynamicNetworkTapIP starting from 172.16.X.1
DynamicNetworkTapIP = "172.16.X.2"
QueueProxyRedirectIP = "172.16.1.2"
DynamicNetworkTapIP = "172.16.X.2"
QueueProxyRedirectIP = "172.16.1.2"
LocalhostDNSResolverIP = "192.168.100.100"
)
109 changes: 109 additions & 0 deletions pkg/network/localhost/docker.go

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can merge this file with "loclahost.go" or its new name.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about something like local_dns.go or loDns.go as shorter one ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, both are better than localhost.go.

Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// Copyright (c) 2023-2026, Nubificus LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package localhost

import (
"errors"
"fmt"
"net"
"os/exec"
"strings"
"syscall"

"github.com/vishvananda/netlink"
)

func dockerRules(f *Forwarder) error {

tcpPort, udpPort, err := dockerDNSPorts(f.LoIP)
if err != nil {
return err
}
lhlog.Debugf("Docker DNS resolver: tcp/%s udp/%s", tcpPort, udpPort)

if err := dnat(f.VirtIP, "udp", net.JoinHostPort(f.LoIP.String(), udpPort)); err != nil {
return err
}
if err := dnat(f.VirtIP, "tcp", net.JoinHostPort(f.LoIP.String(), tcpPort)); err != nil {
return err
}
lhlog.Debug("Applied Docker DNAT rules")

return nil
}

func dockerDNSPorts(loIP net.IP) (string, string, error) {
var tcpPort, udpPort string

// syscall.AF_INET : IPv4
tcp, err := netlink.SocketDiagTCPInfo(syscall.AF_INET)
if err != nil {
return "", "", fmt.Errorf("could not list TCP sockets in namespace: %w", err)
}
for _, s := range tcp {
if s.InetDiagMsg.ID.Source.String() == loIP.String() {
tcpPort = fmt.Sprintf("%d", s.InetDiagMsg.ID.SourcePort)
break
}
}
udp, err := netlink.SocketDiagUDPInfo(syscall.AF_INET)
if err != nil {
return "", "", fmt.Errorf("could not list UDP sockets in namespace: %w", err)
}
for _, s := range udp {
if s.InetDiagMsg.ID.Source.String() == loIP.String() {
udpPort = fmt.Sprintf("%d", s.InetDiagMsg.ID.SourcePort)
break
}
}
if tcpPort == "" || udpPort == "" {
return "", "", fmt.Errorf("could not find docker embedded resolver ports for %s (tcp=%q udp=%q)", loIP, tcpPort, udpPort)
}
return tcpPort, udpPort, nil
}

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, this doesn't affect the performance much. It's basically the same (plus a few microseconds).

I still think we can optimize this, but I would rather move forward, finalize support for the other unikernels, and come back to this later.

// ClearRules removes DNAT rules dockerRules could have added.
func clearRules() error {

// This will be run from kill() so no memory state could be used.
// we list all IPtable rules from scratch.

// iptables-save output example:
// -A PREROUTING -d 192.168.100.100/32 -i lo -p udp -j DNAT --to-destination 127.0.0.11:60269
ipt, err := exec.LookPath("iptables-save")
if err != nil {
return err
}
out, err := exec.Command(ipt, "-t", "nat").Output() //nolint:gosec
if err != nil {
return fmt.Errorf("iptables-save failed: %w", err)
}

var retErr error
for line := range strings.SplitSeq(string(out), "\n") {
fields := strings.Fields(line)
if len(fields) < 2 || fields[0] != "-A" || fields[1] != "PREROUTING" {
continue
}
if !strings.Contains(line, "-i lo") || !strings.Contains(line, "-j DNAT") {
continue
}
args := append([]string{"-t", "nat", "-D"}, fields[1:]...)
if err := ipTablesExec(args); err != nil {
retErr = errors.Join(retErr, err)
}
}
return retErr
}
Loading