Skip to content

Commit

Permalink
Inspect network info of a joined network namespace
Browse files Browse the repository at this point in the history
Closes: containers#13150
Signed-off-by: 馃槑 Mostafa Emami <mustafaemami@gmail.com>
  • Loading branch information
idleroamer committed Mar 1, 2022
1 parent 2225c65 commit f44fd6a
Show file tree
Hide file tree
Showing 5 changed files with 226 additions and 2 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ require (
github.com/ulikunitz/xz v0.5.10
github.com/vbauerster/mpb/v6 v6.0.4
github.com/vishvananda/netlink v1.1.1-0.20220115184804-dd687eb2f2d4
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f
go.etcd.io/bbolt v1.3.6
golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,7 @@ github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
github.com/coreos/go-iptables v0.5.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
github.com/coreos/go-iptables v0.6.0 h1:is9qnZMPYjLd8LYqmm/qlE+wwEgJIkTYdhV3rfZo4jk=
github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q=
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
Expand Down Expand Up @@ -1195,6 +1196,7 @@ github.com/ryancurrah/gomodguard v1.2.3/go.mod h1:rYbA/4Tg5c54mV1sv4sQTP5WOPBcoL
github.com/ryanrolds/sqlclosecheck v0.3.0/go.mod h1:1gREqxyTGR3lVtpngyFo3hZAgk0KCtEdgEkHwDbigdA=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
github.com/safchain/ethtool v0.0.0-20210803160452-9aa261dae9b1 h1:ZFfeKAhIQiiOrQaI3/znw0gOmYpO28Tcu1YaqMa/jtQ=
github.com/safchain/ethtool v0.0.0-20210803160452-9aa261dae9b1/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
github.com/sagikazarmark/crypt v0.1.0/go.mod h1:B/mN0msZuINBtQ1zZLEQcegFJJf9vnYIR88KRMEuODE=
github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig=
Expand Down
85 changes: 83 additions & 2 deletions libpod/networking_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"github.com/containers/podman/v4/pkg/util"
"github.com/containers/podman/v4/utils"
"github.com/containers/storage/pkg/lockfile"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/selinux/go-selinux/label"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -990,8 +991,28 @@ func (c *Container) getContainerNetworkInfo() (*define.InspectNetworkSettings, e
return nil, err
}

