github.com/AbhinandanKurakure/podman/v3@v3.4.10/libpod/network/cni/run_test.go (about)

     1  // +build linux
     2  
     3  package cni_test
     4  
     5  // The tests have to be run as root.
     6  // For each test there will be two network namespaces created,
     7  // netNSTest and netNSContainer. Each test must be run inside
     8  // netNSTest to prevent leakage in the host netns, therefore
     9  // it should use the following structure:
    10  // It("test name", func() {
    11  //   runTest(func() {
    12  //     // add test logic here
    13  //   })
    14  // })
    15  
    16  import (
    17  	"bytes"
    18  	"io/ioutil"
    19  	"net"
    20  	"os"
    21  	"path/filepath"
    22  	"strconv"
    23  	"sync"
    24  	"time"
    25  
    26  	"github.com/containernetworking/plugins/pkg/ns"
    27  	. "github.com/onsi/ginkgo"
    28  	. "github.com/onsi/gomega"
    29  	"github.com/sirupsen/logrus"
    30  	"github.com/vishvananda/netlink"
    31  	"golang.org/x/sys/unix"
    32  
    33  	"github.com/containers/podman/v3/libpod/network/types"
    34  	"github.com/containers/podman/v3/pkg/netns"
    35  	"github.com/containers/podman/v3/pkg/rootless"
    36  	"github.com/containers/storage/pkg/stringid"
    37  )
    38  
    39  var _ = Describe("run CNI", func() {
    40  	var (
    41  		libpodNet      types.ContainerNetwork
    42  		cniConfDir     string
    43  		logBuffer      bytes.Buffer
    44  		netNSTest      ns.NetNS
    45  		netNSContainer ns.NetNS
    46  	)
    47  	const cniVarDir = "/var/lib/cni"
    48  
    49  	// runTest is a helper function to run a test. It ensures that each test
    50  	// is run in its own netns. It also creates a mountns to mount a tmpfs to /var/lib/cni.
    51  	runTest := func(run func()) {
    52  		netNSTest.Do(func(_ ns.NetNS) error {
    53  			defer GinkgoRecover()
    54  			err := os.MkdirAll(cniVarDir, 0755)
    55  			Expect(err).To(BeNil(), "Failed to create cniVarDir")
    56  			err = unix.Unshare(unix.CLONE_NEWNS)
    57  			Expect(err).To(BeNil(), "Failed to create new mountns")
    58  			err = unix.Mount("tmpfs", cniVarDir, "tmpfs", unix.MS_NOEXEC|unix.MS_NOSUID|unix.MS_NODEV, "")
    59  			Expect(err).To(BeNil(), "Failed to mount tmpfs for cniVarDir")
    60  			defer unix.Unmount(cniVarDir, 0)
    61  
    62  			// we have to setup the loopback adapter in this netns to use port forwarding
    63  			link, err := netlink.LinkByName("lo")
    64  			Expect(err).To(BeNil(), "Failed to get loopback adapter")
    65  			err = netlink.LinkSetUp(link)
    66  			Expect(err).To(BeNil(), "Failed to set loopback adapter up")
    67  			run()
    68  			return nil
    69  		})
    70  	}
    71  
    72  	BeforeEach(func() {
    73  		// The tests need root privileges.
    74  		// Technically we could work around that by using user namespaces and
    75  		// the rootless cni code but this is to much work to get it right for a unit test.
    76  		if rootless.IsRootless() {
    77  			Skip("this test needs to be run as root")
    78  		}
    79  
    80  		var err error
    81  		cniConfDir, err = ioutil.TempDir("", "podman_cni_test")
    82  		if err != nil {
    83  			Fail("Failed to create tmpdir")
    84  		}
    85  		logBuffer = bytes.Buffer{}
    86  		logrus.SetOutput(&logBuffer)
    87  
    88  		netNSTest, err = netns.NewNS()
    89  		if err != nil {
    90  			Fail("Failed to create netns")
    91  		}
    92  
    93  		netNSContainer, err = netns.NewNS()
    94  		if err != nil {
    95  			Fail("Failed to create netns")
    96  		}
    97  	})
    98  
    99  	JustBeforeEach(func() {
   100  		var err error
   101  		libpodNet, err = getNetworkInterface(cniConfDir, false)
   102  		if err != nil {
   103  			Fail("Failed to create NewCNINetworkInterface")
   104  		}
   105  	})
   106  
   107  	AfterEach(func() {
   108  		os.RemoveAll(cniConfDir)
   109  
   110  		netns.UnmountNS(netNSTest)
   111  		netNSTest.Close()
   112  
   113  		netns.UnmountNS(netNSContainer)
   114  		netNSContainer.Close()
   115  	})
   116  
   117  	Context("network setup test", func() {
   118  
   119  		It("run with default config", func() {
   120  			runTest(func() {
   121  				defNet := types.DefaultNetworkName
   122  				intName := "eth0"
   123  				setupOpts := types.SetupOptions{
   124  					NetworkOptions: types.NetworkOptions{
   125  						ContainerID: stringid.GenerateNonCryptoID(),
   126  						Networks: map[string]types.PerNetworkOptions{
   127  							defNet: {InterfaceName: intName},
   128  						},
   129  					},
   130  				}
   131  				res, err := libpodNet.Setup(netNSContainer.Path(), setupOpts)
   132  				Expect(err).To(BeNil())
   133  				Expect(res).To(HaveLen(1))
   134  				Expect(res).To(HaveKey(defNet))
   135  				Expect(res[defNet].Interfaces).To(HaveKey(intName))
   136  				Expect(res[defNet].Interfaces[intName].Networks).To(HaveLen(1))
   137  				Expect(res[defNet].Interfaces[intName].Networks[0].Subnet.IP.String()).To(ContainSubstring("10.88.0."))
   138  				Expect(res[defNet].Interfaces[intName].MacAddress).To(HaveLen(6))
   139  				// default network has no dns
   140  				Expect(res[defNet].DNSServerIPs).To(BeEmpty())
   141  				Expect(res[defNet].DNSSearchDomains).To(BeEmpty())
   142  
   143  				err = libpodNet.Teardown(netNSContainer.Path(), types.TeardownOptions(setupOpts))
   144  				Expect(err).To(BeNil())
   145  			})
   146  		})
   147  
   148  		It("run with default config and static ip", func() {
   149  			runTest(func() {
   150  				defNet := types.DefaultNetworkName
   151  				intName := "eth0"
   152  				ip := net.ParseIP("10.88.5.5")
   153  				setupOpts := types.SetupOptions{
   154  					NetworkOptions: types.NetworkOptions{
   155  						ContainerID: stringid.GenerateNonCryptoID(),
   156  						Networks: map[string]types.PerNetworkOptions{
   157  							defNet: {
   158  								InterfaceName: intName,
   159  								StaticIPs:     []net.IP{ip},
   160  							},
   161  						},
   162  					},
   163  				}
   164  				res, err := libpodNet.Setup(netNSContainer.Path(), setupOpts)
   165  				Expect(err).To(BeNil())
   166  				Expect(res).To(HaveLen(1))
   167  				Expect(res).To(HaveKey(defNet))
   168  				Expect(res[defNet].Interfaces).To(HaveKey(intName))
   169  				Expect(res[defNet].Interfaces[intName].Networks).To(HaveLen(1))
   170  				Expect(res[defNet].Interfaces[intName].Networks[0].Subnet.IP).To(Equal(ip))
   171  				Expect(res[defNet].Interfaces[intName].MacAddress).To(HaveLen(6))
   172  				// default network has no dns
   173  				Expect(res[defNet].DNSServerIPs).To(BeEmpty())
   174  				Expect(res[defNet].DNSSearchDomains).To(BeEmpty())
   175  
   176  				err = libpodNet.Teardown(netNSContainer.Path(), types.TeardownOptions(setupOpts))
   177  				Expect(err).To(BeNil())
   178  			})
   179  		})
   180  
   181  		for _, proto := range []string{"tcp", "udp"} {
   182  			// copy proto to extra var to keep correct references in the goroutines
   183  			protocol := proto
   184  			It("run with exposed ports protocol "+protocol, func() {
   185  				runTest(func() {
   186  					testdata := stringid.GenerateNonCryptoID()
   187  					defNet := types.DefaultNetworkName
   188  					intName := "eth0"
   189  					setupOpts := types.SetupOptions{
   190  						NetworkOptions: types.NetworkOptions{
   191  							ContainerID: stringid.GenerateNonCryptoID(),
   192  							PortMappings: []types.PortMapping{{
   193  								Protocol:      protocol,
   194  								HostIP:        "127.0.0.1",
   195  								HostPort:      5000,
   196  								ContainerPort: 5000,
   197  							}},
   198  							Networks: map[string]types.PerNetworkOptions{
   199  								defNet: {InterfaceName: intName},
   200  							},
   201  						},
   202  					}
   203  					res, err := libpodNet.Setup(netNSContainer.Path(), setupOpts)
   204  					Expect(err).To(BeNil())
   205  					Expect(res).To(HaveLen(1))
   206  					Expect(res).To(HaveKey(defNet))
   207  					Expect(res[defNet].Interfaces).To(HaveKey(intName))
   208  					Expect(res[defNet].Interfaces[intName].Networks).To(HaveLen(1))
   209  					Expect(res[defNet].Interfaces[intName].Networks[0].Subnet.IP.String()).To(ContainSubstring("10.88.0."))
   210  					Expect(res[defNet].Interfaces[intName].MacAddress).To(HaveLen(6))
   211  					// default network has no dns
   212  					Expect(res[defNet].DNSServerIPs).To(BeEmpty())
   213  					Expect(res[defNet].DNSSearchDomains).To(BeEmpty())
   214  					var wg sync.WaitGroup
   215  					wg.Add(1)
   216  					// start a listener in the container ns
   217  					err = netNSContainer.Do(func(_ ns.NetNS) error {
   218  						defer GinkgoRecover()
   219  						runNetListener(&wg, protocol, "0.0.0.0", 5000, testdata)
   220  						return nil
   221  					})
   222  					Expect(err).To(BeNil())
   223  
   224  					conn, err := net.Dial(protocol, "127.0.0.1:5000")
   225  					Expect(err).To(BeNil())
   226  					_, err = conn.Write([]byte(testdata))
   227  					Expect(err).To(BeNil())
   228  					conn.Close()
   229  
   230  					// wait for the listener to finish
   231  					wg.Wait()
   232  
   233  					err = libpodNet.Teardown(netNSContainer.Path(), types.TeardownOptions(setupOpts))
   234  					Expect(err).To(BeNil())
   235  				})
   236  			})
   237  
   238  			It("run with range ports protocol "+protocol, func() {
   239  				runTest(func() {
   240  					defNet := types.DefaultNetworkName
   241  					intName := "eth0"
   242  					setupOpts := types.SetupOptions{
   243  						NetworkOptions: types.NetworkOptions{
   244  							ContainerID: stringid.GenerateNonCryptoID(),
   245  							PortMappings: []types.PortMapping{{
   246  								Protocol:      protocol,
   247  								HostIP:        "127.0.0.1",
   248  								HostPort:      5001,
   249  								ContainerPort: 5000,
   250  								Range:         3,
   251  							}},
   252  							Networks: map[string]types.PerNetworkOptions{
   253  								defNet: {InterfaceName: intName},
   254  							},
   255  						},
   256  					}
   257  					res, err := libpodNet.Setup(netNSContainer.Path(), setupOpts)
   258  					Expect(err).To(BeNil())
   259  					Expect(res).To(HaveLen(1))
   260  					Expect(res).To(HaveKey(defNet))
   261  					Expect(res[defNet].Interfaces).To(HaveKey(intName))
   262  					Expect(res[defNet].Interfaces[intName].Networks).To(HaveLen(1))
   263  					containerIP := res[defNet].Interfaces[intName].Networks[0].Subnet.IP.String()
   264  					Expect(containerIP).To(ContainSubstring("10.88.0."))
   265  					Expect(res[defNet].Interfaces[intName].MacAddress).To(HaveLen(6))
   266  					// default network has no dns
   267  					Expect(res[defNet].DNSServerIPs).To(BeEmpty())
   268  					Expect(res[defNet].DNSSearchDomains).To(BeEmpty())
   269  
   270  					// loop over all ports
   271  					for p := 5001; p < 5004; p++ {
   272  						port := p
   273  						var wg sync.WaitGroup
   274  						wg.Add(1)
   275  						testdata := stringid.GenerateNonCryptoID()
   276  						// start a listener in the container ns
   277  						err = netNSContainer.Do(func(_ ns.NetNS) error {
   278  							defer GinkgoRecover()
   279  							runNetListener(&wg, protocol, containerIP, port-1, testdata)
   280  							return nil
   281  						})
   282  						Expect(err).To(BeNil())
   283  
   284  						conn, err := net.Dial(protocol, net.JoinHostPort("127.0.0.1", strconv.Itoa(port)))
   285  						Expect(err).To(BeNil())
   286  						_, err = conn.Write([]byte(testdata))
   287  						Expect(err).To(BeNil())
   288  						conn.Close()
   289  
   290  						// wait for the listener to finish
   291  						wg.Wait()
   292  					}
   293  
   294  					err = libpodNet.Teardown(netNSContainer.Path(), types.TeardownOptions(setupOpts))
   295  					Expect(err).To(BeNil())
   296  				})
   297  			})
   298  		}
   299  
   300  		It("run with comma separated port protocol", func() {
   301  			runTest(func() {
   302  				defNet := types.DefaultNetworkName
   303  				intName := "eth0"
   304  				setupOpts := types.SetupOptions{
   305  					NetworkOptions: types.NetworkOptions{
   306  						ContainerID: stringid.GenerateNonCryptoID(),
   307  						PortMappings: []types.PortMapping{{
   308  							Protocol:      "tcp,udp",
   309  							HostIP:        "127.0.0.1",
   310  							HostPort:      5000,
   311  							ContainerPort: 5000,
   312  						}},
   313  						Networks: map[string]types.PerNetworkOptions{
   314  							defNet: {InterfaceName: intName},
   315  						},
   316  					},
   317  				}
   318  				res, err := libpodNet.Setup(netNSContainer.Path(), setupOpts)
   319  				Expect(err).To(BeNil())
   320  				Expect(res).To(HaveLen(1))
   321  				Expect(res).To(HaveKey(defNet))
   322  				Expect(res[defNet].Interfaces).To(HaveKey(intName))
   323  				Expect(res[defNet].Interfaces[intName].Networks).To(HaveLen(1))
   324  				Expect(res[defNet].Interfaces[intName].Networks[0].Subnet.IP.String()).To(ContainSubstring("10.88.0."))
   325  				Expect(res[defNet].Interfaces[intName].MacAddress).To(HaveLen(6))
   326  
   327  				for _, proto := range []string{"tcp", "udp"} {
   328  					// copy proto to extra var to keep correct references in the goroutines
   329  					protocol := proto
   330  
   331  					testdata := stringid.GenerateNonCryptoID()
   332  					var wg sync.WaitGroup
   333  					wg.Add(1)
   334  					// start tcp listener in the container ns
   335  					err = netNSContainer.Do(func(_ ns.NetNS) error {
   336  						defer GinkgoRecover()
   337  						runNetListener(&wg, protocol, "0.0.0.0", 5000, testdata)
   338  						return nil
   339  					})
   340  					Expect(err).To(BeNil())
   341  
   342  					conn, err := net.Dial(protocol, "127.0.0.1:5000")
   343  					Expect(err).To(BeNil())
   344  					_, err = conn.Write([]byte(testdata))
   345  					Expect(err).To(BeNil())
   346  					conn.Close()
   347  
   348  					// wait for the listener to finish
   349  					wg.Wait()
   350  				}
   351  
   352  				err = libpodNet.Teardown(netNSContainer.Path(), types.TeardownOptions(setupOpts))
   353  				Expect(err).To(BeNil())
   354  			})
   355  		})
   356  
   357  		It("call setup twice", func() {
   358  			runTest(func() {
   359  				network := types.Network{}
   360  				network1, err := libpodNet.NetworkCreate(network)
   361  				Expect(err).To(BeNil())
   362  
   363  				intName1 := "eth0"
   364  				netName1 := network1.Name
   365  
   366  				containerID := stringid.GenerateNonCryptoID()
   367  
   368  				setupOpts := types.SetupOptions{
   369  					NetworkOptions: types.NetworkOptions{
   370  						ContainerID: containerID,
   371  						Networks: map[string]types.PerNetworkOptions{
   372  							netName1: {
   373  								InterfaceName: intName1,
   374  							},
   375  						},
   376  					},
   377  				}
   378  
   379  				res, err := libpodNet.Setup(netNSContainer.Path(), setupOpts)
   380  				Expect(err).To(BeNil())
   381  				Expect(res).To(HaveLen(1))
   382  
   383  				Expect(res).To(HaveKey(netName1))
   384  				Expect(res[netName1].Interfaces).To(HaveKey(intName1))
   385  				Expect(res[netName1].Interfaces[intName1].Networks).To(HaveLen(1))
   386  				ipInt1 := res[netName1].Interfaces[intName1].Networks[0].Subnet.IP
   387  				Expect(ipInt1).ToNot(BeEmpty())
   388  				macInt1 := res[netName1].Interfaces[intName1].MacAddress
   389  				Expect(macInt1).To(HaveLen(6))
   390  
   391  				// check in the container namespace if the settings are applied
   392  				err = netNSContainer.Do(func(_ ns.NetNS) error {
   393  					defer GinkgoRecover()
   394  					i, err := net.InterfaceByName(intName1)
   395  					Expect(err).To(BeNil())
   396  					Expect(i.Name).To(Equal(intName1))
   397  					Expect(i.HardwareAddr).To(Equal(macInt1))
   398  					addrs, err := i.Addrs()
   399  					Expect(err).To(BeNil())
   400  					subnet := &net.IPNet{
   401  						IP:   ipInt1,
   402  						Mask: net.CIDRMask(24, 32),
   403  					}
   404  					Expect(addrs).To(ContainElements(subnet))
   405  
   406  					// check loopback adapter
   407  					i, err = net.InterfaceByName("lo")
   408  					Expect(err).To(BeNil())
   409  					Expect(i.Name).To(Equal("lo"))
   410  					Expect(i.Flags & net.FlagLoopback).To(Equal(net.FlagLoopback))
   411  					Expect(i.Flags&net.FlagUp).To(Equal(net.FlagUp), "Loopback adapter should be up")
   412  					return nil
   413  				})
   414  				Expect(err).To(BeNil())
   415  
   416  				network = types.Network{}
   417  				network2, err := libpodNet.NetworkCreate(network)
   418  				Expect(err).To(BeNil())
   419  
   420  				intName2 := "eth1"
   421  				netName2 := network2.Name
   422  
   423  				setupOpts.Networks = map[string]types.PerNetworkOptions{
   424  					netName2: {
   425  						InterfaceName: intName2,
   426  					},
   427  				}
   428  
   429  				res, err = libpodNet.Setup(netNSContainer.Path(), setupOpts)
   430  				Expect(err).To(BeNil())
   431  				Expect(res).To(HaveLen(1))
   432  
   433  				Expect(res).To(HaveKey(netName2))
   434  				Expect(res[netName2].Interfaces).To(HaveKey(intName2))
   435  				Expect(res[netName2].Interfaces[intName2].Networks).To(HaveLen(1))
   436  				ipInt2 := res[netName2].Interfaces[intName2].Networks[0].Subnet.IP
   437  				Expect(ipInt2).ToNot(BeEmpty())
   438  				macInt2 := res[netName2].Interfaces[intName2].MacAddress
   439  				Expect(macInt2).To(HaveLen(6))
   440  
   441  				// check in the container namespace if the settings are applied
   442  				err = netNSContainer.Do(func(_ ns.NetNS) error {
   443  					defer GinkgoRecover()
   444  					i, err := net.InterfaceByName(intName1)
   445  					Expect(err).To(BeNil())
   446  					Expect(i.Name).To(Equal(intName1))
   447  					Expect(i.HardwareAddr).To(Equal(macInt1))
   448  					addrs, err := i.Addrs()
   449  					Expect(err).To(BeNil())
   450  					subnet := &net.IPNet{
   451  						IP:   ipInt1,
   452  						Mask: net.CIDRMask(24, 32),
   453  					}
   454  					Expect(addrs).To(ContainElements(subnet))
   455  
   456  					i, err = net.InterfaceByName(intName2)
   457  					Expect(err).To(BeNil())
   458  					Expect(i.Name).To(Equal(intName2))
   459  					Expect(i.HardwareAddr).To(Equal(macInt2))
   460  					addrs, err = i.Addrs()
   461  					Expect(err).To(BeNil())
   462  					subnet = &net.IPNet{
   463  						IP:   ipInt2,
   464  						Mask: net.CIDRMask(24, 32),
   465  					}
   466  					Expect(addrs).To(ContainElements(subnet))
   467  
   468  					// check loopback adapter
   469  					i, err = net.InterfaceByName("lo")
   470  					Expect(err).To(BeNil())
   471  					Expect(i.Name).To(Equal("lo"))
   472  					Expect(i.Flags & net.FlagLoopback).To(Equal(net.FlagLoopback))
   473  					Expect(i.Flags&net.FlagUp).To(Equal(net.FlagUp), "Loopback adapter should be up")
   474  					return nil
   475  				})
   476  				Expect(err).To(BeNil())
   477  
   478  				teatdownOpts := types.TeardownOptions{
   479  					NetworkOptions: types.NetworkOptions{
   480  						ContainerID: containerID,
   481  						Networks: map[string]types.PerNetworkOptions{
   482  							netName1: {
   483  								InterfaceName: intName1,
   484  							},
   485  							netName2: {
   486  								InterfaceName: intName2,
   487  							},
   488  						},
   489  					},
   490  				}
   491  
   492  				err = libpodNet.Teardown(netNSContainer.Path(), teatdownOpts)
   493  				Expect(err).To(BeNil())
   494  				logString := logBuffer.String()
   495  				Expect(logString).To(BeEmpty())
   496  
   497  				// check in the container namespace that the interface is removed
   498  				err = netNSContainer.Do(func(_ ns.NetNS) error {
   499  					defer GinkgoRecover()
   500  					_, err := net.InterfaceByName(intName1)
   501  					Expect(err).To(HaveOccurred())
   502  					_, err = net.InterfaceByName(intName2)
   503  					Expect(err).To(HaveOccurred())
   504  
   505  					// check that only the loopback adapter is left
   506  					ints, err := net.Interfaces()
   507  					Expect(err).To(BeNil())
   508  					Expect(ints).To(HaveLen(1))
   509  					Expect(ints[0].Name).To(Equal("lo"))
   510  					Expect(ints[0].Flags & net.FlagLoopback).To(Equal(net.FlagLoopback))
   511  					Expect(ints[0].Flags&net.FlagUp).To(Equal(net.FlagUp), "Loopback adapter should be up")
   512  
   513  					return nil
   514  				})
   515  				Expect(err).To(BeNil())
   516  
   517  				err = libpodNet.NetworkRemove(netName1)
   518  				Expect(err).To(BeNil())
   519  				err = libpodNet.NetworkRemove(netName2)
   520  				Expect(err).To(BeNil())
   521  
   522  				// check that the interfaces are removed in the host ns
   523  				_, err = net.InterfaceByName(network1.NetworkInterface)
   524  				Expect(err).To(HaveOccurred())
   525  				_, err = net.InterfaceByName(network2.NetworkInterface)
   526  				Expect(err).To(HaveOccurred())
   527  			})
   528  		})
   529  
   530  		It("setup two networks with one setup call", func() {
   531  			runTest(func() {
   532  				subnet1, _ := types.ParseCIDR("192.168.0.0/24")
   533  				subnet2, _ := types.ParseCIDR("192.168.1.0/24")
   534  				network := types.Network{
   535  					Subnets: []types.Subnet{
   536  						{Subnet: subnet1},
   537  					},
   538  				}
   539  				network1, err := libpodNet.NetworkCreate(network)
   540  				Expect(err).To(BeNil())
   541  
   542  				network = types.Network{
   543  					Subnets: []types.Subnet{
   544  						{Subnet: subnet2},
   545  					},
   546  				}
   547  				network2, err := libpodNet.NetworkCreate(network)
   548  				Expect(err).To(BeNil())
   549  
   550  				intName1 := "eth0"
   551  				intName2 := "eth1"
   552  				netName1 := network1.Name
   553  				netName2 := network2.Name
   554  
   555  				setupOpts := types.SetupOptions{
   556  					NetworkOptions: types.NetworkOptions{
   557  						ContainerID: stringid.GenerateNonCryptoID(),
   558  						Networks: map[string]types.PerNetworkOptions{
   559  							netName1: {
   560  								InterfaceName: intName1,
   561  							},
   562  							netName2: {
   563  								InterfaceName: intName2,
   564  							},
   565  						},
   566  					},
   567  				}
   568  
   569  				res, err := libpodNet.Setup(netNSContainer.Path(), setupOpts)
   570  				Expect(err).To(BeNil())
   571  				Expect(res).To(HaveLen(2))
   572  
   573  				Expect(res).To(HaveKey(netName1))
   574  				Expect(res[netName1].Interfaces).To(HaveKey(intName1))
   575  				Expect(res[netName1].Interfaces[intName1].Networks).To(HaveLen(1))
   576  				ipInt1 := res[netName1].Interfaces[intName1].Networks[0].Subnet.IP
   577  				Expect(ipInt1.String()).To(ContainSubstring("192.168.0."))
   578  				macInt1 := res[netName1].Interfaces[intName1].MacAddress
   579  				Expect(macInt1).To(HaveLen(6))
   580  
   581  				Expect(res).To(HaveKey(netName2))
   582  				Expect(res[netName2].Interfaces).To(HaveKey(intName2))
   583  				Expect(res[netName2].Interfaces[intName2].Networks).To(HaveLen(1))
   584  				ipInt2 := res[netName2].Interfaces[intName2].Networks[0].Subnet.IP
   585  				Expect(ipInt2.String()).To(ContainSubstring("192.168.1."))
   586  				macInt2 := res[netName2].Interfaces[intName2].MacAddress
   587  				Expect(macInt2).To(HaveLen(6))
   588  
   589  				// default network has no dns
   590  				Expect(res[netName1].DNSServerIPs).To(BeEmpty())
   591  				Expect(res[netName1].DNSSearchDomains).To(BeEmpty())
   592  
   593  				// check in the container namespace if the settings are applied
   594  				err = netNSContainer.Do(func(_ ns.NetNS) error {
   595  					defer GinkgoRecover()
   596  					i, err := net.InterfaceByName(intName1)
   597  					Expect(err).To(BeNil())
   598  					Expect(i.Name).To(Equal(intName1))
   599  					Expect(i.HardwareAddr).To(Equal(macInt1))
   600  					addrs, err := i.Addrs()
   601  					Expect(err).To(BeNil())
   602  					subnet := &net.IPNet{
   603  						IP:   ipInt1,
   604  						Mask: net.CIDRMask(24, 32),
   605  					}
   606  					Expect(addrs).To(ContainElements(subnet))
   607  
   608  					i, err = net.InterfaceByName(intName2)
   609  					Expect(err).To(BeNil())
   610  					Expect(i.Name).To(Equal(intName2))
   611  					Expect(i.HardwareAddr).To(Equal(macInt2))
   612  					addrs, err = i.Addrs()
   613  					Expect(err).To(BeNil())
   614  					subnet = &net.IPNet{
   615  						IP:   ipInt2,
   616  						Mask: net.CIDRMask(24, 32),
   617  					}
   618  					Expect(addrs).To(ContainElements(subnet))
   619  
   620  					// check loopback adapter
   621  					i, err = net.InterfaceByName("lo")
   622  					Expect(err).To(BeNil())
   623  					Expect(i.Name).To(Equal("lo"))
   624  					Expect(i.Flags & net.FlagLoopback).To(Equal(net.FlagLoopback))
   625  					Expect(i.Flags&net.FlagUp).To(Equal(net.FlagUp), "Loopback adapter should be up")
   626  					return nil
   627  				})
   628  				Expect(err).To(BeNil())
   629  
   630  				err = libpodNet.Teardown(netNSContainer.Path(), types.TeardownOptions(setupOpts))
   631  				Expect(err).To(BeNil())
   632  				logString := logBuffer.String()
   633  				Expect(logString).To(BeEmpty())
   634  
   635  				// check in the container namespace that the interface is removed
   636  				err = netNSContainer.Do(func(_ ns.NetNS) error {
   637  					defer GinkgoRecover()
   638  					_, err := net.InterfaceByName(intName1)
   639  					Expect(err).To(HaveOccurred())
   640  					_, err = net.InterfaceByName(intName2)
   641  					Expect(err).To(HaveOccurred())
   642  
   643  					// check that only the loopback adapter is left
   644  					ints, err := net.Interfaces()
   645  					Expect(err).To(BeNil())
   646  					Expect(ints).To(HaveLen(1))
   647  					Expect(ints[0].Name).To(Equal("lo"))
   648  					Expect(ints[0].Flags & net.FlagLoopback).To(Equal(net.FlagLoopback))
   649  					Expect(ints[0].Flags&net.FlagUp).To(Equal(net.FlagUp), "Loopback adapter should be up")
   650  
   651  					return nil
   652  				})
   653  				Expect(err).To(BeNil())
   654  			})
   655  
   656  		})
   657  
   658  		It("dual stack network with static ips", func() {
   659  			// Version checks for cni plugins are not possible, the plugins do not output
   660  			// version information and using the package manager does not work across distros.
   661  			// Fedora has the right version so we use this for now.
   662  			SkipIfNotFedora("requires cni plugins 1.0.0 or newer for multiple static ips")
   663  			runTest(func() {
   664  				subnet1, _ := types.ParseCIDR("192.168.0.0/24")
   665  				subnet2, _ := types.ParseCIDR("fd41:0a75:2ca0:48a9::/64")
   666  				network := types.Network{
   667  					Subnets: []types.Subnet{
   668  						{Subnet: subnet1}, {Subnet: subnet2},
   669  					},
   670  				}
   671  				network1, err := libpodNet.NetworkCreate(network)
   672  				Expect(err).To(BeNil())
   673  
   674  				mac, _ := net.ParseMAC("40:15:2f:d8:42:36")
   675  				interfaceName := "eth0"
   676  
   677  				ip1 := net.ParseIP("192.168.0.5")
   678  				ip2 := net.ParseIP("fd41:0a75:2ca0:48a9::5")
   679  
   680  				netName := network1.Name
   681  				setupOpts := types.SetupOptions{
   682  					NetworkOptions: types.NetworkOptions{
   683  						ContainerName: "mycon",
   684  						ContainerID:   stringid.GenerateNonCryptoID(),
   685  						Networks: map[string]types.PerNetworkOptions{
   686  							netName: {
   687  								InterfaceName: interfaceName,
   688  								StaticIPs:     []net.IP{ip1, ip2},
   689  								StaticMAC:     mac,
   690  							},
   691  						},
   692  					},
   693  				}
   694  
   695  				res, err := libpodNet.Setup(netNSContainer.Path(), setupOpts)
   696  				Expect(err).To(BeNil())
   697  				Expect(res).To(HaveLen(1))
   698  				Expect(res).To(HaveKey(netName))
   699  				Expect(res[netName].Interfaces).To(HaveKey(interfaceName))
   700  				Expect(res[netName].Interfaces[interfaceName].Networks).To(HaveLen(2))
   701  				Expect(res[netName].Interfaces[interfaceName].Networks[0].Subnet.IP.String()).To(Equal(ip1.String()))
   702  				Expect(res[netName].Interfaces[interfaceName].Networks[0].Subnet.Mask).To(Equal(subnet1.Mask))
   703  				Expect(res[netName].Interfaces[interfaceName].Networks[0].Gateway).To(Equal(net.ParseIP("192.168.0.1")))
   704  				Expect(res[netName].Interfaces[interfaceName].Networks[1].Subnet.IP.String()).To(Equal(ip2.String()))
   705  				Expect(res[netName].Interfaces[interfaceName].Networks[1].Subnet.Mask).To(Equal(subnet2.Mask))
   706  				Expect(res[netName].Interfaces[interfaceName].Networks[1].Gateway).To(Equal(net.ParseIP("fd41:0a75:2ca0:48a9::1")))
   707  				Expect(res[netName].Interfaces[interfaceName].MacAddress).To(Equal(mac))
   708  				// default network has no dns
   709  				Expect(res[netName].DNSServerIPs).To(BeEmpty())
   710  				Expect(res[netName].DNSSearchDomains).To(BeEmpty())
   711  
   712  				// check in the container namespace if the settings are applied
   713  				err = netNSContainer.Do(func(_ ns.NetNS) error {
   714  					defer GinkgoRecover()
   715  					i, err := net.InterfaceByName(interfaceName)
   716  					Expect(err).To(BeNil())
   717  					Expect(i.Name).To(Equal(interfaceName))
   718  					Expect(i.HardwareAddr).To(Equal(mac))
   719  					addrs, err := i.Addrs()
   720  					Expect(err).To(BeNil())
   721  					subnet1 := &net.IPNet{
   722  						IP:   ip1,
   723  						Mask: net.CIDRMask(24, 32),
   724  					}
   725  					subnet2 := &net.IPNet{
   726  						IP:   ip2,
   727  						Mask: net.CIDRMask(64, 128),
   728  					}
   729  					Expect(addrs).To(ContainElements(subnet1, subnet2))
   730  
   731  					// check loopback adapter
   732  					i, err = net.InterfaceByName("lo")
   733  					Expect(err).To(BeNil())
   734  					Expect(i.Name).To(Equal("lo"))
   735  					Expect(i.Flags & net.FlagLoopback).To(Equal(net.FlagLoopback))
   736  					Expect(i.Flags&net.FlagUp).To(Equal(net.FlagUp), "Loopback adapter should be up")
   737  					return nil
   738  				})
   739  				Expect(err).To(BeNil())
   740  
   741  				err = libpodNet.Teardown(netNSContainer.Path(), types.TeardownOptions(setupOpts))
   742  				Expect(err).To(BeNil())
   743  				logString := logBuffer.String()
   744  				Expect(logString).To(BeEmpty())
   745  
   746  				// check in the container namespace that the interface is removed
   747  				err = netNSContainer.Do(func(_ ns.NetNS) error {
   748  					defer GinkgoRecover()
   749  					_, err := net.InterfaceByName(interfaceName)
   750  					Expect(err).To(HaveOccurred())
   751  
   752  					// check that only the loopback adapter is left
   753  					ints, err := net.Interfaces()
   754  					Expect(err).To(BeNil())
   755  					Expect(ints).To(HaveLen(1))
   756  					Expect(ints[0].Name).To(Equal("lo"))
   757  					Expect(ints[0].Flags & net.FlagLoopback).To(Equal(net.FlagLoopback))
   758  					Expect(ints[0].Flags&net.FlagUp).To(Equal(net.FlagUp), "Loopback adapter should be up")
   759  
   760  					return nil
   761  				})
   762  				Expect(err).To(BeNil())
   763  			})
   764  		})
   765  
   766  		It("CNI_ARGS from environment variable", func() {
   767  			runTest(func() {
   768  				subnet1, _ := types.ParseCIDR("172.16.1.0/24")
   769  				ip := "172.16.1.5"
   770  				network := types.Network{
   771  					Subnets: []types.Subnet{
   772  						{Subnet: subnet1},
   773  					},
   774  				}
   775  				network1, err := libpodNet.NetworkCreate(network)
   776  				Expect(err).To(BeNil())
   777  				netName := network1.Name
   778  				intName := "eth0"
   779  				setupOpts := types.SetupOptions{
   780  					NetworkOptions: types.NetworkOptions{
   781  						ContainerID: stringid.GenerateNonCryptoID(),
   782  						Networks: map[string]types.PerNetworkOptions{
   783  							netName: {
   784  								InterfaceName: intName,
   785  							},
   786  						},
   787  					},
   788  				}
   789  
   790  				os.Setenv("CNI_ARGS", "IP="+ip)
   791  				defer os.Unsetenv("CNI_ARGS")
   792  
   793  				res, err := libpodNet.Setup(netNSContainer.Path(), setupOpts)
   794  				Expect(err).To(BeNil())
   795  				Expect(res).To(HaveLen(1))
   796  				Expect(res).To(HaveKey(netName))
   797  				Expect(res[netName].Interfaces).To(HaveKey(intName))
   798  				Expect(res[netName].Interfaces[intName].Networks).To(HaveLen(1))
   799  				Expect(res[netName].Interfaces[intName].Networks[0].Subnet.IP.String()).To(Equal(ip))
   800  				Expect(res[netName].Interfaces[intName].Networks[0].Subnet.Mask).To(Equal(net.CIDRMask(24, 32)))
   801  
   802  				// check in the container namespace if the settings are applied
   803  				err = netNSContainer.Do(func(_ ns.NetNS) error {
   804  					defer GinkgoRecover()
   805  					i, err := net.InterfaceByName(intName)
   806  					Expect(err).To(BeNil())
   807  					Expect(i.Name).To(Equal(intName))
   808  					addrs, err := i.Addrs()
   809  					Expect(err).To(BeNil())
   810  					subnet := &net.IPNet{
   811  						IP:   net.ParseIP(ip),
   812  						Mask: net.CIDRMask(24, 32),
   813  					}
   814  					Expect(addrs).To(ContainElements(subnet))
   815  
   816  					// check loopback adapter
   817  					i, err = net.InterfaceByName("lo")
   818  					Expect(err).To(BeNil())
   819  					Expect(i.Name).To(Equal("lo"))
   820  					Expect(i.Flags & net.FlagLoopback).To(Equal(net.FlagLoopback))
   821  					Expect(i.Flags&net.FlagUp).To(Equal(net.FlagUp), "Loopback adapter should be up")
   822  					return nil
   823  				})
   824  				Expect(err).To(BeNil())
   825  			})
   826  		})
   827  	})
   828  
   829  	Context("network setup test with networks from disk", func() {
   830  
   831  		BeforeEach(func() {
   832  			dir := "testfiles/valid"
   833  			files, err := ioutil.ReadDir(dir)
   834  			if err != nil {
   835  				Fail("Failed to read test directory")
   836  			}
   837  			for _, file := range files {
   838  				filename := file.Name()
   839  				data, err := ioutil.ReadFile(filepath.Join(dir, filename))
   840  				if err != nil {
   841  					Fail("Failed to copy test files")
   842  				}
   843  				err = ioutil.WriteFile(filepath.Join(cniConfDir, filename), data, 0700)
   844  				if err != nil {
   845  					Fail("Failed to copy test files")
   846  				}
   847  			}
   848  		})
   849  
   850  		It("dualstack setup with static ip and dns", func() {
   851  			SkipIfNoDnsname()
   852  			// Version checks for cni plugins are not possible, the plugins do not output
   853  			// version information and using the package manager does not work across distros.
   854  			// Fedora has the right version so we use this for now.
   855  			SkipIfNotFedora("requires cni plugins 1.0.0 or newer for multiple static ips")
   856  			runTest(func() {
   857  				interfaceName := "eth0"
   858  
   859  				ip1 := net.ParseIP("fd10:88:a::11")
   860  				ip2 := net.ParseIP("10.89.19.15")
   861  
   862  				containerName := "myname"
   863  				aliases := []string{"aliasname"}
   864  
   865  				netName := "dualstack"
   866  				setupOpts := types.SetupOptions{
   867  					NetworkOptions: types.NetworkOptions{
   868  						ContainerID:   stringid.GenerateNonCryptoID(),
   869  						ContainerName: containerName,
   870  						Networks: map[string]types.PerNetworkOptions{
   871  							netName: {
   872  								InterfaceName: interfaceName,
   873  								StaticIPs:     []net.IP{ip1, ip2},
   874  								Aliases:       aliases,
   875  							},
   876  						},
   877  					},
   878  				}
   879  
   880  				network, err := libpodNet.NetworkInspect(netName)
   881  				Expect(err).To(BeNil())
   882  				Expect(network.Name).To(Equal(netName))
   883  				Expect(network.DNSEnabled).To(BeTrue())
   884  				Expect(network.Subnets).To(HaveLen(2))
   885  				gw1 := network.Subnets[0].Gateway
   886  				Expect(gw1).To(HaveLen(16))
   887  				mask1 := network.Subnets[0].Subnet.Mask
   888  				Expect(mask1).To(HaveLen(16))
   889  				gw2 := network.Subnets[1].Gateway
   890  				Expect(gw2).To(HaveLen(4))
   891  				mask2 := network.Subnets[1].Subnet.Mask
   892  				Expect(mask2).To(HaveLen(4))
   893  
   894  				// because this net has dns we should always teardown otherwise we leak a dnsmasq process
   895  				defer libpodNet.Teardown(netNSContainer.Path(), types.TeardownOptions(setupOpts))
   896  				res, err := libpodNet.Setup(netNSContainer.Path(), setupOpts)
   897  				Expect(err).To(BeNil())
   898  				Expect(res).To(HaveLen(1))
   899  				Expect(res).To(HaveKey(netName))
   900  				Expect(res[netName].Interfaces).To(HaveKey(interfaceName))
   901  				Expect(res[netName].Interfaces[interfaceName].Networks).To(HaveLen(2))
   902  				Expect(res[netName].Interfaces[interfaceName].Networks[0].Subnet.IP.String()).To(Equal(ip1.String()))
   903  				Expect(res[netName].Interfaces[interfaceName].Networks[0].Subnet.Mask).To(Equal(mask1))
   904  				Expect(res[netName].Interfaces[interfaceName].Networks[1].Subnet.IP.String()).To(Equal(ip2.String()))
   905  				Expect(res[netName].Interfaces[interfaceName].Networks[1].Subnet.Mask).To(Equal(mask2))
   906  				// dualstack network dns
   907  				Expect(res[netName].DNSServerIPs).To(HaveLen(2))
   908  				Expect(res[netName].DNSSearchDomains).To(HaveLen(1))
   909  				Expect(res[netName].DNSSearchDomains).To(ConsistOf("dns.podman"))
   910  
   911  				// check in the container namespace if the settings are applied
   912  				err = netNSContainer.Do(func(_ ns.NetNS) error {
   913  					defer GinkgoRecover()
   914  					i, err := net.InterfaceByName(interfaceName)
   915  					Expect(err).To(BeNil())
   916  					Expect(i.Name).To(Equal(interfaceName))
   917  					addrs, err := i.Addrs()
   918  					Expect(err).To(BeNil())
   919  					subnet1 := &net.IPNet{
   920  						IP:   ip1,
   921  						Mask: net.CIDRMask(64, 128),
   922  					}
   923  					subnet2 := &net.IPNet{
   924  						IP:   ip2,
   925  						Mask: net.CIDRMask(24, 32),
   926  					}
   927  					Expect(addrs).To(ContainElements(subnet1, subnet2))
   928  
   929  					// check loopback adapter
   930  					i, err = net.InterfaceByName("lo")
   931  					Expect(err).To(BeNil())
   932  					Expect(i.Name).To(Equal("lo"))
   933  					Expect(i.Flags & net.FlagLoopback).To(Equal(net.FlagLoopback))
   934  					Expect(i.Flags&net.FlagUp).To(Equal(net.FlagUp), "Loopback adapter should be up")
   935  
   936  					return nil
   937  				})
   938  				Expect(err).To(BeNil())
   939  
   940  				err = libpodNet.Teardown(netNSContainer.Path(), types.TeardownOptions(setupOpts))
   941  				Expect(err).To(BeNil())
   942  				logString := logBuffer.String()
   943  				Expect(logString).To(BeEmpty())
   944  
   945  				// check in the container namespace that the interface is removed
   946  				err = netNSContainer.Do(func(_ ns.NetNS) error {
   947  					defer GinkgoRecover()
   948  					_, err := net.InterfaceByName(interfaceName)
   949  					Expect(err).To(HaveOccurred())
   950  
   951  					// check that only the loopback adapter is left
   952  					ints, err := net.Interfaces()
   953  					Expect(err).To(BeNil())
   954  					Expect(ints).To(HaveLen(1))
   955  					Expect(ints[0].Name).To(Equal("lo"))
   956  					Expect(ints[0].Flags & net.FlagLoopback).To(Equal(net.FlagLoopback))
   957  					Expect(ints[0].Flags&net.FlagUp).To(Equal(net.FlagUp), "Loopback adapter should be up")
   958  
   959  					return nil
   960  				})
   961  				Expect(err).To(BeNil())
   962  			})
   963  		})
   964  
   965  	})
   966  
   967  	Context("invalid network setup test", func() {
   968  
   969  		It("static ip not in subnet", func() {
   970  			runTest(func() {
   971  				defNet := types.DefaultNetworkName
   972  				intName := "eth0"
   973  				ip := "1.1.1.1"
   974  				setupOpts := types.SetupOptions{
   975  					NetworkOptions: types.NetworkOptions{
   976  						ContainerID: stringid.GenerateNonCryptoID(),
   977  						Networks: map[string]types.PerNetworkOptions{
   978  							defNet: {
   979  								InterfaceName: intName,
   980  								StaticIPs:     []net.IP{net.ParseIP(ip)},
   981  							},
   982  						},
   983  					},
   984  				}
   985  				_, err := libpodNet.Setup(netNSContainer.Path(), setupOpts)
   986  				Expect(err).To(HaveOccurred())
   987  				Expect(err.Error()).To(ContainSubstring("requested static ip %s not in any subnet on network %s", ip, defNet))
   988  			})
   989  		})
   990  
   991  		It("setup without namespace path", func() {
   992  			runTest(func() {
   993  				defNet := types.DefaultNetworkName
   994  				intName := "eth0"
   995  				setupOpts := types.SetupOptions{
   996  					NetworkOptions: types.NetworkOptions{
   997  						ContainerID: stringid.GenerateNonCryptoID(),
   998  						Networks: map[string]types.PerNetworkOptions{
   999  							defNet: {
  1000  								InterfaceName: intName,
  1001  							},
  1002  						},
  1003  					},
  1004  				}
  1005  				_, err := libpodNet.Setup("", setupOpts)
  1006  				Expect(err).To(HaveOccurred())
  1007  				Expect(err.Error()).To(ContainSubstring("namespacePath is empty"))
  1008  			})
  1009  		})
  1010  
  1011  		It("setup with invalid namespace path", func() {
  1012  			runTest(func() {
  1013  				defNet := types.DefaultNetworkName
  1014  				intName := "eth0"
  1015  				setupOpts := types.SetupOptions{
  1016  					NetworkOptions: types.NetworkOptions{
  1017  						ContainerID: stringid.GenerateNonCryptoID(),
  1018  						Networks: map[string]types.PerNetworkOptions{
  1019  							defNet: {
  1020  								InterfaceName: intName,
  1021  							},
  1022  						},
  1023  					},
  1024  				}
  1025  				_, err := libpodNet.Setup("some path", setupOpts)
  1026  				Expect(err).To(HaveOccurred())
  1027  				Expect(err.Error()).To(ContainSubstring(`"some path": no such file or directory`))
  1028  			})
  1029  		})
  1030  
  1031  		It("setup without container ID", func() {
  1032  			runTest(func() {
  1033  				defNet := types.DefaultNetworkName
  1034  				intName := "eth0"
  1035  				setupOpts := types.SetupOptions{
  1036  					NetworkOptions: types.NetworkOptions{
  1037  						ContainerID: "",
  1038  						Networks: map[string]types.PerNetworkOptions{
  1039  							defNet: {
  1040  								InterfaceName: intName,
  1041  							},
  1042  						},
  1043  					},
  1044  				}
  1045  				_, err := libpodNet.Setup(netNSContainer.Path(), setupOpts)
  1046  				Expect(err).To(HaveOccurred())
  1047  				Expect(err.Error()).To(ContainSubstring("ContainerID is empty"))
  1048  			})
  1049  		})
  1050  
  1051  		It("setup with aliases but dns disabled", func() {
  1052  			runTest(func() {
  1053  				defNet := types.DefaultNetworkName
  1054  				intName := "eth0"
  1055  				setupOpts := types.SetupOptions{
  1056  					NetworkOptions: types.NetworkOptions{
  1057  						ContainerID: stringid.GenerateNonCryptoID(),
  1058  						Networks: map[string]types.PerNetworkOptions{
  1059  							defNet: {
  1060  								InterfaceName: intName,
  1061  								Aliases:       []string{"somealias"},
  1062  							},
  1063  						},
  1064  					},
  1065  				}
  1066  				_, err := libpodNet.Setup(netNSContainer.Path(), setupOpts)
  1067  				Expect(err).To(HaveOccurred())
  1068  				Expect(err.Error()).To(ContainSubstring("cannot set aliases on a network without dns enabled"))
  1069  			})
  1070  		})
  1071  
  1072  		It("setup without networks", func() {
  1073  			runTest(func() {
  1074  				setupOpts := types.SetupOptions{
  1075  					NetworkOptions: types.NetworkOptions{
  1076  						ContainerID: stringid.GenerateNonCryptoID(),
  1077  					},
  1078  				}
  1079  				_, err := libpodNet.Setup(netNSContainer.Path(), setupOpts)
  1080  				Expect(err).To(HaveOccurred())
  1081  				Expect(err.Error()).To(ContainSubstring("must specify at least one network"))
  1082  			})
  1083  		})
  1084  
  1085  		It("setup without interface name", func() {
  1086  			runTest(func() {
  1087  				defNet := types.DefaultNetworkName
  1088  				setupOpts := types.SetupOptions{
  1089  					NetworkOptions: types.NetworkOptions{
  1090  						ContainerID: stringid.GenerateNonCryptoID(),
  1091  						Networks: map[string]types.PerNetworkOptions{
  1092  							defNet: {
  1093  								InterfaceName: "",
  1094  							},
  1095  						},
  1096  					},
  1097  				}
  1098  				_, err := libpodNet.Setup(netNSContainer.Path(), setupOpts)
  1099  				Expect(err).To(HaveOccurred())
  1100  				Expect(err.Error()).To(ContainSubstring("interface name on network %s is empty", defNet))
  1101  			})
  1102  		})
  1103  
  1104  		It("setup does teardown on failure", func() {
  1105  			runTest(func() {
  1106  				subnet1, _ := types.ParseCIDR("192.168.0.0/24")
  1107  				network := types.Network{
  1108  					Subnets: []types.Subnet{
  1109  						{Subnet: subnet1},
  1110  					},
  1111  				}
  1112  				network1, err := libpodNet.NetworkCreate(network)
  1113  				Expect(err).To(BeNil())
  1114  
  1115  				subnet2, _ := types.ParseCIDR("192.168.1.0/31")
  1116  				network = types.Network{
  1117  					Subnets: []types.Subnet{
  1118  						{Subnet: subnet2},
  1119  					},
  1120  				}
  1121  				network2, err := libpodNet.NetworkCreate(network)
  1122  				Expect(err).To(BeNil())
  1123  
  1124  				intName1 := "eth0"
  1125  				intName2 := "eth1"
  1126  				netName1 := network1.Name
  1127  				netName2 := network2.Name
  1128  
  1129  				setupOpts := types.SetupOptions{
  1130  					NetworkOptions: types.NetworkOptions{
  1131  						ContainerID: stringid.GenerateNonCryptoID(),
  1132  						Networks: map[string]types.PerNetworkOptions{
  1133  							netName1: {
  1134  								InterfaceName: intName1,
  1135  							},
  1136  							netName2: {
  1137  								InterfaceName: intName2,
  1138  							},
  1139  						},
  1140  					},
  1141  				}
  1142  				_, err = libpodNet.Setup(netNSContainer.Path(), setupOpts)
  1143  				Expect(err).To(HaveOccurred())
  1144  				Expect(err.Error()).To(ContainSubstring("Network 192.168.1.0/31 too small to allocate from"))
  1145  				// Note: we call teardown on the failing net and log the error, it should be the same.
  1146  				logString := logBuffer.String()
  1147  				Expect(logString).To(ContainSubstring("Network 192.168.1.0/31 too small to allocate from"))
  1148  
  1149  				// check in the container namespace that no interface is there
  1150  				err = netNSContainer.Do(func(_ ns.NetNS) error {
  1151  					defer GinkgoRecover()
  1152  					_, err := net.InterfaceByName(intName1)
  1153  					Expect(err).To(HaveOccurred())
  1154  
  1155  					// Note: We can check if intName2 is removed because
  1156  					// the cni plugin fails before it removes the interface
  1157  
  1158  					// check loopback adapter
  1159  					i, err := net.InterfaceByName("lo")
  1160  					Expect(err).To(BeNil())
  1161  					Expect(i.Name).To(Equal("lo"))
  1162  					Expect(i.Flags & net.FlagLoopback).To(Equal(net.FlagLoopback))
  1163  					Expect(i.Flags&net.FlagUp).To(Equal(net.FlagUp), "Loopback adapter should be up")
  1164  					return nil
  1165  				})
  1166  				Expect(err).To(BeNil())
  1167  			})
  1168  		})
  1169  
  1170  		It("setup with exposed invalid port protocol", func() {
  1171  			runTest(func() {
  1172  				defNet := types.DefaultNetworkName
  1173  				intName := "eth0"
  1174  				setupOpts := types.SetupOptions{
  1175  					NetworkOptions: types.NetworkOptions{
  1176  						ContainerID: stringid.GenerateNonCryptoID(),
  1177  						PortMappings: []types.PortMapping{{
  1178  							Protocol:      "someproto",
  1179  							HostIP:        "127.0.0.1",
  1180  							HostPort:      5000,
  1181  							ContainerPort: 5000,
  1182  						}},
  1183  						Networks: map[string]types.PerNetworkOptions{
  1184  							defNet: {InterfaceName: intName},
  1185  						},
  1186  					},
  1187  				}
  1188  				_, err := libpodNet.Setup(netNSContainer.Path(), setupOpts)
  1189  				Expect(err).To(HaveOccurred())
  1190  				Expect(err.Error()).To(ContainSubstring("unknown port protocol someproto"))
  1191  			})
  1192  		})
  1193  
  1194  		It("setup with exposed empty port protocol", func() {
  1195  			runTest(func() {
  1196  				defNet := types.DefaultNetworkName
  1197  				intName := "eth0"
  1198  				setupOpts := types.SetupOptions{
  1199  					NetworkOptions: types.NetworkOptions{
  1200  						ContainerID: stringid.GenerateNonCryptoID(),
  1201  						PortMappings: []types.PortMapping{{
  1202  							Protocol:      "",
  1203  							HostIP:        "127.0.0.1",
  1204  							HostPort:      5000,
  1205  							ContainerPort: 5000,
  1206  						}},
  1207  						Networks: map[string]types.PerNetworkOptions{
  1208  							defNet: {InterfaceName: intName},
  1209  						},
  1210  					},
  1211  				}
  1212  				_, err := libpodNet.Setup(netNSContainer.Path(), setupOpts)
  1213  				Expect(err).To(HaveOccurred())
  1214  				Expect(err.Error()).To(ContainSubstring("port protocol should not be empty"))
  1215  			})
  1216  		})
  1217  
  1218  		It("setup with unknown network", func() {
  1219  			runTest(func() {
  1220  				defNet := "somenet"
  1221  				intName := "eth0"
  1222  				setupOpts := types.SetupOptions{
  1223  					NetworkOptions: types.NetworkOptions{
  1224  						ContainerID: stringid.GenerateNonCryptoID(),
  1225  						Networks: map[string]types.PerNetworkOptions{
  1226  							defNet: {InterfaceName: intName},
  1227  						},
  1228  					},
  1229  				}
  1230  				_, err := libpodNet.Setup(netNSContainer.Path(), setupOpts)
  1231  				Expect(err).To(HaveOccurred())
  1232  				Expect(err.Error()).To(ContainSubstring("network somenet: network not found"))
  1233  			})
  1234  		})
  1235  
  1236  		It("teardown with unknown network", func() {
  1237  			runTest(func() {
  1238  				interfaceName := "eth0"
  1239  				netName := "somenet"
  1240  				teardownOpts := types.TeardownOptions{
  1241  					NetworkOptions: types.NetworkOptions{
  1242  						ContainerID: stringid.GenerateNonCryptoID(),
  1243  						Networks: map[string]types.PerNetworkOptions{
  1244  							netName: {
  1245  								InterfaceName: interfaceName,
  1246  							},
  1247  						},
  1248  					},
  1249  				}
  1250  
  1251  				err := libpodNet.Teardown(netNSContainer.Path(), teardownOpts)
  1252  				Expect(err).To(HaveOccurred())
  1253  				Expect(err.Error()).To(ContainSubstring("network somenet: network not found"))
  1254  				logString := logBuffer.String()
  1255  				Expect(logString).To(ContainSubstring("failed to load cached network config"))
  1256  			})
  1257  		})
  1258  
  1259  		It("teardown on not connected network", func() {
  1260  			runTest(func() {
  1261  				network := types.Network{}
  1262  				network1, err := libpodNet.NetworkCreate(network)
  1263  				Expect(err).To(BeNil())
  1264  
  1265  				interfaceName := "eth0"
  1266  				netName := network1.Name
  1267  				teardownOpts := types.TeardownOptions{
  1268  					NetworkOptions: types.NetworkOptions{
  1269  						ContainerID: stringid.GenerateNonCryptoID(),
  1270  						Networks: map[string]types.PerNetworkOptions{
  1271  							netName: {
  1272  								InterfaceName: interfaceName,
  1273  							},
  1274  						},
  1275  					},
  1276  				}
  1277  
  1278  				// Most CNI plugins do not error on teardown when there is nothing to do.
  1279  				err = libpodNet.Teardown(netNSContainer.Path(), teardownOpts)
  1280  				Expect(err).To(BeNil())
  1281  				logString := logBuffer.String()
  1282  				Expect(logString).To(ContainSubstring("failed to load cached network config"))
  1283  			})
  1284  		})
  1285  	})
  1286  })
  1287  
  1288  func runNetListener(wg *sync.WaitGroup, protocol, ip string, port int, expectedData string) {
  1289  	switch protocol {
  1290  	case "tcp":
  1291  		ln, err := net.Listen(protocol, net.JoinHostPort(ip, strconv.Itoa(port)))
  1292  		Expect(err).To(BeNil())
  1293  		// make sure to read in a separate goroutine to not block
  1294  		go func() {
  1295  			defer GinkgoRecover()
  1296  			defer wg.Done()
  1297  			conn, err := ln.Accept()
  1298  			Expect(err).To(BeNil())
  1299  			conn.SetDeadline(time.Now().Add(1 * time.Second))
  1300  			data, err := ioutil.ReadAll(conn)
  1301  			Expect(err).To(BeNil())
  1302  			Expect(string(data)).To(Equal(expectedData))
  1303  			conn.Close()
  1304  			ln.Close()
  1305  		}()
  1306  	case "udp":
  1307  		conn, err := net.ListenUDP("udp", &net.UDPAddr{
  1308  			IP:   net.ParseIP(ip),
  1309  			Port: port,
  1310  		})
  1311  		Expect(err).To(BeNil())
  1312  		conn.SetDeadline(time.Now().Add(1 * time.Second))
  1313  		go func() {
  1314  			defer GinkgoRecover()
  1315  			defer wg.Done()
  1316  			data := make([]byte, len(expectedData))
  1317  			i, err := conn.Read(data)
  1318  			Expect(err).To(BeNil())
  1319  			Expect(i).To(Equal(len(expectedData)))
  1320  			Expect(string(data)).To(Equal(expectedData))
  1321  			conn.Close()
  1322  		}()
  1323  	default:
  1324  		Fail("unsupported protocol")
  1325  	}
  1326  }