summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntonio Ojea <aojea@redhat.com>2020-08-14 11:19:02 +0200
committerMatthew Heon <matthew.heon@pm.me>2020-08-20 12:16:52 -0400
commit5e50ba3ecbdd738679849d7a86fef0c4ab7f109d (patch)
tree54eddc9445475aa12d8177f2a294dca563f56164
parent386de7a1fbfef0c266e04f6471f9382a5d39a02f (diff)
downloadpodman-5e50ba3ecbdd738679849d7a86fef0c4ab7f109d.tar.gz
podman-5e50ba3ecbdd738679849d7a86fef0c4ab7f109d.tar.bz2
podman-5e50ba3ecbdd738679849d7a86fef0c4ab7f109d.zip
podman support for IPv6 networks
podman containers using IPv6 were missing the default route, breaking deployments trying to use them. The problem is that the default route was hardcoded to IPv4, this takes into consideration the podman subnet IP family to generate the corresponding default route. Signed-off-by: Antonio Ojea <aojea@redhat.com>
-rw-r--r--pkg/domain/infra/abi/network.go2
-rw-r--r--pkg/network/ip.go5
-rw-r--r--pkg/network/netconflist.go15
-rw-r--r--pkg/network/netconflist_test.go38
-rw-r--r--test/e2e/network_create_test.go41
5 files changed, 97 insertions, 4 deletions
diff --git a/pkg/domain/infra/abi/network.go b/pkg/domain/infra/abi/network.go
index 26383129c..fd63fc80f 100644
--- a/pkg/domain/infra/abi/network.go
+++ b/pkg/domain/infra/abi/network.go
@@ -191,7 +191,7 @@ func createBridge(r *libpod.Runtime, name string, options entities.NetworkCreate
var plugins []network.CNIPlugins
var routes []network.IPAMRoute
- defaultRoute, err := network.NewIPAMDefaultRoute()
+ defaultRoute, err := network.NewIPAMDefaultRoute(network.IsIPv6(subnet.IP))
if err != nil {
return "", err
}
diff --git a/pkg/network/ip.go b/pkg/network/ip.go
index 1798cd939..ba93a0d05 100644
--- a/pkg/network/ip.go
+++ b/pkg/network/ip.go
@@ -12,3 +12,8 @@ func CalcGatewayIP(ipn *net.IPNet) net.IP {
nid := ipn.IP.Mask(ipn.Mask)
return ip.NextIP(nid)
}
+
+// IsIPv6 returns if netIP is IPv6.
+func IsIPv6(netIP net.IP) bool {
+ return netIP != nil && netIP.To4() == nil
+}
diff --git a/pkg/network/netconflist.go b/pkg/network/netconflist.go
index 4271d3f54..8187fdb39 100644
--- a/pkg/network/netconflist.go
+++ b/pkg/network/netconflist.go
@@ -6,6 +6,11 @@ import (
"path/filepath"
)
+const (
+ defaultIPv4Route = "0.0.0.0/0"
+ defaultIPv6Route = "::/0"
+)
+
// NcList describes a generic map
type NcList map[string]interface{}
@@ -86,9 +91,13 @@ func NewIPAMRoute(r *net.IPNet) IPAMRoute { //nolint:interfacer
}
// NewIPAMDefaultRoute creates a new IPAMDefault route of
-// 0.0.0.0/0
-func NewIPAMDefaultRoute() (IPAMRoute, error) {
- _, n, err := net.ParseCIDR("0.0.0.0/0")
+// 0.0.0.0/0 for IPv4 or ::/0 for IPv6
+func NewIPAMDefaultRoute(isIPv6 bool) (IPAMRoute, error) {
+ route := defaultIPv4Route
+ if isIPv6 {
+ route = defaultIPv6Route
+ }
+ _, n, err := net.ParseCIDR(route)
if err != nil {
return IPAMRoute{}, err
}
diff --git a/pkg/network/netconflist_test.go b/pkg/network/netconflist_test.go
new file mode 100644
index 000000000..a82a0140a
--- /dev/null
+++ b/pkg/network/netconflist_test.go
@@ -0,0 +1,38 @@
+package network
+
+import (
+ "reflect"
+ "testing"
+)
+
+func TestNewIPAMDefaultRoute(t *testing.T) {
+
+ tests := []struct {
+ name string
+ isIPv6 bool
+ want IPAMRoute
+ }{
+ {
+ name: "IPv4 default route",
+ isIPv6: false,
+ want: IPAMRoute{defaultIPv4Route},
+ },
+ {
+ name: "IPv6 default route",
+ isIPv6: true,
+ want: IPAMRoute{defaultIPv6Route},
+ },
+ }
+ for _, tt := range tests {
+ tt := tt
+ t.Run(tt.name, func(t *testing.T) {
+ got, err := NewIPAMDefaultRoute(tt.isIPv6)
+ if err != nil {
+ t.Errorf("no errorr expected: %v", err)
+ }
+ if !reflect.DeepEqual(got, tt.want) {
+ t.Errorf("NewIPAMDefaultRoute() = %v, want %v", got, tt.want)
+ }
+ })
+ }
+}
diff --git a/test/e2e/network_create_test.go b/test/e2e/network_create_test.go
index a69004208..f635f3c6c 100644
--- a/test/e2e/network_create_test.go
+++ b/test/e2e/network_create_test.go
@@ -179,6 +179,47 @@ var _ = Describe("Podman network create", func() {
Expect(subnet.Contains(containerIP)).To(BeTrue())
})
+ It("podman network create with name and IPv6 subnet", func() {
+ SkipIfRemote()
+ var (
+ results []network.NcList
+ )
+ nc := podmanTest.Podman([]string{"network", "create", "--subnet", "fd00:1:2:3:4::/64", "newIPv6network"})
+ nc.WaitWithDefaultTimeout()
+ Expect(nc.ExitCode()).To(BeZero())
+
+ defer podmanTest.removeCNINetwork("newIPv6network")
+
+ // Inspect the network configuration
+ inspect := podmanTest.Podman([]string{"network", "inspect", "newIPv6network"})
+ inspect.WaitWithDefaultTimeout()
+
+ // JSON the network configuration into something usable
+ err := json.Unmarshal([]byte(inspect.OutputToString()), &results)
+ Expect(err).To(BeNil())
+ result := results[0]
+ Expect(result["name"]).To(Equal("newIPv6network"))
+
+ // JSON the bridge info
+ bridgePlugin, err := genericPluginsToBridge(result["plugins"], "bridge")
+ Expect(err).To(BeNil())
+ Expect(bridgePlugin.IPAM.Routes[0].Dest).To(Equal("::/0"))
+
+ // Once a container executes a new network, the nic will be created. We should clean those up
+ // best we can
+ defer removeNetworkDevice(bridgePlugin.BrName)
+
+ try := podmanTest.Podman([]string{"run", "-it", "--rm", "--network", "newIPv6network", ALPINE, "sh", "-c", "ip addr show eth0 | grep global | awk ' /inet6 / {print $2}'"})
+ try.WaitWithDefaultTimeout()
+
+ _, subnet, err := net.ParseCIDR("fd00:1:2:3:4::/64")
+ Expect(err).To(BeNil())
+ containerIP, _, err := net.ParseCIDR(try.OutputToString())
+ Expect(err).To(BeNil())
+ // Ensure that the IP the container got is within the subnet the user asked for
+ Expect(subnet.Contains(containerIP)).To(BeTrue())
+ })
+
It("podman network create with invalid subnet", func() {
nc := podmanTest.Podman([]string{"network", "create", "--subnet", "10.11.12.0/17000", "fail"})
nc.WaitWithDefaultTimeout()