// We can't do more if the network is down.
if c.state.NetNS == nil {
// check whether we have joined a network namespace
for _, namespace := range c.config.Spec.Linux.Namespaces {
if namespace.Type == spec.NetworkNamespace {
if namespace.Path != "" {
result, err := c.inspectJoinedNetworkNS(namespace.Path)
// do not propagate error inspecting a joined network ns
if err != nil {
logrus.Errorf("Error inspecting network namespace: %s of container %s: %v", namespace.Path, c.ID(), err)
return settings, nil
}
basicConfig, err := resultToBasicNetworkConfig(result)
if err != nil {
return nil, err
}
settings.InspectBasicNetworkConfig = basicConfig
return settings, nil
}
}
}
// We can't do more if the network is down.

// We still want to make dummy configurations for each CNI net
// the container joined.
if len(networks) > 0 {
Expand Down Expand Up @@ -1065,11 +1086,71 @@ func (c *Container) getContainerNetworkInfo() (*define.InspectNetworkSettings, e
return settings, nil
}

func (c *Container) inspectJoinedNetworkNS(networkns string) (q types.StatusBlock, retErr error) {
var result types.StatusBlock
err := ns.WithNetNSPath(networkns, func(_ ns.NetNS) error {
ifaces, err := net.Interfaces()
if err != nil {
return err
}
routes, err := netlink.RouteList(nil, netlink.FAMILY_ALL)
if err != nil {
return err
}
var gateway net.IP
for _, route := range routes {
// default gateway
if route.Dst == nil {
gateway = route.Gw
}
}
result.Interfaces = make(map[string]types.NetInterface)
for _, iface := range ifaces {
if strings.Contains(iface.Flags.String(), "loopback") {
continue
}
addrs, err := iface.Addrs()
if err != nil {
continue
}
if len(addrs) == 0 {
continue
}
subnets := make([]types.NetAddress, 0)
for _, address := range addrs {
if ipnet, ok := address.(*net.IPNet); ok {
subnets = append(subnets, types.NetAddress{
IPNet: types.IPNet{
IPNet: *ipnet,
},
Gateway: gateway,
})
}
}
if macAddress, err := net.ParseMAC(iface.HardwareAddr.String()); err == nil {
result.Interfaces[iface.Name] = types.NetInterface{
Subnets: subnets,
MacAddress: types.HardwareAddr(macAddress),
}
}
}
return nil
})
return result, err
}

// resultToBasicNetworkConfig produces an InspectBasicNetworkConfig from a CNI
// result
func resultToBasicNetworkConfig(result types.StatusBlock) (define.InspectBasicNetworkConfig, error) {
config := define.InspectBasicNetworkConfig{}
for _, netInt := range result.Interfaces {
interfaceNames := make([]string, 0, len(result.Interfaces))
for interfaceName := range result.Interfaces {
interfaceNames = append(interfaceNames, interfaceName)
}
// ensure consistent inspect result by sorting
sort.Strings(interfaceNames)
for _, interfaceName := range interfaceNames {
netInt := result.Interfaces[interfaceName]
for _, netAddress := range netInt.Subnets {
size, _ := netAddress.IPNet.Mask.Size()
if netAddress.IPNet.IP.To4() != nil {
Expand Down
133 changes: 133 additions & 0 deletions test/e2e/run_networking_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,21 @@ package integration

import (
"fmt"
"net"
"os"
"strings"
"syscall"

"github.com/containernetworking/plugins/pkg/ip"
"github.com/containernetworking/plugins/pkg/ns"
. "github.com/containers/podman/v4/test/utils"
"github.com/containers/storage/pkg/stringid"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
. "github.com/onsi/gomega/gexec"
"github.com/uber/jaeger-client-go/utils"
"github.com/vishvananda/netlink"
"github.com/vishvananda/netns"
)

var _ = Describe("Podman run networking", func() {
Expand Down Expand Up @@ -694,6 +700,133 @@ EXPOSE 2004-2005/tcp`, ALPINE)
Expect(session.OutputToString()).To(ContainSubstring("11.11.11.11"))
})

addAddr := func(cidr string, containerInterface netlink.Link) error {
_, ipnet, err := net.ParseCIDR(cidr)
Expect(err).To(BeNil())
addr := &netlink.Addr{IPNet: ipnet, Label: ""}
if err := netlink.AddrAdd(containerInterface, addr); err != nil && err != syscall.EEXIST {
return err
}
return nil
}

vethup := func(name string, mac string, hostNS ns.NetNS, addresses []string) {
_, veth, err := ip.SetupVeth(name, 1500, mac, hostNS)
Expect(err).To(BeNil())
eth, err := netlink.LinkByName(veth.Name)
Expect(err).To(BeNil())
err = netlink.LinkSetUp(eth)
Expect(err).To(BeNil())
for _, address := range addresses {
err := addAddr(address, eth)
Expect(err).To(BeNil())
}
}

setupNetworkNs := func(networkNSName string) {
ns.WithNetNSPath("/run/netns/"+networkNSName, func(hostNS ns.NetNS) error {
vethup("eth0", "46:7f:45:6e:4f:c8", hostNS, []string{"10.0.0.0/24"})
vethup("eth1", "56:6e:35:5d:3e:a8", hostNS, []string{"20.20.0.0/20"})
return nil
})
}

checkNetworkNsInspect := func(name string) {
inspectOut := podmanTest.InspectContainer(name)
Expect(inspectOut[0].NetworkSettings.IPAddress).To(Equal("10.0.0.0"))
Expect(inspectOut[0].NetworkSettings.IPPrefixLen).To(Equal(24))
Expect(len(inspectOut[0].NetworkSettings.SecondaryIPAddresses)).To(Equal(1))
Expect(inspectOut[0].NetworkSettings.SecondaryIPAddresses[0].Addr).To(Equal("20.20.0.0"))
Expect(inspectOut[0].NetworkSettings.SecondaryIPAddresses[0].PrefixLength).To(Equal(20))
Expect(inspectOut[0].NetworkSettings.MacAddress).To(Equal("46:7f:45:6e:4f:c8"))
Expect(len(inspectOut[0].NetworkSettings.AdditionalMacAddresses)).To(Equal(3))
Expect(inspectOut[0].NetworkSettings.AdditionalMacAddresses[0]).To(Equal("56:6e:35:5d:3e:a8"))
}

It("podman run newtork inspect fails gracefully on non-reachable network ns", func() {
SkipIfRootless("ip netns is not supported for rootless users")
if Containerized() {
Skip("Cannot be run within a container.")
}
networkNSName := "xxx3"
newns, _ := netns.NewNamed(networkNSName)

setupNetworkNs(networkNSName)

name := "xxx3Container"
session := podmanTest.Podman([]string{"run", "-d", "--name", name, "--net", "ns:/run/netns/" + networkNSName, ALPINE, "top"})
session.WaitWithDefaultTimeout()

// delete the named network ns before inspect
newns.Close()
netns.DeleteNamed(networkNSName)

inspectOut := podmanTest.InspectContainer(name)
Expect(inspectOut[0].NetworkSettings.IPAddress).To(Equal(""))
Expect(len(inspectOut[0].NetworkSettings.Networks)).To(Equal(0))
})

It("podman inspect can handle joined network ns with multiple interfaces", func() {
SkipIfRootless("ip netns is not supported for rootless users")
if Containerized() {
Skip("Cannot be run within a container.")
}

networkNSName := "xxx3"
newns, _ := netns.NewNamed(networkNSName)
defer newns.Close()
defer netns.DeleteNamed(networkNSName)

setupNetworkNs(networkNSName)

name := "xxx3Container"
session := podmanTest.Podman([]string{"run", "--name", name, "--net", "ns:/run/netns/" + networkNSName, ALPINE})
session.WaitWithDefaultTimeout()

session = podmanTest.Podman([]string{"container", "rm", name})
session.WaitWithDefaultTimeout()

// no network teardown should touch joined network ns interfaces
session = podmanTest.Podman([]string{"run", "-d", "--replace", "--name", name, "--net", "ns:/run/netns/" + networkNSName, ALPINE, "top"})
session.WaitWithDefaultTimeout()

checkNetworkNsInspect(name)
})

It("podman do not tamper with joined network ns interfaces", func() {
SkipIfRootless("ip netns is not supported for rootless users")
if Containerized() {
Skip("Cannot be run within a container.")
}

networkNSName := "xxx3"
newns, _ := netns.NewNamed(networkNSName)
defer newns.Close()
defer netns.DeleteNamed(networkNSName)

setupNetworkNs(networkNSName)

name := "xxx3Container"
session := podmanTest.Podman([]string{"run", "--name", name, "--net", "ns:/run/netns/" + networkNSName, ALPINE})
session.WaitWithDefaultTimeout()

checkNetworkNsInspect(name)

name = "xxx4Container"
session = podmanTest.Podman([]string{"run", "--name", name, "--net", "ns:/run/netns/" + networkNSName, ALPINE})
session.WaitWithDefaultTimeout()

checkNetworkNsInspect(name)

session = podmanTest.Podman([]string{"container", "rm", name})
session.WaitWithDefaultTimeout()

session = podmanTest.Podman([]string{"run", "-d", "--replace", "--name", name, "--net", "ns:/run/netns/" + networkNSName, ALPINE, "top"})
session.WaitWithDefaultTimeout()

checkNetworkNsInspect(name)
})

It("podman run network in bogus user created network namespace", func() {
session := podmanTest.Podman([]string{"run", "-dt", "--net", "ns:/run/netns/xxy", ALPINE, "wget", "www.podman.io"})
session.Wait(90)
Expand Down
7 changes: 7 additions & 0 deletions vendor/modules.txt
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,9 @@ github.com/containernetworking/cni/pkg/utils
github.com/containernetworking/cni/pkg/version
# github.com/containernetworking/plugins v1.1.0
## explicit
github.com/containernetworking/plugins/pkg/ip
github.com/containernetworking/plugins/pkg/ns
github.com/containernetworking/plugins/pkg/utils/sysctl
# github.com/containers/buildah v1.24.2
## explicit
github.com/containers/buildah
Expand Down Expand Up @@ -277,6 +279,8 @@ github.com/containers/storage/pkg/tarlog
github.com/containers/storage/pkg/truncindex
github.com/containers/storage/pkg/unshare
github.com/containers/storage/types
# github.com/coreos/go-iptables v0.6.0
github.com/coreos/go-iptables/iptables
# github.com/coreos/go-systemd v0.0.0-20190620071333-e64a0ec8b42a
github.com/coreos/go-systemd/activation
# github.com/coreos/go-systemd/v22 v22.3.2
Expand Down Expand Up @@ -639,6 +643,8 @@ github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/tcp
github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/udp
github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/udp/udpproxy
github.com/rootless-containers/rootlesskit/pkg/port/portutil
# github.com/safchain/ethtool v0.0.0-20210803160452-9aa261dae9b1
github.com/safchain/ethtool
# github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921
github.com/seccomp/libseccomp-golang
# github.com/sirupsen/logrus v1.8.1
Expand Down Expand Up @@ -698,6 +704,7 @@ github.com/vbauerster/mpb/v7/internal
github.com/vishvananda/netlink
github.com/vishvananda/netlink/nl
# github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f
## explicit
github.com/vishvananda/netns
# github.com/xeipuuv/gojsonpointer v0.0.0-20190809123943-df4f5c81cb3b
github.com/xeipuuv/gojsonpointer
Expand Down

0 comments on commit f44fd6a

Please sign in to comment.