github.com/containers/podman/v4@v4.9.4/test/e2e/network_create_test.go (about)

     1  package integration
     2  
     3  import (
     4  	"encoding/json"
     5  	"net"
     6  
     7  	"github.com/containers/common/libnetwork/types"
     8  	. "github.com/containers/podman/v4/test/utils"
     9  	"github.com/containers/storage/pkg/stringid"
    10  	. "github.com/onsi/ginkgo/v2"
    11  	. "github.com/onsi/gomega"
    12  	. "github.com/onsi/gomega/gexec"
    13  )
    14  
    15  func removeNetworkDevice(name string) {
    16  	session := SystemExec("ip", []string{"link", "delete", name})
    17  	session.WaitWithDefaultTimeout()
    18  }
    19  
    20  var _ = Describe("Podman network create", func() {
    21  
    22  	It("podman network create with name and subnet", func() {
    23  		netName := "subnet-" + stringid.GenerateRandomID()
    24  		nc := podmanTest.Podman([]string{"network", "create", "--subnet", "10.11.12.0/24", "--ip-range", "10.11.12.0/26", netName})
    25  		nc.WaitWithDefaultTimeout()
    26  		defer podmanTest.removeNetwork(netName)
    27  		Expect(nc).Should(ExitCleanly())
    28  
    29  		// Inspect the network configuration
    30  		inspect := podmanTest.Podman([]string{"network", "inspect", netName})
    31  		inspect.WaitWithDefaultTimeout()
    32  		Expect(inspect).Should(ExitCleanly())
    33  
    34  		// JSON the network configuration into something usable
    35  		var results []types.Network
    36  		err := json.Unmarshal([]byte(inspect.OutputToString()), &results)
    37  		Expect(err).ToNot(HaveOccurred())
    38  		Expect(results).To(HaveLen(1))
    39  		result := results[0]
    40  		Expect(result).To(HaveField("Name", netName))
    41  		Expect(result.Subnets).To(HaveLen(1))
    42  		Expect(result.Subnets[0].Subnet.String()).To(Equal("10.11.12.0/24"))
    43  		Expect(result.Subnets[0].Gateway.String()).To(Equal("10.11.12.1"))
    44  		Expect(result.Subnets[0].LeaseRange).ToNot(BeNil())
    45  		Expect(result.Subnets[0].LeaseRange.StartIP.String()).To(Equal("10.11.12.1"))
    46  		Expect(result.Subnets[0].LeaseRange.EndIP.String()).To(Equal("10.11.12.63"))
    47  
    48  		// Once a container executes a new network, the nic will be created. We should clean those up
    49  		// best we can
    50  		defer removeNetworkDevice(result.NetworkInterface)
    51  
    52  		try := podmanTest.Podman([]string{"run", "--rm", "--network", netName, ALPINE, "sh", "-c", "ip addr show eth0 |  awk ' /inet / {print $2}'"})
    53  		try.WaitWithDefaultTimeout()
    54  		Expect(try).To(ExitCleanly())
    55  
    56  		_, subnet, err := net.ParseCIDR("10.11.12.0/24")
    57  		Expect(err).ToNot(HaveOccurred())
    58  		// Note this is an IPv4 test only!
    59  		containerIP, _, err := net.ParseCIDR(try.OutputToString())
    60  		Expect(err).ToNot(HaveOccurred())
    61  		// Ensure that the IP the container got is within the subnet the user asked for
    62  		Expect(subnet.Contains(containerIP)).To(BeTrue(), "subnet contains containerIP")
    63  	})
    64  
    65  	It("podman network create with name and subnet and static route", func() {
    66  		SkipIfCNI(podmanTest)
    67  		netName := "subnet-" + stringid.GenerateRandomID()
    68  		nc := podmanTest.Podman([]string{
    69  			"network",
    70  			"create",
    71  			"--subnet",
    72  			"10.19.12.0/24",
    73  			"--route",
    74  			"10.21.0.0/24,10.19.12.250",
    75  			netName,
    76  		})
    77  		nc.WaitWithDefaultTimeout()
    78  		defer podmanTest.removeNetwork(netName)
    79  		Expect(nc).Should(ExitCleanly())
    80  
    81  		// Inspect the network configuration
    82  		inspect := podmanTest.Podman([]string{"network", "inspect", netName})
    83  		inspect.WaitWithDefaultTimeout()
    84  		Expect(inspect).Should(ExitCleanly())
    85  
    86  		// JSON the network configuration into something usable
    87  		var results []types.Network
    88  		err := json.Unmarshal([]byte(inspect.OutputToString()), &results)
    89  		Expect(err).ToNot(HaveOccurred())
    90  		Expect(results).To(HaveLen(1))
    91  		result := results[0]
    92  		Expect(result).To(HaveField("Name", netName))
    93  		Expect(result.Subnets).To(HaveLen(1))
    94  		Expect(result.Subnets[0].Subnet.String()).To(Equal("10.19.12.0/24"))
    95  		Expect(result.Subnets[0].Gateway.String()).To(Equal("10.19.12.1"))
    96  		Expect(result.Routes[0].Destination.String()).To(Equal("10.21.0.0/24"))
    97  		Expect(result.Routes[0].Gateway.String()).To(Equal("10.19.12.250"))
    98  		Expect(result.Routes[0].Metric).To(BeNil())
    99  
   100  		// Once a container executes a new network, the nic will be created. We should clean those up
   101  		// best we can
   102  		defer removeNetworkDevice(result.NetworkInterface)
   103  
   104  	})
   105  
   106  	It("podman network create with name and subnet and static route and metric", func() {
   107  		SkipIfCNI(podmanTest)
   108  		netName := "subnet-" + stringid.GenerateRandomID()
   109  		nc := podmanTest.Podman([]string{
   110  			"network",
   111  			"create",
   112  			"--subnet",
   113  			"10.19.13.0/24",
   114  			"--route",
   115  			"10.21.1.0/24,10.19.13.250,120",
   116  			netName,
   117  		})
   118  		nc.WaitWithDefaultTimeout()
   119  		defer podmanTest.removeNetwork(netName)
   120  		Expect(nc).Should(ExitCleanly())
   121  
   122  		// Inspect the network configuration
   123  		inspect := podmanTest.Podman([]string{"network", "inspect", netName})
   124  		inspect.WaitWithDefaultTimeout()
   125  		Expect(inspect).Should(ExitCleanly())
   126  
   127  		// JSON the network configuration into something usable
   128  		var results []types.Network
   129  		err := json.Unmarshal([]byte(inspect.OutputToString()), &results)
   130  		Expect(err).ToNot(HaveOccurred())
   131  		Expect(results).To(HaveLen(1))
   132  		result := results[0]
   133  		Expect(result).To(HaveField("Name", netName))
   134  		Expect(result.Subnets).To(HaveLen(1))
   135  		Expect(result.Subnets[0].Subnet.String()).To(Equal("10.19.13.0/24"))
   136  		Expect(result.Subnets[0].Gateway.String()).To(Equal("10.19.13.1"))
   137  		Expect(result.Routes[0].Destination.String()).To(Equal("10.21.1.0/24"))
   138  		Expect(result.Routes[0].Gateway.String()).To(Equal("10.19.13.250"))
   139  		Expect(*result.Routes[0].Metric).To(Equal(uint32(120)))
   140  
   141  		// Once a container executes a new network, the nic will be created. We should clean those up
   142  		// best we can
   143  		defer removeNetworkDevice(result.NetworkInterface)
   144  
   145  	})
   146  
   147  	It("podman network create with name and subnet and two static routes", func() {
   148  		SkipIfCNI(podmanTest)
   149  		netName := "subnet-" + stringid.GenerateRandomID()
   150  		nc := podmanTest.Podman([]string{
   151  			"network",
   152  			"create",
   153  			"--subnet",
   154  			"10.19.14.0/24",
   155  			"--route",
   156  			"10.21.2.0/24,10.19.14.250",
   157  			"--route",
   158  			"10.21.3.0/24,10.19.14.251,120",
   159  			netName,
   160  		})
   161  		nc.WaitWithDefaultTimeout()
   162  		defer podmanTest.removeNetwork(netName)
   163  		Expect(nc).Should(ExitCleanly())
   164  
   165  		// Inspect the network configuration
   166  		inspect := podmanTest.Podman([]string{"network", "inspect", netName})
   167  		inspect.WaitWithDefaultTimeout()
   168  		Expect(inspect).Should(ExitCleanly())
   169  
   170  		// JSON the network configuration into something usable
   171  		var results []types.Network
   172  		err := json.Unmarshal([]byte(inspect.OutputToString()), &results)
   173  		Expect(err).ToNot(HaveOccurred())
   174  		Expect(results).To(HaveLen(1))
   175  		result := results[0]
   176  		Expect(result).To(HaveField("Name", netName))
   177  		Expect(result.Subnets).To(HaveLen(1))
   178  		Expect(result.Subnets[0].Subnet.String()).To(Equal("10.19.14.0/24"))
   179  		Expect(result.Subnets[0].Gateway.String()).To(Equal("10.19.14.1"))
   180  		Expect(result.Routes).To(HaveLen(2))
   181  		Expect(result.Routes[0].Destination.String()).To(Equal("10.21.2.0/24"))
   182  		Expect(result.Routes[0].Gateway.String()).To(Equal("10.19.14.250"))
   183  		Expect(result.Routes[0].Metric).To(BeNil())
   184  		Expect(result.Routes[1].Destination.String()).To(Equal("10.21.3.0/24"))
   185  		Expect(result.Routes[1].Gateway.String()).To(Equal("10.19.14.251"))
   186  		Expect(*result.Routes[1].Metric).To(Equal(uint32(120)))
   187  
   188  		// Once a container executes a new network, the nic will be created. We should clean those up
   189  		// best we can
   190  		defer removeNetworkDevice(result.NetworkInterface)
   191  
   192  	})
   193  
   194  	It("podman network create with name and subnet and static route (ipv6)", func() {
   195  		SkipIfCNI(podmanTest)
   196  		netName := "subnet-" + stringid.GenerateRandomID()
   197  		nc := podmanTest.Podman([]string{
   198  			"network",
   199  			"create",
   200  			"--subnet",
   201  			"fd:ab04::/64",
   202  			"--route",
   203  			"fd:1::/64,fd::1,120",
   204  			netName,
   205  		})
   206  		nc.WaitWithDefaultTimeout()
   207  		defer podmanTest.removeNetwork(netName)
   208  		Expect(nc).Should(ExitCleanly())
   209  
   210  		// Inspect the network configuration
   211  		inspect := podmanTest.Podman([]string{"network", "inspect", netName})
   212  		inspect.WaitWithDefaultTimeout()
   213  		Expect(inspect).Should(ExitCleanly())
   214  
   215  		// JSON the network configuration into something usable
   216  		var results []types.Network
   217  		err := json.Unmarshal([]byte(inspect.OutputToString()), &results)
   218  		Expect(err).ToNot(HaveOccurred())
   219  		Expect(results).To(HaveLen(1))
   220  		result := results[0]
   221  		Expect(result).To(HaveField("Name", netName))
   222  		Expect(result.Subnets).To(HaveLen(1))
   223  		Expect(result.Subnets[0].Subnet.String()).To(Equal("fd:ab04::/64"))
   224  		Expect(result.Subnets[0].Gateway.String()).To(Equal("fd:ab04::1"))
   225  		Expect(result.Routes[0].Destination.String()).To(Equal("fd:1::/64"))
   226  		Expect(result.Routes[0].Gateway.String()).To(Equal("fd::1"))
   227  		Expect(*result.Routes[0].Metric).To(Equal(uint32(120)))
   228  
   229  		// Once a container executes a new network, the nic will be created. We should clean those up
   230  		// best we can
   231  		defer removeNetworkDevice(result.NetworkInterface)
   232  
   233  	})
   234  
   235  	It("podman network create with name and subnet with --opt no_default_route=1", func() {
   236  		SkipIfCNI(podmanTest)
   237  		netName := "subnet-" + stringid.GenerateRandomID()
   238  		nc := podmanTest.Podman([]string{
   239  			"network",
   240  			"create",
   241  			"--subnet",
   242  			"10.19.15.0/24",
   243  			"--opt",
   244  			"no_default_route=1",
   245  			netName,
   246  		})
   247  		nc.WaitWithDefaultTimeout()
   248  		defer podmanTest.removeNetwork(netName)
   249  		Expect(nc).Should(ExitCleanly())
   250  
   251  		// Inspect the network configuration
   252  		inspect := podmanTest.Podman([]string{"network", "inspect", netName})
   253  		inspect.WaitWithDefaultTimeout()
   254  		Expect(inspect).Should(ExitCleanly())
   255  
   256  		// JSON the network configuration into something usable
   257  		var results []types.Network
   258  		err := json.Unmarshal([]byte(inspect.OutputToString()), &results)
   259  		Expect(err).ToNot(HaveOccurred())
   260  		Expect(results).To(HaveLen(1))
   261  		result := results[0]
   262  		Expect(result).To(HaveField("Name", netName))
   263  		Expect(result.Subnets).To(HaveLen(1))
   264  		Expect(result.Subnets[0].Subnet.String()).To(Equal("10.19.15.0/24"))
   265  		Expect(result.Subnets[0].Gateway.String()).To(Equal("10.19.15.1"))
   266  		Expect(result.Options[types.NoDefaultRoute]).To(Equal("true"))
   267  
   268  		// Once a container executes a new network, the nic will be created. We should clean those up
   269  		// best we can
   270  		defer removeNetworkDevice(result.NetworkInterface)
   271  
   272  	})
   273  
   274  	It("podman network create with name and IPv6 subnet", func() {
   275  		netName := "ipv6-" + stringid.GenerateRandomID()
   276  		nc := podmanTest.Podman([]string{"network", "create", "--subnet", "fd00:1:2:3:4::/64", netName})
   277  		nc.WaitWithDefaultTimeout()
   278  		defer podmanTest.removeNetwork(netName)
   279  		Expect(nc).Should(ExitCleanly())
   280  
   281  		// Inspect the network configuration
   282  		inspect := podmanTest.Podman([]string{"network", "inspect", netName})
   283  		inspect.WaitWithDefaultTimeout()
   284  		Expect(inspect).Should(ExitCleanly())
   285  
   286  		// JSON the network configuration into something usable
   287  		var results []types.Network
   288  		err := json.Unmarshal([]byte(inspect.OutputToString()), &results)
   289  		Expect(err).ToNot(HaveOccurred())
   290  		Expect(results).To(HaveLen(1))
   291  		result := results[0]
   292  		Expect(result).To(HaveField("Name", netName))
   293  		Expect(result.Subnets).To(HaveLen(1))
   294  		Expect(result.Subnets[0].Gateway.String()).To(Equal("fd00:1:2:3::1"))
   295  		Expect(result.Subnets[0].Subnet.String()).To(Equal("fd00:1:2:3::/64"))
   296  
   297  		// Once a container executes a new network, the nic will be created. We should clean those up
   298  		// best we can
   299  		defer removeNetworkDevice(result.NetworkInterface)
   300  
   301  		try := podmanTest.Podman([]string{"run", "--rm", "--network", netName, ALPINE, "sh", "-c", "ip addr show eth0 |  grep global | awk ' /inet6 / {print $2}'"})
   302  		try.WaitWithDefaultTimeout()
   303  		Expect(try).To(ExitCleanly())
   304  
   305  		_, subnet, err := net.ParseCIDR("fd00:1:2:3:4::/64")
   306  		Expect(err).ToNot(HaveOccurred())
   307  		containerIP, _, err := net.ParseCIDR(try.OutputToString())
   308  		Expect(err).ToNot(HaveOccurred())
   309  		// Ensure that the IP the container got is within the subnet the user asked for
   310  		Expect(subnet.Contains(containerIP)).To(BeTrue(), "subnet contains containerIP")
   311  	})
   312  
   313  	It("podman network create with name and IPv6 flag (dual-stack)", func() {
   314  		netName := "dual-" + stringid.GenerateRandomID()
   315  		nc := podmanTest.Podman([]string{"network", "create", "--subnet", "fd00:4:3:2::/64", "--ipv6", netName})
   316  		nc.WaitWithDefaultTimeout()
   317  		defer podmanTest.removeNetwork(netName)
   318  		Expect(nc).Should(ExitCleanly())
   319  
   320  		// Inspect the network configuration
   321  		inspect := podmanTest.Podman([]string{"network", "inspect", netName})
   322  		inspect.WaitWithDefaultTimeout()
   323  		Expect(inspect).Should(ExitCleanly())
   324  
   325  		// JSON the network configuration into something usable
   326  		var results []types.Network
   327  		err := json.Unmarshal([]byte(inspect.OutputToString()), &results)
   328  		Expect(err).ToNot(HaveOccurred())
   329  		Expect(results).To(HaveLen(1))
   330  		result := results[0]
   331  		Expect(result).To(HaveField("Name", netName))
   332  		Expect(result.Subnets).To(HaveLen(2))
   333  		Expect(result.Subnets[0].Subnet.IP).ToNot(BeNil())
   334  		Expect(result.Subnets[1].Subnet.IP).ToNot(BeNil())
   335  
   336  		_, subnet11, err := net.ParseCIDR(result.Subnets[0].Subnet.String())
   337  		Expect(err).ToNot(HaveOccurred())
   338  		_, subnet12, err := net.ParseCIDR(result.Subnets[1].Subnet.String())
   339  		Expect(err).ToNot(HaveOccurred())
   340  
   341  		// Once a container executes a new network, the nic will be created. We should clean those up
   342  		// best we can
   343  		defer removeNetworkDevice(result.NetworkInterface)
   344  
   345  		// create a second network to check the auto assigned ipv4 subnet does not overlap
   346  		// https://github.com/containers/podman/issues/11032
   347  		netName2 := "dual-" + stringid.GenerateRandomID()
   348  		nc = podmanTest.Podman([]string{"network", "create", "--subnet", "fd00:10:3:2::/64", "--ipv6", netName2})
   349  		nc.WaitWithDefaultTimeout()
   350  		defer podmanTest.removeNetwork(netName2)
   351  		Expect(nc).Should(ExitCleanly())
   352  
   353  		// Inspect the network configuration
   354  		inspect = podmanTest.Podman([]string{"network", "inspect", netName2})
   355  		inspect.WaitWithDefaultTimeout()
   356  		Expect(inspect).Should(ExitCleanly())
   357  
   358  		// JSON the network configuration into something usable
   359  		err = json.Unmarshal([]byte(inspect.OutputToString()), &results)
   360  		Expect(err).ToNot(HaveOccurred())
   361  		Expect(results).To(HaveLen(1))
   362  		result = results[0]
   363  		Expect(result).To(HaveField("Name", netName2))
   364  		Expect(result.Subnets).To(HaveLen(2))
   365  		Expect(result.Subnets[0].Subnet.IP).ToNot(BeNil())
   366  		Expect(result.Subnets[1].Subnet.IP).ToNot(BeNil())
   367  
   368  		_, subnet21, err := net.ParseCIDR(result.Subnets[0].Subnet.String())
   369  		Expect(err).ToNot(HaveOccurred())
   370  		_, subnet22, err := net.ParseCIDR(result.Subnets[1].Subnet.String())
   371  		Expect(err).ToNot(HaveOccurred())
   372  
   373  		// check that the subnets do not overlap
   374  		Expect(subnet11.Contains(subnet21.IP)).To(BeFalse())
   375  		Expect(subnet12.Contains(subnet22.IP)).To(BeFalse())
   376  
   377  		try := podmanTest.Podman([]string{"run", "--rm", "--network", netName, ALPINE, "sh", "-c", "ip addr show eth0 |  grep global | awk ' /inet6 / {print $2}'"})
   378  		try.WaitWithDefaultTimeout()
   379  
   380  		_, subnet, err := net.ParseCIDR("fd00:4:3:2:1::/64")
   381  		Expect(err).ToNot(HaveOccurred())
   382  		containerIP, _, err := net.ParseCIDR(try.OutputToString())
   383  		Expect(err).ToNot(HaveOccurred())
   384  		// Ensure that the IP the container got is within the subnet the user asked for
   385  		Expect(subnet.Contains(containerIP)).To(BeTrue(), "subnet contains containerIP")
   386  		// verify the container has an IPv4 address too (the IPv4 subnet is autogenerated)
   387  		try = podmanTest.Podman([]string{"run", "--rm", "--network", netName, ALPINE, "sh", "-c", "ip addr show eth0 |  awk ' /inet / {print $2}'"})
   388  		try.WaitWithDefaultTimeout()
   389  		containerIP, _, err = net.ParseCIDR(try.OutputToString())
   390  		Expect(err).ToNot(HaveOccurred())
   391  		Expect(containerIP.To4()).To(Not(BeNil()))
   392  	})
   393  
   394  	It("podman network create with invalid subnet", func() {
   395  		nc := podmanTest.Podman([]string{"network", "create", "--subnet", "10.11.12.0/17000", stringid.GenerateRandomID()})
   396  		nc.WaitWithDefaultTimeout()
   397  		Expect(nc).To(ExitWithError())
   398  	})
   399  
   400  	It("podman network create with ipv4 subnet and ipv6 flag", func() {
   401  		name := stringid.GenerateRandomID()
   402  		nc := podmanTest.Podman([]string{"network", "create", "--subnet", "10.11.14.0/24", "--ipv6", name})
   403  		nc.WaitWithDefaultTimeout()
   404  		Expect(nc).To(ExitCleanly())
   405  		defer podmanTest.removeNetwork(name)
   406  
   407  		nc = podmanTest.Podman([]string{"network", "inspect", name})
   408  		nc.WaitWithDefaultTimeout()
   409  		Expect(nc).To(ExitCleanly())
   410  		Expect(nc.OutputToString()).To(ContainSubstring(`::/64`))
   411  		Expect(nc.OutputToString()).To(ContainSubstring(`10.11.14.0/24`))
   412  	})
   413  
   414  	It("podman network create with empty subnet and ipv6 flag", func() {
   415  		name := stringid.GenerateRandomID()
   416  		nc := podmanTest.Podman([]string{"network", "create", "--ipv6", name})
   417  		nc.WaitWithDefaultTimeout()
   418  		Expect(nc).To(ExitCleanly())
   419  		defer podmanTest.removeNetwork(name)
   420  
   421  		nc = podmanTest.Podman([]string{"network", "inspect", name})
   422  		nc.WaitWithDefaultTimeout()
   423  		Expect(nc).To(ExitCleanly())
   424  		Expect(nc.OutputToString()).To(ContainSubstring(`::/64`))
   425  		Expect(nc.OutputToString()).To(ContainSubstring(`.0/24`))
   426  	})
   427  
   428  	It("podman network create with invalid IP", func() {
   429  		nc := podmanTest.Podman([]string{"network", "create", "--subnet", "10.11.0/17000", stringid.GenerateRandomID()})
   430  		nc.WaitWithDefaultTimeout()
   431  		Expect(nc).To(ExitWithError())
   432  	})
   433  
   434  	It("podman network create with invalid gateway for subnet", func() {
   435  		nc := podmanTest.Podman([]string{"network", "create", "--subnet", "10.11.12.0/24", "--gateway", "192.168.1.1", stringid.GenerateRandomID()})
   436  		nc.WaitWithDefaultTimeout()
   437  		Expect(nc).To(ExitWithError())
   438  	})
   439  
   440  	It("podman network create two networks with same name should fail", func() {
   441  		netName := "same-" + stringid.GenerateRandomID()
   442  		nc := podmanTest.Podman([]string{"network", "create", netName})
   443  		nc.WaitWithDefaultTimeout()
   444  		defer podmanTest.removeNetwork(netName)
   445  		Expect(nc).Should(ExitCleanly())
   446  
   447  		ncFail := podmanTest.Podman([]string{"network", "create", netName})
   448  		ncFail.WaitWithDefaultTimeout()
   449  		Expect(ncFail).To(ExitWithError())
   450  	})
   451  
   452  	It("podman network create two networks with same subnet should fail", func() {
   453  		netName1 := "sub1-" + stringid.GenerateRandomID()
   454  		nc := podmanTest.Podman([]string{"network", "create", "--subnet", "10.11.13.0/24", netName1})
   455  		nc.WaitWithDefaultTimeout()
   456  		defer podmanTest.removeNetwork(netName1)
   457  		Expect(nc).Should(ExitCleanly())
   458  
   459  		netName2 := "sub2-" + stringid.GenerateRandomID()
   460  		ncFail := podmanTest.Podman([]string{"network", "create", "--subnet", "10.11.13.0/24", netName2})
   461  		ncFail.WaitWithDefaultTimeout()
   462  		defer podmanTest.removeNetwork(netName2)
   463  		Expect(ncFail).To(ExitWithError())
   464  	})
   465  
   466  	It("podman network create two IPv6 networks with same subnet should fail", func() {
   467  		netName1 := "subipv61-" + stringid.GenerateRandomID()
   468  		nc := podmanTest.Podman([]string{"network", "create", "--subnet", "fd00:4:4:4:4::/64", "--ipv6", netName1})
   469  		nc.WaitWithDefaultTimeout()
   470  		defer podmanTest.removeNetwork(netName1)
   471  		Expect(nc).Should(ExitCleanly())
   472  
   473  		netName2 := "subipv62-" + stringid.GenerateRandomID()
   474  		ncFail := podmanTest.Podman([]string{"network", "create", "--subnet", "fd00:4:4:4:4::/64", "--ipv6", netName2})
   475  		ncFail.WaitWithDefaultTimeout()
   476  		defer podmanTest.removeNetwork(netName2)
   477  		Expect(ncFail).To(ExitWithError())
   478  	})
   479  
   480  	It("podman network create with invalid network name", func() {
   481  		nc := podmanTest.Podman([]string{"network", "create", "foo "})
   482  		nc.WaitWithDefaultTimeout()
   483  		Expect(nc).To(ExitWithError())
   484  	})
   485  
   486  	It("podman network create with mtu option", func() {
   487  		net := "mtu-test" + stringid.GenerateRandomID()
   488  		nc := podmanTest.Podman([]string{"network", "create", "--opt", "mtu=9000", net})
   489  		nc.WaitWithDefaultTimeout()
   490  		defer podmanTest.removeNetwork(net)
   491  		Expect(nc).Should(ExitCleanly())
   492  
   493  		nc = podmanTest.Podman([]string{"network", "inspect", net})
   494  		nc.WaitWithDefaultTimeout()
   495  		Expect(nc).Should(ExitCleanly())
   496  		Expect(nc.OutputToString()).To(ContainSubstring(`"mtu": "9000"`))
   497  	})
   498  
   499  	It("podman network create with vlan option", func() {
   500  		net := "vlan-test" + stringid.GenerateRandomID()
   501  		nc := podmanTest.Podman([]string{"network", "create", "--opt", "vlan=9", net})
   502  		nc.WaitWithDefaultTimeout()
   503  		defer podmanTest.removeNetwork(net)
   504  		Expect(nc).Should(ExitCleanly())
   505  
   506  		nc = podmanTest.Podman([]string{"network", "inspect", net})
   507  		nc.WaitWithDefaultTimeout()
   508  		Expect(nc).Should(ExitCleanly())
   509  		Expect(nc.OutputToString()).To(ContainSubstring(`"vlan": "9"`))
   510  	})
   511  
   512  	It("podman network create with invalid option", func() {
   513  		net := "invalid-test" + stringid.GenerateRandomID()
   514  		nc := podmanTest.Podman([]string{"network", "create", "--opt", "foo=bar", net})
   515  		nc.WaitWithDefaultTimeout()
   516  		defer podmanTest.removeNetwork(net)
   517  		Expect(nc).To(ExitWithError())
   518  	})
   519  
   520  	It("podman CNI network create with internal should not have dnsname", func() {
   521  		SkipIfNetavark(podmanTest)
   522  		net := "internal-test" + stringid.GenerateRandomID()
   523  		nc := podmanTest.Podman([]string{"network", "create", "--internal", net})
   524  		nc.WaitWithDefaultTimeout()
   525  		defer podmanTest.removeNetwork(net)
   526  		// Cannot ExitCleanly(): "dnsname and internal networks are incompatible"
   527  		Expect(nc).Should(Exit(0))
   528  		// Not performing this check on remote tests because it is a logrus error which does
   529  		// not come back via stderr on the remote client.
   530  		if !IsRemote() {
   531  			Expect(nc.ErrorToString()).To(ContainSubstring("dnsname and internal networks are incompatible"))
   532  		}
   533  		nc = podmanTest.Podman([]string{"network", "inspect", net})
   534  		nc.WaitWithDefaultTimeout()
   535  		Expect(nc).Should(ExitCleanly())
   536  		Expect(nc.OutputToString()).ToNot(ContainSubstring("dnsname"))
   537  	})
   538  
   539  	It("podman Netavark network create with internal should have dnsname", func() {
   540  		SkipIfCNI(podmanTest)
   541  		net := "internal-test" + stringid.GenerateRandomID()
   542  		nc := podmanTest.Podman([]string{"network", "create", "--internal", net})
   543  		nc.WaitWithDefaultTimeout()
   544  		defer podmanTest.removeNetwork(net)
   545  		Expect(nc).Should(ExitCleanly())
   546  		// Not performing this check on remote tests because it is a logrus error which does
   547  		// not come back via stderr on the remote client.
   548  		if !IsRemote() {
   549  			Expect(nc.ErrorToString()).To(BeEmpty())
   550  		}
   551  		nc = podmanTest.Podman([]string{"network", "inspect", net})
   552  		nc.WaitWithDefaultTimeout()
   553  		Expect(nc).Should(ExitCleanly())
   554  		Expect(nc.OutputToString()).To(ContainSubstring(`"dns_enabled": true`))
   555  	})
   556  
   557  	It("podman network create with invalid name", func() {
   558  		for _, name := range []string{"none", "host", "bridge", "private", "slirp4netns", "container", "ns", "default"} {
   559  			nc := podmanTest.Podman([]string{"network", "create", name})
   560  			nc.WaitWithDefaultTimeout()
   561  			Expect(nc).To(Exit(125))
   562  			Expect(nc.ErrorToString()).To(ContainSubstring("cannot create network with name %q because it conflicts with a valid network mode", name))
   563  		}
   564  	})
   565  
   566  	It("podman network create with multiple subnets", func() {
   567  		name := "subnets-" + stringid.GenerateRandomID()
   568  		subnet1 := "10.10.0.0/24"
   569  		subnet2 := "10.10.1.0/24"
   570  		nc := podmanTest.Podman([]string{"network", "create", "--subnet", subnet1, "--subnet", subnet2, name})
   571  		nc.WaitWithDefaultTimeout()
   572  		defer podmanTest.removeNetwork(name)
   573  		Expect(nc).To(ExitCleanly())
   574  		Expect(nc.OutputToString()).To(Equal(name))
   575  
   576  		inspect := podmanTest.Podman([]string{"network", "inspect", name})
   577  		inspect.WaitWithDefaultTimeout()
   578  		Expect(inspect).To(ExitCleanly())
   579  		Expect(inspect.OutputToString()).To(ContainSubstring(`"subnet": "` + subnet1))
   580  		Expect(inspect.OutputToString()).To(ContainSubstring(`"subnet": "` + subnet2))
   581  		Expect(inspect.OutputToString()).To(ContainSubstring(`"ipv6_enabled": false`))
   582  	})
   583  
   584  	It("podman network create with multiple subnets dual stack", func() {
   585  		name := "subnets-" + stringid.GenerateRandomID()
   586  		subnet1 := "10.10.2.0/24"
   587  		subnet2 := "fd52:2a5a:747e:3acd::/64"
   588  		nc := podmanTest.Podman([]string{"network", "create", "--subnet", subnet1, "--subnet", subnet2, name})
   589  		nc.WaitWithDefaultTimeout()
   590  		defer podmanTest.removeNetwork(name)
   591  		Expect(nc).To(ExitCleanly())
   592  		Expect(nc.OutputToString()).To(Equal(name))
   593  
   594  		inspect := podmanTest.Podman([]string{"network", "inspect", name})
   595  		inspect.WaitWithDefaultTimeout()
   596  		Expect(inspect).To(ExitCleanly())
   597  		Expect(inspect.OutputToString()).To(ContainSubstring(`"subnet": "` + subnet1))
   598  		Expect(inspect.OutputToString()).To(ContainSubstring(`"subnet": "` + subnet2))
   599  		Expect(inspect.OutputToString()).To(ContainSubstring(`"ipv6_enabled": true`))
   600  	})
   601  
   602  	It("podman network create with multiple subnets dual stack with gateway and range", func() {
   603  		name := "subnets-" + stringid.GenerateRandomID()
   604  		subnet1 := "10.10.3.0/24"
   605  		gw1 := "10.10.3.10"
   606  		range1 := "10.10.3.0/26"
   607  		subnet2 := "fd52:2a5a:747e:3ace::/64"
   608  		gw2 := "fd52:2a5a:747e:3ace::10"
   609  		nc := podmanTest.Podman([]string{"network", "create", "--subnet", subnet1, "--gateway", gw1, "--ip-range", range1, "--subnet", subnet2, "--gateway", gw2, name})
   610  		nc.WaitWithDefaultTimeout()
   611  		defer podmanTest.removeNetwork(name)
   612  		Expect(nc).To(ExitCleanly())
   613  		Expect(nc.OutputToString()).To(Equal(name))
   614  
   615  		inspect := podmanTest.Podman([]string{"network", "inspect", name})
   616  		inspect.WaitWithDefaultTimeout()
   617  		Expect(inspect).To(ExitCleanly())
   618  		Expect(inspect.OutputToString()).To(ContainSubstring(`"subnet": "` + subnet1))
   619  		Expect(inspect.OutputToString()).To(ContainSubstring(`"gateway": "` + gw1))
   620  		Expect(inspect.OutputToString()).To(ContainSubstring(`"start_ip": "10.10.3.1",`))
   621  		Expect(inspect.OutputToString()).To(ContainSubstring(`"end_ip": "10.10.3.63"`))
   622  		Expect(inspect.OutputToString()).To(ContainSubstring(`"subnet": "` + subnet2))
   623  		Expect(inspect.OutputToString()).To(ContainSubstring(`"gateway": "` + gw2))
   624  		Expect(inspect.OutputToString()).To(ContainSubstring(`"ipv6_enabled": true`))
   625  	})
   626  
   627  	It("podman network create invalid options with multiple subnets", func() {
   628  		name := "subnets-" + stringid.GenerateRandomID()
   629  		subnet1 := "10.10.3.0/24"
   630  		gw1 := "10.10.3.10"
   631  		gw2 := "fd52:2a5a:747e:3acf::10"
   632  		nc := podmanTest.Podman([]string{"network", "create", "--subnet", subnet1, "--gateway", gw1, "--gateway", gw2, name})
   633  		nc.WaitWithDefaultTimeout()
   634  		Expect(nc).To(Exit(125))
   635  		Expect(nc.ErrorToString()).To(Equal("Error: cannot set more gateways than subnets"))
   636  
   637  		range1 := "10.10.3.0/26"
   638  		range2 := "10.10.3.0/28"
   639  		nc = podmanTest.Podman([]string{"network", "create", "--subnet", subnet1, "--ip-range", range1, "--ip-range", range2, name})
   640  		nc.WaitWithDefaultTimeout()
   641  		Expect(nc).To(Exit(125))
   642  		Expect(nc.ErrorToString()).To(Equal("Error: cannot set more ranges than subnets"))
   643  	})
   644  
   645  	It("podman network create same name - fail", func() {
   646  		name := "same-name-" + stringid.GenerateRandomID()
   647  		networkCreateCommand := []string{"network", "create", name}
   648  		nc := podmanTest.Podman(networkCreateCommand)
   649  		nc.WaitWithDefaultTimeout()
   650  		defer podmanTest.removeNetwork(name)
   651  		Expect(nc).To(ExitCleanly())
   652  		Expect(nc.OutputToString()).To(Equal(name))
   653  
   654  		nc = podmanTest.Podman(networkCreateCommand)
   655  		nc.WaitWithDefaultTimeout()
   656  		Expect(nc).To(Exit(125))
   657  	})
   658  
   659  	It("podman network create same name - succeed with ignore", func() {
   660  		name := "same-name-" + stringid.GenerateRandomID()
   661  		networkCreateCommand := []string{"network", "create", "--ignore", name}
   662  		nc := podmanTest.Podman(networkCreateCommand)
   663  		nc.WaitWithDefaultTimeout()
   664  		defer podmanTest.removeNetwork(name)
   665  		Expect(nc).To(ExitCleanly())
   666  		Expect(nc.OutputToString()).To(Equal(name))
   667  
   668  		nc = podmanTest.Podman(networkCreateCommand)
   669  		nc.WaitWithDefaultTimeout()
   670  		Expect(nc).To(ExitCleanly())
   671  		Expect(nc.OutputToString()).To(Equal(name))
   672  	})
   673  
   674  	It("podman network create --interface-name", func() {
   675  		netName := "bridge-" + stringid.GenerateRandomID()
   676  		bridgeName := "mybridge" + stringid.GenerateRandomID()[:4]
   677  		nc := podmanTest.Podman([]string{"network", "create", "--interface-name", bridgeName, netName})
   678  		nc.WaitWithDefaultTimeout()
   679  		defer podmanTest.removeNetwork(netName)
   680  		Expect(nc).To(ExitCleanly())
   681  		Expect(nc.OutputToString()).To(Equal(netName))
   682  
   683  		session := podmanTest.Podman([]string{"network", "inspect", "--format", "{{.NetworkInterface}}", netName})
   684  		session.WaitWithDefaultTimeout()
   685  		Expect(session).To(ExitCleanly())
   686  		Expect(session.OutputToString()).To(Equal(bridgeName))
   687  
   688  		session = podmanTest.Podman([]string{"run", "-d", "--network", netName, ALPINE, "top"})
   689  		session.WaitWithDefaultTimeout()
   690  		Expect(session).To(ExitCleanly())
   691  
   692  		// can only check this as root
   693  		if !isRootless() {
   694  			// make sure cni/netavark created bridge with expected name
   695  			bridge, err := net.InterfaceByName(bridgeName)
   696  			Expect(err).ToNot(HaveOccurred())
   697  			Expect(bridge.Name).To(Equal(bridgeName))
   698  		}
   699  	})
   700  
   701  	It("podman network create --ip-range sip-eip", func() {
   702  		netName := "subnet-" + stringid.GenerateRandomID()
   703  		nc := podmanTest.Podman([]string{"network", "create", "--subnet", "10.11.16.0/24", "--ip-range", "10.11.16.11-10.11.16.12", netName})
   704  		nc.WaitWithDefaultTimeout()
   705  		defer podmanTest.removeNetwork(netName)
   706  		Expect(nc).Should(ExitCleanly())
   707  
   708  		// Inspect the network configuration
   709  		inspect := podmanTest.Podman([]string{"network", "inspect", netName})
   710  		inspect.WaitWithDefaultTimeout()
   711  		Expect(inspect).Should(ExitCleanly())
   712  
   713  		// JSON the network configuration into something usable
   714  		var results []types.Network
   715  		err := json.Unmarshal([]byte(inspect.OutputToString()), &results)
   716  		Expect(err).ToNot(HaveOccurred())
   717  		Expect(results).To(HaveLen(1))
   718  		result := results[0]
   719  		Expect(result).To(HaveField("Name", netName))
   720  		Expect(result.Subnets).To(HaveLen(1))
   721  		Expect(result.Subnets[0].Subnet.String()).To(Equal("10.11.16.0/24"))
   722  		Expect(result.Subnets[0].Gateway.String()).To(Equal("10.11.16.1"))
   723  		Expect(result.Subnets[0].LeaseRange).ToNot(BeNil())
   724  		Expect(result.Subnets[0].LeaseRange.StartIP.String()).To(Equal("10.11.16.11"))
   725  		Expect(result.Subnets[0].LeaseRange.EndIP.String()).To(Equal("10.11.16.12"))
   726  
   727  		try := podmanTest.Podman([]string{"run", "--rm", "--network", netName, ALPINE, "sh", "-c", "ip addr show eth0 |  awk ' /inet / {print $2}'"})
   728  		try.WaitWithDefaultTimeout()
   729  		Expect(try).To(ExitCleanly())
   730  
   731  		containerIP, _, err := net.ParseCIDR(try.OutputToString())
   732  		Expect(err).ToNot(HaveOccurred())
   733  		// Note as of today (June 2023) we always get the first ip from netavark and cni but let's not depend on that.
   734  		// All we care about is the ip is from the range which allows for both.
   735  		Expect(containerIP.String()).To(Or(Equal("10.11.16.11"), Equal("10.11.16.12")), "ip address must be in --ip-range")
   736  	})
   737  })