Skip to content

Commit

Permalink
Merge pull request #2136 from Luap99/pasta-map-guest-addr
Browse files Browse the repository at this point in the history
pasta: use new --map-guest-addr option
  • Loading branch information
openshift-merge-bot[bot] authored Sep 6, 2024
2 parents 5a7ac5b + 6125e26 commit 5298b83
Show file tree
Hide file tree
Showing 6 changed files with 271 additions and 93 deletions.
56 changes: 42 additions & 14 deletions libnetwork/etchosts/ip.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,27 @@ import (
"github.com/containers/storage/pkg/unshare"
)

// GetHostContainersInternalIP returns the host.containers.internal ip
// if netStatus is not nil then networkInterface also must be non nil otherwise this function panics
func GetHostContainersInternalIP(conf *config.Config, netStatus map[string]types.StatusBlock, networkInterface types.ContainerNetwork) string {
return GetHostContainersInternalIPExcluding(conf, netStatus, networkInterface, nil)
// HostContainersInternalOptions contains the options for GetHostContainersInternalIP()
type HostContainersInternalOptions struct {
// Conf is the containers.Conf, must not be nil
Conf *config.Config
// NetStatus is the network status for the container,
// if this is set networkInterface must not be nil
NetStatus map[string]types.StatusBlock
// NetworkInterface of the current runtime
NetworkInterface types.ContainerNetwork
// Exclude are then ips that should not be returned, this is
// useful to prevent returning the same ip as in the container.
Exclude []net.IP
// PreferIP is a ip that should be used if set but it has a
// lower priority than the containers.conf config option.
// This is used for the pasta --map-guest-addr ip.
PreferIP string
}

// GetHostContainersInternalIPExcluding returns the host.containers.internal ip
// Exclude are ips that should not be returned, this is useful to prevent returning the same ip as in the container.
// if netStatus is not nil then networkInterface also must be non nil otherwise this function panics
func GetHostContainersInternalIPExcluding(conf *config.Config, netStatus map[string]types.StatusBlock, networkInterface types.ContainerNetwork, exclude []net.IP) string {
switch conf.Containers.HostContainersInternalIP {
// GetHostContainersInternalIP returns the host.containers.internal ip
func GetHostContainersInternalIP(opts HostContainersInternalOptions) string {
switch opts.Conf.Containers.HostContainersInternalIP {
case "":
// if empty (default) we will automatically choose one below
// if machine using gvproxy we let the gvproxy dns server handle the dns name so do not add it
Expand All @@ -30,16 +40,22 @@ func GetHostContainersInternalIPExcluding(conf *config.Config, netStatus map[str
case "none":
return ""
default:
return conf.Containers.HostContainersInternalIP
return opts.Conf.Containers.HostContainersInternalIP
}

// caller has a specific ip it prefers
if opts.PreferIP != "" {
return opts.PreferIP
}

ip := ""
// Only use the bridge ip when root, as rootless the interfaces are created
// inside the special netns and not the host so we cannot use them.
if unshare.IsRootless() {
return util.GetLocalIPExcluding(exclude)
return util.GetLocalIPExcluding(opts.Exclude)
}
for net, status := range netStatus {
network, err := networkInterface.NetworkInspect(net)
for net, status := range opts.NetStatus {
network, err := opts.NetworkInterface.NetworkInspect(net)
// only add the host entry for bridge networks
// ip/macvlan gateway is normally not on the host
if err != nil || network.Driver != types.BridgeNetworkDriver {
Expand All @@ -60,7 +76,19 @@ func GetHostContainersInternalIPExcluding(conf *config.Config, netStatus map[str
if ip != "" {
return ip
}
return util.GetLocalIPExcluding(exclude)
return util.GetLocalIPExcluding(opts.Exclude)
}

// GetHostContainersInternalIPExcluding returns the host.containers.internal ip
// Exclude are ips that should not be returned, this is useful to prevent returning the same ip as in the container.
// if netStatus is not nil then networkInterface also must be non nil otherwise this function panics
func GetHostContainersInternalIPExcluding(conf *config.Config, netStatus map[string]types.StatusBlock, networkInterface types.ContainerNetwork, exclude []net.IP) string {
return GetHostContainersInternalIP(HostContainersInternalOptions{
Conf: conf,
NetStatus: netStatus,
NetworkInterface: networkInterface,
Exclude: exclude,
})
}

// GetNetworkHostEntries returns HostEntries for all ips in the network status
Expand Down
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)
}
Loading

0 comments on commit 5298b83

Please sign in to comment.