Skip to content

Commit

Permalink
rootlessnetns: cache dns and guest addr options
Browse files Browse the repository at this point in the history
When using the rootless netns (bridge mode) so far podman ignored the
proper pasta or slirp4netns dns sever for networks without aardvark-dns.
This is not good. We should try to use them by default, and with the new
MapGuestAddr option we need to use that as well for
host.containers.internal. The problem is that becuase we only know what
options we uses when we started the process later container starts from
a new podman process do not really see these options if we just cache
the result in memory. So in order to make all following podman process
aware we serialize this info struct as json and later processes read it
when needed.

It also means we do not have to lookup the netns ip evey time so I
removed that code.

Signed-off-by: Paul Holzinger <pholzing@redhat.com>
  • Loading branch information
Luap99 committed Aug 26, 2024
1 parent 74444aa commit 3081b0d
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 23 deletions.
82 changes: 59 additions & 23 deletions libnetwork/internal/rootlessnetns/netns_linux.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package rootlessnetns

import (
"encoding/json"
"errors"
"fmt"
"io/fs"
Expand Down Expand Up @@ -34,6 +35,9 @@ const (
// refCountFile file name for the ref count file
refCountFile = "ref-count"

// infoCacheFile file name for the cache file used to store the rootless netns info
infoCacheFile = "info.json"

// rootlessNetNsConnPidFile is the name of the rootless netns slirp4netns/pasta pid file
rootlessNetNsConnPidFile = "rootless-netns-conn.pid"

Expand All @@ -54,11 +58,9 @@ type Netns struct {
// config contains containers.conf options.
config *config.Config

// ipAddresses used in the netns, this is needed to store
// the netns ips that are used by pasta. This is then handed
// back to the caller via IPAddresses() which then can make
// sure to not use them for host.containers.internal.
ipAddresses []net.IP
// info contain information about ip addresses used in the netns.
// A caller can get this info via Info().
info *types.RootlessNetnsInfo
}

type rootlessNetnsError struct {
Expand Down Expand Up @@ -115,6 +117,9 @@ func (n *Netns) getOrCreateNetns() (ns.NetNS, bool, error) {
// quick check if pasta/slirp4netns are still running
err := unix.Kill(pid, 0)
if err == nil {
if err := n.deserializeInfo(); err != nil {
return nil, false, wrapError("deserialize info", err)
}
// All good, return the netns.
return nsRef, false, nil
}
Expand Down Expand Up @@ -227,6 +232,15 @@ func (n *Netns) setupPasta(nsPath string) error {
return wrapError("create resolv.conf", err)
}

n.info = &types.RootlessNetnsInfo{
IPAddresses: res.IPAddresses,
DnsForwardIps: res.DNSForwardIPs,
MapGuestIps: res.MapGuestAddrIPs,
}
if err := n.serializeInfo(); err != nil {
return wrapError("serialize info", err)
}

return nil
}

Expand Down Expand Up @@ -261,6 +275,12 @@ func (n *Netns) setupSlirp4netns(nsPath string) error {
if err != nil {
return wrapError("determine default slirp4netns DNS address", err)
}
nameservers := []string{resolveIP.String()}

netnsIP, err := slirp4netns.GetIP(res.Subnet)
if err != nil {
return wrapError("determine default slirp4netns ip address", err)
}

if err := resolvconf.New(&resolvconf.Params{
Path: n.getPath(resolvConfName),
Expand All @@ -270,10 +290,19 @@ func (n *Netns) setupSlirp4netns(nsPath string) error {
},
IPv6Enabled: res.IPv6,
KeepHostServers: true,
Nameservers: []string{resolveIP.String()},
Nameservers: nameservers,
}); err != nil {
return wrapError("create resolv.conf", err)
}

n.info = &types.RootlessNetnsInfo{
IPAddresses: []net.IP{*netnsIP},
DnsForwardIps: nameservers,
}
if err := n.serializeInfo(); err != nil {
return wrapError("serialize info", err)
}

return nil
}

Expand Down Expand Up @@ -541,20 +570,6 @@ func (n *Netns) runInner(toRun func() error, cleanup bool) (err error) {
if err := toRun(); err != nil {
return err
}

// get the current active addresses in the netns, and store them
addrs, err := net.InterfaceAddrs()
if err != nil {
return err
}
ips := make([]net.IP, 0, len(addrs))
for _, addr := range addrs {
// make sure to skip localhost and other special addresses
if ipnet, ok := addr.(*net.IPNet); ok && ipnet.IP.IsGlobalUnicast() {
ips = append(ips, ipnet.IP)
}
}
n.ipAddresses = ips
return nil
})
}
Expand Down Expand Up @@ -630,9 +645,7 @@ func (n *Netns) Run(lock *lockfile.LockFile, toRun func() error) error {
// IPAddresses returns the currently used ip addresses in the netns
// These should then not be assigned for the host.containers.internal entry.
func (n *Netns) Info() *types.RootlessNetnsInfo {
return &types.RootlessNetnsInfo{
IPAddresses: n.ipAddresses,
}
return n.info
}

func refCount(dir string, inc int) (int, error) {
Expand Down Expand Up @@ -671,3 +684,26 @@ func readPidFile(path string) (int, error) {
}
return strconv.Atoi(strings.TrimSpace(string(b)))
}

func (n *Netns) serializeInfo() error {
f, err := os.Create(filepath.Join(n.dir, infoCacheFile))
if err != nil {
return err
}
return json.NewEncoder(f).Encode(n.info)
}

func (n *Netns) deserializeInfo() error {
f, err := os.Open(filepath.Join(n.dir, infoCacheFile))
if err != nil {
if errors.Is(err, fs.ErrNotExist) {
return nil
}
return err
}
defer f.Close()
if n.info == nil {
n.info = new(types.RootlessNetnsInfo)
}
return json.NewDecoder(f).Decode(n.info)
}
4 changes: 4 additions & 0 deletions libnetwork/types/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,10 @@ type TeardownOptions struct {
type RootlessNetnsInfo struct {
// IPAddresses used in the netns, must not be used for host.containers.internal
IPAddresses []net.IP
// DnsForwardIps ips used in resolv.conf
DnsForwardIps []string
// MapGuestIps should be used for the host.containers.internal entry when set
MapGuestIps []string
}

// FilterFunc can be passed to NetworkList to filter the networks.
Expand Down

0 comments on commit 3081b0d

Please sign in to comment.