portmap: increase test coverage to 1.0.0 and older spec versions
Signed-off-by: Dan Williams <dcbw@redhat.com>
This commit is contained in:
parent
8f7fe6d8e8
commit
d2e5b5decb
@ -25,7 +25,7 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/containernetworking/cni/libcni"
|
"github.com/containernetworking/cni/libcni"
|
||||||
current "github.com/containernetworking/cni/pkg/types/100"
|
"github.com/containernetworking/cni/pkg/types/100"
|
||||||
"github.com/containernetworking/plugins/pkg/ns"
|
"github.com/containernetworking/plugins/pkg/ns"
|
||||||
"github.com/containernetworking/plugins/pkg/testutils"
|
"github.com/containernetworking/plugins/pkg/testutils"
|
||||||
"github.com/coreos/go-iptables/iptables"
|
"github.com/coreos/go-iptables/iptables"
|
||||||
@ -37,9 +37,36 @@ import (
|
|||||||
|
|
||||||
const TIMEOUT = 90
|
const TIMEOUT = 90
|
||||||
|
|
||||||
|
func makeConfig(ver string) *libcni.NetworkConfigList {
|
||||||
|
configList, err := libcni.ConfListFromBytes([]byte(fmt.Sprintf(`{
|
||||||
|
"cniVersion": "%s",
|
||||||
|
"name": "cni-portmap-unit-test",
|
||||||
|
"plugins": [
|
||||||
|
{
|
||||||
|
"type": "ptp",
|
||||||
|
"ipMasq": true,
|
||||||
|
"ipam": {
|
||||||
|
"type": "host-local",
|
||||||
|
"subnet": "172.16.31.0/24",
|
||||||
|
"routes": [
|
||||||
|
{"dst": "0.0.0.0/0"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "portmap",
|
||||||
|
"capabilities": {
|
||||||
|
"portMappings": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}`, ver)))
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
return configList
|
||||||
|
}
|
||||||
|
|
||||||
var _ = Describe("portmap integration tests", func() {
|
var _ = Describe("portmap integration tests", func() {
|
||||||
var (
|
var (
|
||||||
configList *libcni.NetworkConfigList
|
|
||||||
cniConf *libcni.CNIConfig
|
cniConf *libcni.CNIConfig
|
||||||
targetNS ns.NetNS
|
targetNS ns.NetNS
|
||||||
containerPort int
|
containerPort int
|
||||||
@ -47,38 +74,11 @@ var _ = Describe("portmap integration tests", func() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
var err error
|
|
||||||
rawConfig := `{
|
|
||||||
"cniVersion": "0.3.0",
|
|
||||||
"name": "cni-portmap-unit-test",
|
|
||||||
"plugins": [
|
|
||||||
{
|
|
||||||
"type": "ptp",
|
|
||||||
"ipMasq": true,
|
|
||||||
"ipam": {
|
|
||||||
"type": "host-local",
|
|
||||||
"subnet": "172.16.31.0/24",
|
|
||||||
"routes": [
|
|
||||||
{"dst": "0.0.0.0/0"}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "portmap",
|
|
||||||
"capabilities": {
|
|
||||||
"portMappings": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}`
|
|
||||||
|
|
||||||
configList, err = libcni.ConfListFromBytes([]byte(rawConfig))
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
// turn PATH in to CNI_PATH
|
// turn PATH in to CNI_PATH
|
||||||
dirs := filepath.SplitList(os.Getenv("PATH"))
|
dirs := filepath.SplitList(os.Getenv("PATH"))
|
||||||
cniConf = &libcni.CNIConfig{Path: dirs}
|
cniConf = &libcni.CNIConfig{Path: dirs}
|
||||||
|
|
||||||
|
var err error
|
||||||
targetNS, err = testutils.NewNS()
|
targetNS, err = testutils.NewNS()
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
fmt.Fprintln(GinkgoWriter, "namespace:", targetNS.Path())
|
fmt.Fprintln(GinkgoWriter, "namespace:", targetNS.Path())
|
||||||
@ -90,333 +90,340 @@ var _ = Describe("portmap integration tests", func() {
|
|||||||
|
|
||||||
AfterEach(func() {
|
AfterEach(func() {
|
||||||
session.Terminate().Wait()
|
session.Terminate().Wait()
|
||||||
if targetNS != nil {
|
targetNS.Close()
|
||||||
targetNS.Close()
|
testutils.UnmountNS(targetNS)
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
Describe("Creating an interface in a namespace with the ptp plugin", func() {
|
for _, ver := range []string{"0.3.0", "0.3.1", "0.4.0", "1.0.0"} {
|
||||||
// This needs to be done using Ginkgo's asynchronous testing mode.
|
// Redefine ver inside for scope so real value is picked up by each dynamically defined It()
|
||||||
It("forwards a TCP port on ipv4", func(done Done) {
|
// See Gingkgo's "Patterns for dynamically generating tests" documentation.
|
||||||
var err error
|
ver := ver
|
||||||
hostPort := rand.Intn(10000) + 1025
|
|
||||||
runtimeConfig := libcni.RuntimeConf{
|
Describe("Creating an interface in a namespace with the ptp plugin", func() {
|
||||||
ContainerID: fmt.Sprintf("unit-test-%d", hostPort),
|
// This needs to be done using Ginkgo's asynchronous testing mode.
|
||||||
NetNS: targetNS.Path(),
|
It(fmt.Sprintf("[%s] forwards a TCP port on ipv4", ver), func(done Done) {
|
||||||
IfName: "eth0",
|
var err error
|
||||||
CapabilityArgs: map[string]interface{}{
|
hostPort := rand.Intn(10000) + 1025
|
||||||
"portMappings": []map[string]interface{}{
|
runtimeConfig := libcni.RuntimeConf{
|
||||||
{
|
ContainerID: fmt.Sprintf("unit-test-%d", hostPort),
|
||||||
"hostPort": hostPort,
|
NetNS: targetNS.Path(),
|
||||||
"containerPort": containerPort,
|
IfName: "eth0",
|
||||||
"protocol": "tcp",
|
CapabilityArgs: map[string]interface{}{
|
||||||
|
"portMappings": []map[string]interface{}{
|
||||||
|
{
|
||||||
|
"hostPort": hostPort,
|
||||||
|
"containerPort": containerPort,
|
||||||
|
"protocol": "tcp",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make delete idempotent, so we can clean up on failure
|
|
||||||
netDeleted := false
|
|
||||||
deleteNetwork := func() error {
|
|
||||||
if netDeleted {
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
netDeleted = true
|
configList := makeConfig(ver)
|
||||||
return cniConf.DelNetworkList(context.TODO(), configList, &runtimeConfig)
|
|
||||||
}
|
|
||||||
|
|
||||||
// we'll also manually check the iptables chains
|
// Make delete idempotent, so we can clean up on failure
|
||||||
ipt, err := iptables.NewWithProtocol(iptables.ProtocolIPv4)
|
netDeleted := false
|
||||||
Expect(err).NotTo(HaveOccurred())
|
deleteNetwork := func() error {
|
||||||
dnatChainName := genDnatChain("cni-portmap-unit-test", runtimeConfig.ContainerID).name
|
if netDeleted {
|
||||||
|
return nil
|
||||||
// Create the network
|
}
|
||||||
resI, err := cniConf.AddNetworkList(context.TODO(), configList, &runtimeConfig)
|
netDeleted = true
|
||||||
Expect(err).NotTo(HaveOccurred())
|
return cniConf.DelNetworkList(context.TODO(), configList, &runtimeConfig)
|
||||||
defer deleteNetwork()
|
|
||||||
|
|
||||||
// Undo Docker's forwarding policy
|
|
||||||
cmd := exec.Command("iptables", "-t", "filter",
|
|
||||||
"-P", "FORWARD", "ACCEPT")
|
|
||||||
cmd.Stderr = GinkgoWriter
|
|
||||||
err = cmd.Run()
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
// Check the chain exists
|
|
||||||
_, err = ipt.List("nat", dnatChainName)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
result, err := current.GetResult(resI)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
var contIP net.IP
|
|
||||||
|
|
||||||
for _, ip := range result.IPs {
|
|
||||||
intfIndex := *ip.Interface
|
|
||||||
if result.Interfaces[intfIndex].Sandbox == "" {
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
contIP = ip.Address.IP
|
|
||||||
}
|
|
||||||
if contIP == nil {
|
|
||||||
Fail("could not determine container IP")
|
|
||||||
}
|
|
||||||
|
|
||||||
hostIP := getLocalIP()
|
// we'll also manually check the iptables chains
|
||||||
fmt.Fprintf(GinkgoWriter, "hostIP: %s:%d, contIP: %s:%d\n",
|
ipt, err := iptables.NewWithProtocol(iptables.ProtocolIPv4)
|
||||||
hostIP, hostPort, contIP, containerPort)
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
dnatChainName := genDnatChain("cni-portmap-unit-test", runtimeConfig.ContainerID).name
|
||||||
|
|
||||||
// dump iptables-save output for debugging
|
// Create the network
|
||||||
cmd = exec.Command("iptables-save")
|
resI, err := cniConf.AddNetworkList(context.TODO(), configList, &runtimeConfig)
|
||||||
cmd.Stderr = GinkgoWriter
|
Expect(err).NotTo(HaveOccurred())
|
||||||
cmd.Stdout = GinkgoWriter
|
defer deleteNetwork()
|
||||||
Expect(cmd.Run()).To(Succeed())
|
|
||||||
|
|
||||||
// dump ip routes output for debugging
|
// Undo Docker's forwarding policy
|
||||||
cmd = exec.Command("ip", "route")
|
cmd := exec.Command("iptables", "-t", "filter",
|
||||||
cmd.Stderr = GinkgoWriter
|
"-P", "FORWARD", "ACCEPT")
|
||||||
cmd.Stdout = GinkgoWriter
|
cmd.Stderr = GinkgoWriter
|
||||||
Expect(cmd.Run()).To(Succeed())
|
err = cmd.Run()
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
// dump ip addresses output for debugging
|
// Check the chain exists
|
||||||
cmd = exec.Command("ip", "addr")
|
_, err = ipt.List("nat", dnatChainName)
|
||||||
cmd.Stderr = GinkgoWriter
|
Expect(err).NotTo(HaveOccurred())
|
||||||
cmd.Stdout = GinkgoWriter
|
|
||||||
Expect(cmd.Run()).To(Succeed())
|
|
||||||
|
|
||||||
// Sanity check: verify that the container is reachable directly
|
result, err := types100.GetResult(resI)
|
||||||
contOK := testEchoServer(contIP.String(), "tcp", containerPort, "")
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
var contIP net.IP
|
||||||
|
|
||||||
// Verify that a connection to the forwarded port works
|
for _, ip := range result.IPs {
|
||||||
dnatOK := testEchoServer(hostIP, "tcp", hostPort, "")
|
intfIndex := *ip.Interface
|
||||||
|
if result.Interfaces[intfIndex].Sandbox == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
contIP = ip.Address.IP
|
||||||
|
}
|
||||||
|
if contIP == nil {
|
||||||
|
Fail("could not determine container IP")
|
||||||
|
}
|
||||||
|
|
||||||
// Verify that a connection to localhost works
|
hostIP := getLocalIP()
|
||||||
snatOK := testEchoServer("127.0.0.1", "tcp", hostPort, "")
|
fmt.Fprintf(GinkgoWriter, "hostIP: %s:%d, contIP: %s:%d\n",
|
||||||
|
hostIP, hostPort, contIP, containerPort)
|
||||||
|
|
||||||
// verify that hairpin works
|
// dump iptables-save output for debugging
|
||||||
hairpinOK := testEchoServer(hostIP, "tcp", hostPort, targetNS.Path())
|
cmd = exec.Command("iptables-save")
|
||||||
|
cmd.Stderr = GinkgoWriter
|
||||||
|
cmd.Stdout = GinkgoWriter
|
||||||
|
Expect(cmd.Run()).To(Succeed())
|
||||||
|
|
||||||
// Cleanup
|
// dump ip routes output for debugging
|
||||||
session.Terminate()
|
cmd = exec.Command("ip", "route")
|
||||||
err = deleteNetwork()
|
cmd.Stderr = GinkgoWriter
|
||||||
Expect(err).NotTo(HaveOccurred())
|
cmd.Stdout = GinkgoWriter
|
||||||
|
Expect(cmd.Run()).To(Succeed())
|
||||||
|
|
||||||
// Verify iptables rules are gone
|
// dump ip addresses output for debugging
|
||||||
_, err = ipt.List("nat", dnatChainName)
|
cmd = exec.Command("ip", "addr")
|
||||||
Expect(err).To(MatchError(ContainSubstring("iptables: No chain/target/match by that name.")))
|
cmd.Stderr = GinkgoWriter
|
||||||
|
cmd.Stdout = GinkgoWriter
|
||||||
|
Expect(cmd.Run()).To(Succeed())
|
||||||
|
|
||||||
// Check that everything succeeded *after* we clean up the network
|
// Sanity check: verify that the container is reachable directly
|
||||||
if !contOK {
|
contOK := testEchoServer(contIP.String(), "tcp", containerPort, "")
|
||||||
Fail("connection direct to " + contIP.String() + " failed")
|
|
||||||
}
|
|
||||||
if !dnatOK {
|
|
||||||
Fail("Connection to " + hostIP + " was not forwarded")
|
|
||||||
}
|
|
||||||
if !snatOK {
|
|
||||||
Fail("connection to 127.0.0.1 was not forwarded")
|
|
||||||
}
|
|
||||||
if !hairpinOK {
|
|
||||||
Fail("Hairpin connection failed")
|
|
||||||
}
|
|
||||||
|
|
||||||
close(done)
|
// Verify that a connection to the forwarded port works
|
||||||
}, TIMEOUT*9)
|
dnatOK := testEchoServer(hostIP, "tcp", hostPort, "")
|
||||||
|
|
||||||
It("forwards a UDP port on ipv4 and keep working after creating a second container with the same HostPort", func(done Done) {
|
// Verify that a connection to localhost works
|
||||||
var err error
|
snatOK := testEchoServer("127.0.0.1", "tcp", hostPort, "")
|
||||||
hostPort := rand.Intn(10000) + 1025
|
|
||||||
runtimeConfig := libcni.RuntimeConf{
|
// verify that hairpin works
|
||||||
ContainerID: fmt.Sprintf("unit-test-%d", hostPort),
|
hairpinOK := testEchoServer(hostIP, "tcp", hostPort, targetNS.Path())
|
||||||
NetNS: targetNS.Path(),
|
|
||||||
IfName: "eth0",
|
// Cleanup
|
||||||
CapabilityArgs: map[string]interface{}{
|
session.Terminate()
|
||||||
"portMappings": []map[string]interface{}{
|
err = deleteNetwork()
|
||||||
{
|
Expect(err).NotTo(HaveOccurred())
|
||||||
"hostPort": hostPort,
|
|
||||||
"containerPort": containerPort,
|
// Verify iptables rules are gone
|
||||||
"protocol": "udp",
|
_, err = ipt.List("nat", dnatChainName)
|
||||||
|
Expect(err).To(MatchError(ContainSubstring("iptables: No chain/target/match by that name.")))
|
||||||
|
|
||||||
|
// Check that everything succeeded *after* we clean up the network
|
||||||
|
if !contOK {
|
||||||
|
Fail("connection direct to " + contIP.String() + " failed")
|
||||||
|
}
|
||||||
|
if !dnatOK {
|
||||||
|
Fail("Connection to " + hostIP + " was not forwarded")
|
||||||
|
}
|
||||||
|
if !snatOK {
|
||||||
|
Fail("connection to 127.0.0.1 was not forwarded")
|
||||||
|
}
|
||||||
|
if !hairpinOK {
|
||||||
|
Fail("Hairpin connection failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
close(done)
|
||||||
|
}, TIMEOUT*9)
|
||||||
|
|
||||||
|
It(fmt.Sprintf("[%s] forwards a UDP port on ipv4 and keep working after creating a second container with the same HostPort", ver), func(done Done) {
|
||||||
|
var err error
|
||||||
|
hostPort := rand.Intn(10000) + 1025
|
||||||
|
runtimeConfig := libcni.RuntimeConf{
|
||||||
|
ContainerID: fmt.Sprintf("unit-test-%d", hostPort),
|
||||||
|
NetNS: targetNS.Path(),
|
||||||
|
IfName: "eth0",
|
||||||
|
CapabilityArgs: map[string]interface{}{
|
||||||
|
"portMappings": []map[string]interface{}{
|
||||||
|
{
|
||||||
|
"hostPort": hostPort,
|
||||||
|
"containerPort": containerPort,
|
||||||
|
"protocol": "udp",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make delete idempotent, so we can clean up on failure
|
|
||||||
netDeleted := false
|
|
||||||
deleteNetwork := func() error {
|
|
||||||
if netDeleted {
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
netDeleted = true
|
configList := makeConfig(ver)
|
||||||
return cniConf.DelNetworkList(context.TODO(), configList, &runtimeConfig)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the network
|
// Make delete idempotent, so we can clean up on failure
|
||||||
resI, err := cniConf.AddNetworkList(context.TODO(), configList, &runtimeConfig)
|
netDeleted := false
|
||||||
Expect(err).NotTo(HaveOccurred())
|
deleteNetwork := func() error {
|
||||||
defer deleteNetwork()
|
if netDeleted {
|
||||||
|
return nil
|
||||||
// Undo Docker's forwarding policy
|
}
|
||||||
cmd := exec.Command("iptables", "-t", "filter",
|
netDeleted = true
|
||||||
"-P", "FORWARD", "ACCEPT")
|
return cniConf.DelNetworkList(context.TODO(), configList, &runtimeConfig)
|
||||||
cmd.Stderr = GinkgoWriter
|
|
||||||
err = cmd.Run()
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
result, err := current.GetResult(resI)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
var contIP net.IP
|
|
||||||
|
|
||||||
for _, ip := range result.IPs {
|
|
||||||
intfIndex := *ip.Interface
|
|
||||||
if result.Interfaces[intfIndex].Sandbox == "" {
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
contIP = ip.Address.IP
|
|
||||||
}
|
|
||||||
if contIP == nil {
|
|
||||||
Fail("could not determine container IP")
|
|
||||||
}
|
|
||||||
|
|
||||||
hostIP := getLocalIP()
|
// Create the network
|
||||||
fmt.Fprintf(GinkgoWriter, "First container hostIP: %s:%d, contIP: %s:%d\n",
|
resI, err := cniConf.AddNetworkList(context.TODO(), configList, &runtimeConfig)
|
||||||
hostIP, hostPort, contIP, containerPort)
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
defer deleteNetwork()
|
||||||
|
|
||||||
// dump iptables-save output for debugging
|
// Undo Docker's forwarding policy
|
||||||
cmd = exec.Command("iptables-save")
|
cmd := exec.Command("iptables", "-t", "filter",
|
||||||
cmd.Stderr = GinkgoWriter
|
"-P", "FORWARD", "ACCEPT")
|
||||||
cmd.Stdout = GinkgoWriter
|
cmd.Stderr = GinkgoWriter
|
||||||
Expect(cmd.Run()).To(Succeed())
|
err = cmd.Run()
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
// dump ip routes output for debugging
|
result, err := types100.GetResult(resI)
|
||||||
cmd = exec.Command("ip", "route")
|
Expect(err).NotTo(HaveOccurred())
|
||||||
cmd.Stderr = GinkgoWriter
|
var contIP net.IP
|
||||||
cmd.Stdout = GinkgoWriter
|
|
||||||
Expect(cmd.Run()).To(Succeed())
|
|
||||||
|
|
||||||
// dump ip addresses output for debugging
|
for _, ip := range result.IPs {
|
||||||
cmd = exec.Command("ip", "addr")
|
intfIndex := *ip.Interface
|
||||||
cmd.Stderr = GinkgoWriter
|
if result.Interfaces[intfIndex].Sandbox == "" {
|
||||||
cmd.Stdout = GinkgoWriter
|
continue
|
||||||
Expect(cmd.Run()).To(Succeed())
|
}
|
||||||
|
contIP = ip.Address.IP
|
||||||
|
}
|
||||||
|
if contIP == nil {
|
||||||
|
Fail("could not determine container IP")
|
||||||
|
}
|
||||||
|
|
||||||
// Sanity check: verify that the container is reachable directly
|
hostIP := getLocalIP()
|
||||||
fmt.Fprintln(GinkgoWriter, "Connect to container:", contIP.String(), containerPort)
|
fmt.Fprintf(GinkgoWriter, "First container hostIP: %s:%d, contIP: %s:%d\n",
|
||||||
contOK := testEchoServer(contIP.String(), "udp", containerPort, "")
|
hostIP, hostPort, contIP, containerPort)
|
||||||
|
|
||||||
// Verify that a connection to the forwarded port works
|
// dump iptables-save output for debugging
|
||||||
fmt.Fprintln(GinkgoWriter, "Connect to host:", hostIP, hostPort)
|
cmd = exec.Command("iptables-save")
|
||||||
dnatOK := testEchoServer(hostIP, "udp", hostPort, "")
|
cmd.Stderr = GinkgoWriter
|
||||||
|
cmd.Stdout = GinkgoWriter
|
||||||
|
Expect(cmd.Run()).To(Succeed())
|
||||||
|
|
||||||
// Cleanup
|
// dump ip routes output for debugging
|
||||||
session.Terminate()
|
cmd = exec.Command("ip", "route")
|
||||||
err = deleteNetwork()
|
cmd.Stderr = GinkgoWriter
|
||||||
Expect(err).NotTo(HaveOccurred())
|
cmd.Stdout = GinkgoWriter
|
||||||
|
Expect(cmd.Run()).To(Succeed())
|
||||||
|
|
||||||
// Check that everything succeeded *after* we clean up the network
|
// dump ip addresses output for debugging
|
||||||
if !contOK {
|
cmd = exec.Command("ip", "addr")
|
||||||
Fail("connection direct to " + contIP.String() + " failed")
|
cmd.Stderr = GinkgoWriter
|
||||||
}
|
cmd.Stdout = GinkgoWriter
|
||||||
if !dnatOK {
|
Expect(cmd.Run()).To(Succeed())
|
||||||
Fail("Connection to " + hostIP + " was not forwarded")
|
|
||||||
}
|
|
||||||
// Create a second container
|
|
||||||
targetNS2, err := testutils.NewNS()
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
fmt.Fprintln(GinkgoWriter, "namespace:", targetNS2.Path())
|
|
||||||
|
|
||||||
// Start an echo server and get the port
|
// Sanity check: verify that the container is reachable directly
|
||||||
containerPort, session2, err := StartEchoServerInNamespace(targetNS2)
|
fmt.Fprintln(GinkgoWriter, "Connect to container:", contIP.String(), containerPort)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
contOK := testEchoServer(contIP.String(), "udp", containerPort, "")
|
||||||
|
|
||||||
runtimeConfig2 := libcni.RuntimeConf{
|
// Verify that a connection to the forwarded port works
|
||||||
ContainerID: fmt.Sprintf("unit-test2-%d", hostPort),
|
fmt.Fprintln(GinkgoWriter, "Connect to host:", hostIP, hostPort)
|
||||||
NetNS: targetNS2.Path(),
|
dnatOK := testEchoServer(hostIP, "udp", hostPort, "")
|
||||||
IfName: "eth0",
|
|
||||||
CapabilityArgs: map[string]interface{}{
|
// Cleanup
|
||||||
"portMappings": []map[string]interface{}{
|
session.Terminate()
|
||||||
{
|
err = deleteNetwork()
|
||||||
"hostPort": hostPort,
|
Expect(err).NotTo(HaveOccurred())
|
||||||
"containerPort": containerPort,
|
|
||||||
"protocol": "udp",
|
// Check that everything succeeded *after* we clean up the network
|
||||||
|
if !contOK {
|
||||||
|
Fail("connection direct to " + contIP.String() + " failed")
|
||||||
|
}
|
||||||
|
if !dnatOK {
|
||||||
|
Fail("Connection to " + hostIP + " was not forwarded")
|
||||||
|
}
|
||||||
|
// Create a second container
|
||||||
|
targetNS2, err := testutils.NewNS()
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
fmt.Fprintln(GinkgoWriter, "namespace:", targetNS2.Path())
|
||||||
|
|
||||||
|
// Start an echo server and get the port
|
||||||
|
containerPort, session2, err := StartEchoServerInNamespace(targetNS2)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
runtimeConfig2 := libcni.RuntimeConf{
|
||||||
|
ContainerID: fmt.Sprintf("unit-test2-%d", hostPort),
|
||||||
|
NetNS: targetNS2.Path(),
|
||||||
|
IfName: "eth0",
|
||||||
|
CapabilityArgs: map[string]interface{}{
|
||||||
|
"portMappings": []map[string]interface{}{
|
||||||
|
{
|
||||||
|
"hostPort": hostPort,
|
||||||
|
"containerPort": containerPort,
|
||||||
|
"protocol": "udp",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make delete idempotent, so we can clean up on failure
|
|
||||||
net2Deleted := false
|
|
||||||
deleteNetwork2 := func() error {
|
|
||||||
if net2Deleted {
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
net2Deleted = true
|
|
||||||
return cniConf.DelNetworkList(context.TODO(), configList, &runtimeConfig2)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the network
|
// Make delete idempotent, so we can clean up on failure
|
||||||
resI2, err := cniConf.AddNetworkList(context.TODO(), configList, &runtimeConfig2)
|
net2Deleted := false
|
||||||
Expect(err).NotTo(HaveOccurred())
|
deleteNetwork2 := func() error {
|
||||||
defer deleteNetwork2()
|
if net2Deleted {
|
||||||
|
return nil
|
||||||
result2, err := current.GetResult(resI2)
|
}
|
||||||
Expect(err).NotTo(HaveOccurred())
|
net2Deleted = true
|
||||||
var contIP2 net.IP
|
return cniConf.DelNetworkList(context.TODO(), configList, &runtimeConfig2)
|
||||||
|
|
||||||
for _, ip := range result2.IPs {
|
|
||||||
intfIndex := *ip.Interface
|
|
||||||
if result2.Interfaces[intfIndex].Sandbox == "" {
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
contIP2 = ip.Address.IP
|
|
||||||
}
|
|
||||||
if contIP2 == nil {
|
|
||||||
Fail("could not determine container IP")
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprintf(GinkgoWriter, "Second container: hostIP: %s:%d, contIP: %s:%d\n",
|
// Create the network
|
||||||
hostIP, hostPort, contIP2, containerPort)
|
resI2, err := cniConf.AddNetworkList(context.TODO(), configList, &runtimeConfig2)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
defer deleteNetwork2()
|
||||||
|
|
||||||
// dump iptables-save output for debugging
|
result2, err := types100.GetResult(resI2)
|
||||||
cmd = exec.Command("iptables-save")
|
Expect(err).NotTo(HaveOccurred())
|
||||||
cmd.Stderr = GinkgoWriter
|
var contIP2 net.IP
|
||||||
cmd.Stdout = GinkgoWriter
|
|
||||||
Expect(cmd.Run()).To(Succeed())
|
|
||||||
|
|
||||||
// dump ip routes output for debugging
|
for _, ip := range result2.IPs {
|
||||||
cmd = exec.Command("ip", "route")
|
intfIndex := *ip.Interface
|
||||||
cmd.Stderr = GinkgoWriter
|
if result2.Interfaces[intfIndex].Sandbox == "" {
|
||||||
cmd.Stdout = GinkgoWriter
|
continue
|
||||||
Expect(cmd.Run()).To(Succeed())
|
}
|
||||||
|
contIP2 = ip.Address.IP
|
||||||
|
}
|
||||||
|
if contIP2 == nil {
|
||||||
|
Fail("could not determine container IP")
|
||||||
|
}
|
||||||
|
|
||||||
// dump ip addresses output for debugging
|
fmt.Fprintf(GinkgoWriter, "Second container: hostIP: %s:%d, contIP: %s:%d\n",
|
||||||
cmd = exec.Command("ip", "addr")
|
hostIP, hostPort, contIP2, containerPort)
|
||||||
cmd.Stderr = GinkgoWriter
|
|
||||||
cmd.Stdout = GinkgoWriter
|
|
||||||
Expect(cmd.Run()).To(Succeed())
|
|
||||||
|
|
||||||
// Sanity check: verify that the container is reachable directly
|
// dump iptables-save output for debugging
|
||||||
fmt.Fprintln(GinkgoWriter, "Connect to container:", contIP2.String(), containerPort)
|
cmd = exec.Command("iptables-save")
|
||||||
cont2OK := testEchoServer(contIP2.String(), "udp", containerPort, "")
|
cmd.Stderr = GinkgoWriter
|
||||||
|
cmd.Stdout = GinkgoWriter
|
||||||
|
Expect(cmd.Run()).To(Succeed())
|
||||||
|
|
||||||
// Verify that a connection to the forwarded port works
|
// dump ip routes output for debugging
|
||||||
fmt.Fprintln(GinkgoWriter, "Connect to host:", hostIP, hostPort)
|
cmd = exec.Command("ip", "route")
|
||||||
dnat2OK := testEchoServer(hostIP, "udp", hostPort, "")
|
cmd.Stderr = GinkgoWriter
|
||||||
|
cmd.Stdout = GinkgoWriter
|
||||||
|
Expect(cmd.Run()).To(Succeed())
|
||||||
|
|
||||||
// Cleanup
|
// dump ip addresses output for debugging
|
||||||
session2.Terminate()
|
cmd = exec.Command("ip", "addr")
|
||||||
err = deleteNetwork2()
|
cmd.Stderr = GinkgoWriter
|
||||||
Expect(err).NotTo(HaveOccurred())
|
cmd.Stdout = GinkgoWriter
|
||||||
|
Expect(cmd.Run()).To(Succeed())
|
||||||
|
|
||||||
// Check that everything succeeded *after* we clean up the network
|
// Sanity check: verify that the container is reachable directly
|
||||||
if !cont2OK {
|
fmt.Fprintln(GinkgoWriter, "Connect to container:", contIP2.String(), containerPort)
|
||||||
Fail("connection direct to " + contIP2.String() + " failed")
|
cont2OK := testEchoServer(contIP2.String(), "udp", containerPort, "")
|
||||||
}
|
|
||||||
if !dnat2OK {
|
|
||||||
Fail("Connection to " + hostIP + " was not forwarded")
|
|
||||||
}
|
|
||||||
|
|
||||||
close(done)
|
// Verify that a connection to the forwarded port works
|
||||||
}, TIMEOUT*9)
|
fmt.Fprintln(GinkgoWriter, "Connect to host:", hostIP, hostPort)
|
||||||
})
|
dnat2OK := testEchoServer(hostIP, "udp", hostPort, "")
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
session2.Terminate()
|
||||||
|
err = deleteNetwork2()
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
// Check that everything succeeded *after* we clean up the network
|
||||||
|
if !cont2OK {
|
||||||
|
Fail("connection direct to " + contIP2.String() + " failed")
|
||||||
|
}
|
||||||
|
if !dnat2OK {
|
||||||
|
Fail("Connection to " + hostIP + " was not forwarded")
|
||||||
|
}
|
||||||
|
|
||||||
|
close(done)
|
||||||
|
}, TIMEOUT*9)
|
||||||
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// testEchoServer returns true if we found an echo server on the port
|
// testEchoServer returns true if we found an echo server on the port
|
||||||
|
@ -27,336 +27,342 @@ var _ = Describe("portmapping configuration", func() {
|
|||||||
netName := "testNetName"
|
netName := "testNetName"
|
||||||
containerID := "icee6giejonei6sohng6ahngee7laquohquee9shiGo7fohferakah3Feiyoolu2pei7ciPhoh7shaoX6vai3vuf0ahfaeng8yohb9ceu0daez5hashee8ooYai5wa3y"
|
containerID := "icee6giejonei6sohng6ahngee7laquohquee9shiGo7fohferakah3Feiyoolu2pei7ciPhoh7shaoX6vai3vuf0ahfaeng8yohb9ceu0daez5hashee8ooYai5wa3y"
|
||||||
|
|
||||||
Context("config parsing", func() {
|
for _, ver := range []string{"0.3.0", "0.3.1", "0.4.0", "1.0.0"} {
|
||||||
It("Correctly parses an ADD config", func() {
|
// Redefine ver inside for scope so real value is picked up by each dynamically defined It()
|
||||||
configBytes := []byte(`{
|
// See Gingkgo's "Patterns for dynamically generating tests" documentation.
|
||||||
"name": "test",
|
ver := ver
|
||||||
"type": "portmap",
|
|
||||||
"cniVersion": "0.3.1",
|
|
||||||
"runtimeConfig": {
|
|
||||||
"portMappings": [
|
|
||||||
{ "hostPort": 8080, "containerPort": 80, "protocol": "tcp"},
|
|
||||||
{ "hostPort": 8081, "containerPort": 81, "protocol": "udp"}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"snat": false,
|
|
||||||
"conditionsV4": ["a", "b"],
|
|
||||||
"conditionsV6": ["c", "d"],
|
|
||||||
"prevResult": {
|
|
||||||
"interfaces": [
|
|
||||||
{"name": "host"},
|
|
||||||
{"name": "container", "sandbox":"netns"}
|
|
||||||
],
|
|
||||||
"ips": [
|
|
||||||
{
|
|
||||||
"version": "4",
|
|
||||||
"address": "10.0.0.1/24",
|
|
||||||
"gateway": "10.0.0.1",
|
|
||||||
"interface": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"version": "6",
|
|
||||||
"address": "2001:db8:1::2/64",
|
|
||||||
"gateway": "2001:db8:1::1",
|
|
||||||
"interface": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"version": "4",
|
|
||||||
"address": "10.0.0.2/24",
|
|
||||||
"gateway": "10.0.0.1",
|
|
||||||
"interface": 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}`)
|
|
||||||
c, _, err := parseConfig(configBytes, "container")
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(c.CNIVersion).To(Equal("0.3.1"))
|
|
||||||
Expect(c.ConditionsV4).To(Equal(&[]string{"a", "b"}))
|
|
||||||
Expect(c.ConditionsV6).To(Equal(&[]string{"c", "d"}))
|
|
||||||
fvar := false
|
|
||||||
Expect(c.SNAT).To(Equal(&fvar))
|
|
||||||
Expect(c.Name).To(Equal("test"))
|
|
||||||
|
|
||||||
n, err := types.ParseCIDR("10.0.0.2/24")
|
Context("config parsing", func() {
|
||||||
Expect(c.ContIPv4).To(Equal(*n))
|
It(fmt.Sprintf("[%s] correctly parses an ADD config", ver), func() {
|
||||||
n, err = types.ParseCIDR("2001:db8:1::2/64")
|
configBytes := []byte(fmt.Sprintf(`{
|
||||||
Expect(c.ContIPv6).To(Equal(*n))
|
"name": "test",
|
||||||
})
|
"type": "portmap",
|
||||||
|
"cniVersion": "%s",
|
||||||
It("Correctly parses a DEL config", func() {
|
"runtimeConfig": {
|
||||||
// When called with DEL, neither runtimeConfig nor prevResult may be specified
|
"portMappings": [
|
||||||
configBytes := []byte(`{
|
{ "hostPort": 8080, "containerPort": 80, "protocol": "tcp"},
|
||||||
"name": "test",
|
{ "hostPort": 8081, "containerPort": 81, "protocol": "udp"}
|
||||||
"type": "portmap",
|
]
|
||||||
"cniVersion": "0.3.1",
|
},
|
||||||
"snat": false,
|
"snat": false,
|
||||||
"conditionsV4": ["a", "b"],
|
"conditionsV4": ["a", "b"],
|
||||||
"conditionsV6": ["c", "d"]
|
"conditionsV6": ["c", "d"],
|
||||||
}`)
|
"prevResult": {
|
||||||
c, _, err := parseConfig(configBytes, "container")
|
"interfaces": [
|
||||||
Expect(err).NotTo(HaveOccurred())
|
{"name": "host"},
|
||||||
Expect(c.CNIVersion).To(Equal("0.3.1"))
|
{"name": "container", "sandbox":"netns"}
|
||||||
Expect(c.ConditionsV4).To(Equal(&[]string{"a", "b"}))
|
],
|
||||||
Expect(c.ConditionsV6).To(Equal(&[]string{"c", "d"}))
|
"ips": [
|
||||||
fvar := false
|
{
|
||||||
Expect(c.SNAT).To(Equal(&fvar))
|
"version": "4",
|
||||||
Expect(c.Name).To(Equal("test"))
|
"address": "10.0.0.1/24",
|
||||||
})
|
"gateway": "10.0.0.1",
|
||||||
|
"interface": 0
|
||||||
It("fails with invalid mappings", func() {
|
},
|
||||||
configBytes := []byte(`{
|
{
|
||||||
"name": "test",
|
"version": "6",
|
||||||
"type": "portmap",
|
"address": "2001:db8:1::2/64",
|
||||||
"cniVersion": "0.3.1",
|
"gateway": "2001:db8:1::1",
|
||||||
"snat": false,
|
"interface": 1
|
||||||
"conditionsV4": ["a", "b"],
|
},
|
||||||
"conditionsV6": ["c", "d"],
|
{
|
||||||
"runtimeConfig": {
|
"version": "4",
|
||||||
"portMappings": [
|
"address": "10.0.0.2/24",
|
||||||
{ "hostPort": 0, "containerPort": 80, "protocol": "tcp"}
|
"gateway": "10.0.0.1",
|
||||||
]
|
"interface": 1
|
||||||
}
|
}
|
||||||
}`)
|
]
|
||||||
_, _, err := parseConfig(configBytes, "container")
|
}
|
||||||
Expect(err).To(MatchError("Invalid host port number: 0"))
|
}`, ver))
|
||||||
})
|
c, _, err := parseConfig(configBytes, "container")
|
||||||
|
|
||||||
It("Does not fail on missing prevResult interface index", func() {
|
|
||||||
configBytes := []byte(`{
|
|
||||||
"name": "test",
|
|
||||||
"type": "portmap",
|
|
||||||
"cniVersion": "0.3.1",
|
|
||||||
"runtimeConfig": {
|
|
||||||
"portMappings": [
|
|
||||||
{ "hostPort": 8080, "containerPort": 80, "protocol": "tcp"}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"conditionsV4": ["a", "b"],
|
|
||||||
"prevResult": {
|
|
||||||
"interfaces": [
|
|
||||||
{"name": "host"}
|
|
||||||
],
|
|
||||||
"ips": [
|
|
||||||
{
|
|
||||||
"version": "4",
|
|
||||||
"address": "10.0.0.1/24",
|
|
||||||
"gateway": "10.0.0.1"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}`)
|
|
||||||
_, _, err := parseConfig(configBytes, "container")
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
Describe("Generating chains", func() {
|
|
||||||
Context("for DNAT", func() {
|
|
||||||
It("generates a correct standard container chain", func() {
|
|
||||||
ch := genDnatChain(netName, containerID)
|
|
||||||
|
|
||||||
Expect(ch).To(Equal(chain{
|
|
||||||
table: "nat",
|
|
||||||
name: "CNI-DN-bfd599665540dd91d5d28",
|
|
||||||
entryChains: []string{TopLevelDNATChainName},
|
|
||||||
}))
|
|
||||||
configBytes := []byte(`{
|
|
||||||
"name": "test",
|
|
||||||
"type": "portmap",
|
|
||||||
"cniVersion": "0.3.1",
|
|
||||||
"runtimeConfig": {
|
|
||||||
"portMappings": [
|
|
||||||
{ "hostPort": 8080, "containerPort": 80, "protocol": "tcp"},
|
|
||||||
{ "hostPort": 8081, "containerPort": 80, "protocol": "tcp"},
|
|
||||||
{ "hostPort": 8080, "containerPort": 81, "protocol": "udp"},
|
|
||||||
{ "hostPort": 8082, "containerPort": 82, "protocol": "udp"},
|
|
||||||
{ "hostPort": 8083, "containerPort": 83, "protocol": "tcp", "hostIP": "192.168.0.2"},
|
|
||||||
{ "hostPort": 8084, "containerPort": 84, "protocol": "tcp", "hostIP": "0.0.0.0"},
|
|
||||||
{ "hostPort": 8085, "containerPort": 85, "protocol": "tcp", "hostIP": "2001:db8:a::1"},
|
|
||||||
{ "hostPort": 8086, "containerPort": 86, "protocol": "tcp", "hostIP": "::"}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"snat": true,
|
|
||||||
"conditionsV4": ["a", "b"],
|
|
||||||
"conditionsV6": ["c", "d"]
|
|
||||||
}`)
|
|
||||||
|
|
||||||
conf, _, err := parseConfig(configBytes, "foo")
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
conf.ContainerID = containerID
|
Expect(c.CNIVersion).To(Equal(ver))
|
||||||
|
Expect(c.ConditionsV4).To(Equal(&[]string{"a", "b"}))
|
||||||
ch = genDnatChain(conf.Name, containerID)
|
Expect(c.ConditionsV6).To(Equal(&[]string{"c", "d"}))
|
||||||
Expect(ch).To(Equal(chain{
|
|
||||||
table: "nat",
|
|
||||||
name: "CNI-DN-67e92b96e692a494b6b85",
|
|
||||||
entryChains: []string{"CNI-HOSTPORT-DNAT"},
|
|
||||||
}))
|
|
||||||
|
|
||||||
n, err := types.ParseCIDR("10.0.0.2/24")
|
|
||||||
fillDnatRules(&ch, conf, *n)
|
|
||||||
|
|
||||||
Expect(ch.entryRules).To(Equal([][]string{
|
|
||||||
{"-m", "comment", "--comment",
|
|
||||||
fmt.Sprintf("dnat name: \"test\" id: \"%s\"", containerID),
|
|
||||||
"-m", "multiport",
|
|
||||||
"-p", "tcp",
|
|
||||||
"--destination-ports", "8080,8081,8083,8084,8085,8086",
|
|
||||||
"a", "b"},
|
|
||||||
{"-m", "comment", "--comment",
|
|
||||||
fmt.Sprintf("dnat name: \"test\" id: \"%s\"", containerID),
|
|
||||||
"-m", "multiport",
|
|
||||||
"-p", "udp",
|
|
||||||
"--destination-ports", "8080,8082",
|
|
||||||
"a", "b"},
|
|
||||||
}))
|
|
||||||
|
|
||||||
Expect(ch.rules).To(Equal([][]string{
|
|
||||||
// tcp rules and not hostIP
|
|
||||||
{"-p", "tcp", "--dport", "8080", "-s", "10.0.0.2/24", "-j", "CNI-HOSTPORT-SETMARK"},
|
|
||||||
{"-p", "tcp", "--dport", "8080", "-s", "127.0.0.1", "-j", "CNI-HOSTPORT-SETMARK"},
|
|
||||||
{"-p", "tcp", "--dport", "8080", "-j", "DNAT", "--to-destination", "10.0.0.2:80"},
|
|
||||||
{"-p", "tcp", "--dport", "8081", "-s", "10.0.0.2/24", "-j", "CNI-HOSTPORT-SETMARK"},
|
|
||||||
{"-p", "tcp", "--dport", "8081", "-s", "127.0.0.1", "-j", "CNI-HOSTPORT-SETMARK"},
|
|
||||||
{"-p", "tcp", "--dport", "8081", "-j", "DNAT", "--to-destination", "10.0.0.2:80"},
|
|
||||||
// udp rules and not hostIP
|
|
||||||
{"-p", "udp", "--dport", "8080", "-s", "10.0.0.2/24", "-j", "CNI-HOSTPORT-SETMARK"},
|
|
||||||
{"-p", "udp", "--dport", "8080", "-s", "127.0.0.1", "-j", "CNI-HOSTPORT-SETMARK"},
|
|
||||||
{"-p", "udp", "--dport", "8080", "-j", "DNAT", "--to-destination", "10.0.0.2:81"},
|
|
||||||
{"-p", "udp", "--dport", "8082", "-s", "10.0.0.2/24", "-j", "CNI-HOSTPORT-SETMARK"},
|
|
||||||
{"-p", "udp", "--dport", "8082", "-s", "127.0.0.1", "-j", "CNI-HOSTPORT-SETMARK"},
|
|
||||||
{"-p", "udp", "--dport", "8082", "-j", "DNAT", "--to-destination", "10.0.0.2:82"},
|
|
||||||
// tcp rules and hostIP
|
|
||||||
{"-p", "tcp", "--dport", "8083", "-d", "192.168.0.2", "-s", "10.0.0.2/24", "-j", "CNI-HOSTPORT-SETMARK"},
|
|
||||||
{"-p", "tcp", "--dport", "8083", "-d", "192.168.0.2", "-s", "127.0.0.1", "-j", "CNI-HOSTPORT-SETMARK"},
|
|
||||||
{"-p", "tcp", "--dport", "8083", "-d", "192.168.0.2", "-j", "DNAT", "--to-destination", "10.0.0.2:83"},
|
|
||||||
// tcp rules and hostIP = "0.0.0.0"
|
|
||||||
{"-p", "tcp", "--dport", "8084", "-s", "10.0.0.2/24", "-j", "CNI-HOSTPORT-SETMARK"},
|
|
||||||
{"-p", "tcp", "--dport", "8084", "-s", "127.0.0.1", "-j", "CNI-HOSTPORT-SETMARK"},
|
|
||||||
{"-p", "tcp", "--dport", "8084", "-j", "DNAT", "--to-destination", "10.0.0.2:84"},
|
|
||||||
}))
|
|
||||||
|
|
||||||
ch.rules = nil
|
|
||||||
ch.entryRules = nil
|
|
||||||
|
|
||||||
n, err = types.ParseCIDR("2001:db8::2/64")
|
|
||||||
fillDnatRules(&ch, conf, *n)
|
|
||||||
|
|
||||||
Expect(ch.rules).To(Equal([][]string{
|
|
||||||
// tcp rules and not hostIP
|
|
||||||
{"-p", "tcp", "--dport", "8080", "-s", "2001:db8::2/64", "-j", "CNI-HOSTPORT-SETMARK"},
|
|
||||||
{"-p", "tcp", "--dport", "8080", "-j", "DNAT", "--to-destination", "[2001:db8::2]:80"},
|
|
||||||
{"-p", "tcp", "--dport", "8081", "-s", "2001:db8::2/64", "-j", "CNI-HOSTPORT-SETMARK"},
|
|
||||||
{"-p", "tcp", "--dport", "8081", "-j", "DNAT", "--to-destination", "[2001:db8::2]:80"},
|
|
||||||
// udp rules and not hostIP
|
|
||||||
{"-p", "udp", "--dport", "8080", "-s", "2001:db8::2/64", "-j", "CNI-HOSTPORT-SETMARK"},
|
|
||||||
{"-p", "udp", "--dport", "8080", "-j", "DNAT", "--to-destination", "[2001:db8::2]:81"},
|
|
||||||
{"-p", "udp", "--dport", "8082", "-s", "2001:db8::2/64", "-j", "CNI-HOSTPORT-SETMARK"},
|
|
||||||
{"-p", "udp", "--dport", "8082", "-j", "DNAT", "--to-destination", "[2001:db8::2]:82"},
|
|
||||||
// tcp rules and hostIP
|
|
||||||
{"-p", "tcp", "--dport", "8085", "-d", "2001:db8:a::1", "-s", "2001:db8::2/64", "-j", "CNI-HOSTPORT-SETMARK"},
|
|
||||||
{"-p", "tcp", "--dport", "8085", "-d", "2001:db8:a::1", "-j", "DNAT", "--to-destination", "[2001:db8::2]:85"},
|
|
||||||
// tcp rules and hostIP = "::"
|
|
||||||
{"-p", "tcp", "--dport", "8086", "-s", "2001:db8::2/64", "-j", "CNI-HOSTPORT-SETMARK"},
|
|
||||||
{"-p", "tcp", "--dport", "8086", "-j", "DNAT", "--to-destination", "[2001:db8::2]:86"},
|
|
||||||
}))
|
|
||||||
|
|
||||||
// Disable snat, generate rules
|
|
||||||
ch.rules = nil
|
|
||||||
ch.entryRules = nil
|
|
||||||
fvar := false
|
fvar := false
|
||||||
conf.SNAT = &fvar
|
Expect(c.SNAT).To(Equal(&fvar))
|
||||||
|
Expect(c.Name).To(Equal("test"))
|
||||||
|
|
||||||
n, err = types.ParseCIDR("10.0.0.2/24")
|
|
||||||
fillDnatRules(&ch, conf, *n)
|
|
||||||
Expect(ch.rules).To(Equal([][]string{
|
|
||||||
{"-p", "tcp", "--dport", "8080", "-j", "DNAT", "--to-destination", "10.0.0.2:80"},
|
|
||||||
{"-p", "tcp", "--dport", "8081", "-j", "DNAT", "--to-destination", "10.0.0.2:80"},
|
|
||||||
{"-p", "udp", "--dport", "8080", "-j", "DNAT", "--to-destination", "10.0.0.2:81"},
|
|
||||||
{"-p", "udp", "--dport", "8082", "-j", "DNAT", "--to-destination", "10.0.0.2:82"},
|
|
||||||
{"-p", "tcp", "--dport", "8083", "-d", "192.168.0.2", "-j", "DNAT", "--to-destination", "10.0.0.2:83"},
|
|
||||||
{"-p", "tcp", "--dport", "8084", "-j", "DNAT", "--to-destination", "10.0.0.2:84"},
|
|
||||||
}))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("generates a correct chain with external mark", func() {
|
|
||||||
ch := genDnatChain(netName, containerID)
|
|
||||||
|
|
||||||
Expect(ch).To(Equal(chain{
|
|
||||||
table: "nat",
|
|
||||||
name: "CNI-DN-bfd599665540dd91d5d28",
|
|
||||||
entryChains: []string{TopLevelDNATChainName},
|
|
||||||
}))
|
|
||||||
configBytes := []byte(`{
|
|
||||||
"name": "test",
|
|
||||||
"type": "portmap",
|
|
||||||
"cniVersion": "0.3.1",
|
|
||||||
"runtimeConfig": {
|
|
||||||
"portMappings": [
|
|
||||||
{ "hostPort": 8080, "containerPort": 80, "protocol": "tcp"}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"externalSetMarkChain": "PLZ-SET-MARK",
|
|
||||||
"conditionsV4": ["a", "b"],
|
|
||||||
"conditionsV6": ["c", "d"]
|
|
||||||
}`)
|
|
||||||
|
|
||||||
conf, _, err := parseConfig(configBytes, "foo")
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
conf.ContainerID = containerID
|
|
||||||
|
|
||||||
ch = genDnatChain(conf.Name, containerID)
|
|
||||||
n, err := types.ParseCIDR("10.0.0.2/24")
|
n, err := types.ParseCIDR("10.0.0.2/24")
|
||||||
fillDnatRules(&ch, conf, *n)
|
Expect(c.ContIPv4).To(Equal(*n))
|
||||||
Expect(ch.rules).To(Equal([][]string{
|
n, err = types.ParseCIDR("2001:db8:1::2/64")
|
||||||
{"-p", "tcp", "--dport", "8080", "-s", "10.0.0.2/24", "-j", "PLZ-SET-MARK"},
|
Expect(c.ContIPv6).To(Equal(*n))
|
||||||
{"-p", "tcp", "--dport", "8080", "-s", "127.0.0.1", "-j", "PLZ-SET-MARK"},
|
|
||||||
{"-p", "tcp", "--dport", "8080", "-j", "DNAT", "--to-destination", "10.0.0.2:80"},
|
|
||||||
}))
|
|
||||||
})
|
})
|
||||||
|
|
||||||
It("generates a correct top-level chain", func() {
|
It(fmt.Sprintf("[%s] correctly parses a DEL config", ver), func() {
|
||||||
ch := genToplevelDnatChain()
|
// When called with DEL, neither runtimeConfig nor prevResult may be specified
|
||||||
|
configBytes := []byte(fmt.Sprintf(`{
|
||||||
Expect(ch).To(Equal(chain{
|
"name": "test",
|
||||||
table: "nat",
|
"type": "portmap",
|
||||||
name: "CNI-HOSTPORT-DNAT",
|
"cniVersion": "%s",
|
||||||
entryChains: []string{"PREROUTING", "OUTPUT"},
|
"snat": false,
|
||||||
entryRules: [][]string{{"-m", "addrtype", "--dst-type", "LOCAL"}},
|
"conditionsV4": ["a", "b"],
|
||||||
}))
|
"conditionsV6": ["c", "d"]
|
||||||
|
}`, ver))
|
||||||
|
c, _, err := parseConfig(configBytes, "container")
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(c.CNIVersion).To(Equal(ver))
|
||||||
|
Expect(c.ConditionsV4).To(Equal(&[]string{"a", "b"}))
|
||||||
|
Expect(c.ConditionsV6).To(Equal(&[]string{"c", "d"}))
|
||||||
|
fvar := false
|
||||||
|
Expect(c.SNAT).To(Equal(&fvar))
|
||||||
|
Expect(c.Name).To(Equal("test"))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("generates the correct mark chains", func() {
|
It(fmt.Sprintf("[%s] fails with invalid mappings", ver), func() {
|
||||||
masqBit := 5
|
configBytes := []byte(fmt.Sprintf(`{
|
||||||
ch := genSetMarkChain(masqBit)
|
"name": "test",
|
||||||
Expect(ch).To(Equal(chain{
|
"type": "portmap",
|
||||||
table: "nat",
|
"cniVersion": "%s",
|
||||||
name: "CNI-HOSTPORT-SETMARK",
|
"snat": false,
|
||||||
rules: [][]string{{
|
"conditionsV4": ["a", "b"],
|
||||||
"-m", "comment",
|
"conditionsV6": ["c", "d"],
|
||||||
"--comment", "CNI portfwd masquerade mark",
|
"runtimeConfig": {
|
||||||
"-j", "MARK",
|
"portMappings": [
|
||||||
"--set-xmark", "0x20/0x20",
|
{ "hostPort": 0, "containerPort": 80, "protocol": "tcp"}
|
||||||
}},
|
]
|
||||||
}))
|
}
|
||||||
|
}`, ver))
|
||||||
|
_, _, err := parseConfig(configBytes, "container")
|
||||||
|
Expect(err).To(MatchError("Invalid host port number: 0"))
|
||||||
|
})
|
||||||
|
|
||||||
ch = genMarkMasqChain(masqBit)
|
It(fmt.Sprintf("[%s] does not fail on missing prevResult interface index", ver), func() {
|
||||||
Expect(ch).To(Equal(chain{
|
configBytes := []byte(fmt.Sprintf(`{
|
||||||
table: "nat",
|
"name": "test",
|
||||||
name: "CNI-HOSTPORT-MASQ",
|
"type": "portmap",
|
||||||
entryChains: []string{"POSTROUTING"},
|
"cniVersion": "%s",
|
||||||
entryRules: [][]string{{
|
"runtimeConfig": {
|
||||||
"-m", "comment",
|
"portMappings": [
|
||||||
"--comment", "CNI portfwd requiring masquerade",
|
{ "hostPort": 8080, "containerPort": 80, "protocol": "tcp"}
|
||||||
}},
|
]
|
||||||
rules: [][]string{{
|
},
|
||||||
"-m", "mark",
|
"conditionsV4": ["a", "b"],
|
||||||
"--mark", "0x20/0x20",
|
"prevResult": {
|
||||||
"-j", "MASQUERADE",
|
"interfaces": [
|
||||||
}},
|
{"name": "host"}
|
||||||
prependEntry: true,
|
],
|
||||||
}))
|
"ips": [
|
||||||
|
{
|
||||||
|
"version": "4",
|
||||||
|
"address": "10.0.0.1/24",
|
||||||
|
"gateway": "10.0.0.1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}`, ver))
|
||||||
|
_, _, err := parseConfig(configBytes, "container")
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
|
||||||
|
Describe("Generating chains", func() {
|
||||||
|
Context("for DNAT", func() {
|
||||||
|
It(fmt.Sprintf("[%s] generates a correct standard container chain", ver), func() {
|
||||||
|
ch := genDnatChain(netName, containerID)
|
||||||
|
|
||||||
|
Expect(ch).To(Equal(chain{
|
||||||
|
table: "nat",
|
||||||
|
name: "CNI-DN-bfd599665540dd91d5d28",
|
||||||
|
entryChains: []string{TopLevelDNATChainName},
|
||||||
|
}))
|
||||||
|
configBytes := []byte(fmt.Sprintf(`{
|
||||||
|
"name": "test",
|
||||||
|
"type": "portmap",
|
||||||
|
"cniVersion": "%s",
|
||||||
|
"runtimeConfig": {
|
||||||
|
"portMappings": [
|
||||||
|
{ "hostPort": 8080, "containerPort": 80, "protocol": "tcp"},
|
||||||
|
{ "hostPort": 8081, "containerPort": 80, "protocol": "tcp"},
|
||||||
|
{ "hostPort": 8080, "containerPort": 81, "protocol": "udp"},
|
||||||
|
{ "hostPort": 8082, "containerPort": 82, "protocol": "udp"},
|
||||||
|
{ "hostPort": 8083, "containerPort": 83, "protocol": "tcp", "hostIP": "192.168.0.2"},
|
||||||
|
{ "hostPort": 8084, "containerPort": 84, "protocol": "tcp", "hostIP": "0.0.0.0"},
|
||||||
|
{ "hostPort": 8085, "containerPort": 85, "protocol": "tcp", "hostIP": "2001:db8:a::1"},
|
||||||
|
{ "hostPort": 8086, "containerPort": 86, "protocol": "tcp", "hostIP": "::"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"snat": true,
|
||||||
|
"conditionsV4": ["a", "b"],
|
||||||
|
"conditionsV6": ["c", "d"]
|
||||||
|
}`, ver))
|
||||||
|
|
||||||
|
conf, _, err := parseConfig(configBytes, "foo")
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
conf.ContainerID = containerID
|
||||||
|
|
||||||
|
ch = genDnatChain(conf.Name, containerID)
|
||||||
|
Expect(ch).To(Equal(chain{
|
||||||
|
table: "nat",
|
||||||
|
name: "CNI-DN-67e92b96e692a494b6b85",
|
||||||
|
entryChains: []string{"CNI-HOSTPORT-DNAT"},
|
||||||
|
}))
|
||||||
|
|
||||||
|
n, err := types.ParseCIDR("10.0.0.2/24")
|
||||||
|
fillDnatRules(&ch, conf, *n)
|
||||||
|
|
||||||
|
Expect(ch.entryRules).To(Equal([][]string{
|
||||||
|
{"-m", "comment", "--comment",
|
||||||
|
fmt.Sprintf("dnat name: \"test\" id: \"%s\"", containerID),
|
||||||
|
"-m", "multiport",
|
||||||
|
"-p", "tcp",
|
||||||
|
"--destination-ports", "8080,8081,8083,8084,8085,8086",
|
||||||
|
"a", "b"},
|
||||||
|
{"-m", "comment", "--comment",
|
||||||
|
fmt.Sprintf("dnat name: \"test\" id: \"%s\"", containerID),
|
||||||
|
"-m", "multiport",
|
||||||
|
"-p", "udp",
|
||||||
|
"--destination-ports", "8080,8082",
|
||||||
|
"a", "b"},
|
||||||
|
}))
|
||||||
|
|
||||||
|
Expect(ch.rules).To(Equal([][]string{
|
||||||
|
// tcp rules and not hostIP
|
||||||
|
{"-p", "tcp", "--dport", "8080", "-s", "10.0.0.2/24", "-j", "CNI-HOSTPORT-SETMARK"},
|
||||||
|
{"-p", "tcp", "--dport", "8080", "-s", "127.0.0.1", "-j", "CNI-HOSTPORT-SETMARK"},
|
||||||
|
{"-p", "tcp", "--dport", "8080", "-j", "DNAT", "--to-destination", "10.0.0.2:80"},
|
||||||
|
{"-p", "tcp", "--dport", "8081", "-s", "10.0.0.2/24", "-j", "CNI-HOSTPORT-SETMARK"},
|
||||||
|
{"-p", "tcp", "--dport", "8081", "-s", "127.0.0.1", "-j", "CNI-HOSTPORT-SETMARK"},
|
||||||
|
{"-p", "tcp", "--dport", "8081", "-j", "DNAT", "--to-destination", "10.0.0.2:80"},
|
||||||
|
// udp rules and not hostIP
|
||||||
|
{"-p", "udp", "--dport", "8080", "-s", "10.0.0.2/24", "-j", "CNI-HOSTPORT-SETMARK"},
|
||||||
|
{"-p", "udp", "--dport", "8080", "-s", "127.0.0.1", "-j", "CNI-HOSTPORT-SETMARK"},
|
||||||
|
{"-p", "udp", "--dport", "8080", "-j", "DNAT", "--to-destination", "10.0.0.2:81"},
|
||||||
|
{"-p", "udp", "--dport", "8082", "-s", "10.0.0.2/24", "-j", "CNI-HOSTPORT-SETMARK"},
|
||||||
|
{"-p", "udp", "--dport", "8082", "-s", "127.0.0.1", "-j", "CNI-HOSTPORT-SETMARK"},
|
||||||
|
{"-p", "udp", "--dport", "8082", "-j", "DNAT", "--to-destination", "10.0.0.2:82"},
|
||||||
|
// tcp rules and hostIP
|
||||||
|
{"-p", "tcp", "--dport", "8083", "-d", "192.168.0.2", "-s", "10.0.0.2/24", "-j", "CNI-HOSTPORT-SETMARK"},
|
||||||
|
{"-p", "tcp", "--dport", "8083", "-d", "192.168.0.2", "-s", "127.0.0.1", "-j", "CNI-HOSTPORT-SETMARK"},
|
||||||
|
{"-p", "tcp", "--dport", "8083", "-d", "192.168.0.2", "-j", "DNAT", "--to-destination", "10.0.0.2:83"},
|
||||||
|
// tcp rules and hostIP = "0.0.0.0"
|
||||||
|
{"-p", "tcp", "--dport", "8084", "-s", "10.0.0.2/24", "-j", "CNI-HOSTPORT-SETMARK"},
|
||||||
|
{"-p", "tcp", "--dport", "8084", "-s", "127.0.0.1", "-j", "CNI-HOSTPORT-SETMARK"},
|
||||||
|
{"-p", "tcp", "--dport", "8084", "-j", "DNAT", "--to-destination", "10.0.0.2:84"},
|
||||||
|
}))
|
||||||
|
|
||||||
|
ch.rules = nil
|
||||||
|
ch.entryRules = nil
|
||||||
|
|
||||||
|
n, err = types.ParseCIDR("2001:db8::2/64")
|
||||||
|
fillDnatRules(&ch, conf, *n)
|
||||||
|
|
||||||
|
Expect(ch.rules).To(Equal([][]string{
|
||||||
|
// tcp rules and not hostIP
|
||||||
|
{"-p", "tcp", "--dport", "8080", "-s", "2001:db8::2/64", "-j", "CNI-HOSTPORT-SETMARK"},
|
||||||
|
{"-p", "tcp", "--dport", "8080", "-j", "DNAT", "--to-destination", "[2001:db8::2]:80"},
|
||||||
|
{"-p", "tcp", "--dport", "8081", "-s", "2001:db8::2/64", "-j", "CNI-HOSTPORT-SETMARK"},
|
||||||
|
{"-p", "tcp", "--dport", "8081", "-j", "DNAT", "--to-destination", "[2001:db8::2]:80"},
|
||||||
|
// udp rules and not hostIP
|
||||||
|
{"-p", "udp", "--dport", "8080", "-s", "2001:db8::2/64", "-j", "CNI-HOSTPORT-SETMARK"},
|
||||||
|
{"-p", "udp", "--dport", "8080", "-j", "DNAT", "--to-destination", "[2001:db8::2]:81"},
|
||||||
|
{"-p", "udp", "--dport", "8082", "-s", "2001:db8::2/64", "-j", "CNI-HOSTPORT-SETMARK"},
|
||||||
|
{"-p", "udp", "--dport", "8082", "-j", "DNAT", "--to-destination", "[2001:db8::2]:82"},
|
||||||
|
// tcp rules and hostIP
|
||||||
|
{"-p", "tcp", "--dport", "8085", "-d", "2001:db8:a::1", "-s", "2001:db8::2/64", "-j", "CNI-HOSTPORT-SETMARK"},
|
||||||
|
{"-p", "tcp", "--dport", "8085", "-d", "2001:db8:a::1", "-j", "DNAT", "--to-destination", "[2001:db8::2]:85"},
|
||||||
|
// tcp rules and hostIP = "::"
|
||||||
|
{"-p", "tcp", "--dport", "8086", "-s", "2001:db8::2/64", "-j", "CNI-HOSTPORT-SETMARK"},
|
||||||
|
{"-p", "tcp", "--dport", "8086", "-j", "DNAT", "--to-destination", "[2001:db8::2]:86"},
|
||||||
|
}))
|
||||||
|
|
||||||
|
// Disable snat, generate rules
|
||||||
|
ch.rules = nil
|
||||||
|
ch.entryRules = nil
|
||||||
|
fvar := false
|
||||||
|
conf.SNAT = &fvar
|
||||||
|
|
||||||
|
n, err = types.ParseCIDR("10.0.0.2/24")
|
||||||
|
fillDnatRules(&ch, conf, *n)
|
||||||
|
Expect(ch.rules).To(Equal([][]string{
|
||||||
|
{"-p", "tcp", "--dport", "8080", "-j", "DNAT", "--to-destination", "10.0.0.2:80"},
|
||||||
|
{"-p", "tcp", "--dport", "8081", "-j", "DNAT", "--to-destination", "10.0.0.2:80"},
|
||||||
|
{"-p", "udp", "--dport", "8080", "-j", "DNAT", "--to-destination", "10.0.0.2:81"},
|
||||||
|
{"-p", "udp", "--dport", "8082", "-j", "DNAT", "--to-destination", "10.0.0.2:82"},
|
||||||
|
{"-p", "tcp", "--dport", "8083", "-d", "192.168.0.2", "-j", "DNAT", "--to-destination", "10.0.0.2:83"},
|
||||||
|
{"-p", "tcp", "--dport", "8084", "-j", "DNAT", "--to-destination", "10.0.0.2:84"},
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
|
||||||
|
It(fmt.Sprintf("[%s] generates a correct chain with external mark", ver), func() {
|
||||||
|
ch := genDnatChain(netName, containerID)
|
||||||
|
|
||||||
|
Expect(ch).To(Equal(chain{
|
||||||
|
table: "nat",
|
||||||
|
name: "CNI-DN-bfd599665540dd91d5d28",
|
||||||
|
entryChains: []string{TopLevelDNATChainName},
|
||||||
|
}))
|
||||||
|
configBytes := []byte(fmt.Sprintf(`{
|
||||||
|
"name": "test",
|
||||||
|
"type": "portmap",
|
||||||
|
"cniVersion": "%s",
|
||||||
|
"runtimeConfig": {
|
||||||
|
"portMappings": [
|
||||||
|
{ "hostPort": 8080, "containerPort": 80, "protocol": "tcp"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"externalSetMarkChain": "PLZ-SET-MARK",
|
||||||
|
"conditionsV4": ["a", "b"],
|
||||||
|
"conditionsV6": ["c", "d"]
|
||||||
|
}`, ver))
|
||||||
|
|
||||||
|
conf, _, err := parseConfig(configBytes, "foo")
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
conf.ContainerID = containerID
|
||||||
|
|
||||||
|
ch = genDnatChain(conf.Name, containerID)
|
||||||
|
n, err := types.ParseCIDR("10.0.0.2/24")
|
||||||
|
fillDnatRules(&ch, conf, *n)
|
||||||
|
Expect(ch.rules).To(Equal([][]string{
|
||||||
|
{"-p", "tcp", "--dport", "8080", "-s", "10.0.0.2/24", "-j", "PLZ-SET-MARK"},
|
||||||
|
{"-p", "tcp", "--dport", "8080", "-s", "127.0.0.1", "-j", "PLZ-SET-MARK"},
|
||||||
|
{"-p", "tcp", "--dport", "8080", "-j", "DNAT", "--to-destination", "10.0.0.2:80"},
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
|
||||||
|
It(fmt.Sprintf("[%s] generates a correct top-level chain", ver), func() {
|
||||||
|
ch := genToplevelDnatChain()
|
||||||
|
|
||||||
|
Expect(ch).To(Equal(chain{
|
||||||
|
table: "nat",
|
||||||
|
name: "CNI-HOSTPORT-DNAT",
|
||||||
|
entryChains: []string{"PREROUTING", "OUTPUT"},
|
||||||
|
entryRules: [][]string{{"-m", "addrtype", "--dst-type", "LOCAL"}},
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
|
||||||
|
It(fmt.Sprintf("[%s] generates the correct mark chains", ver), func() {
|
||||||
|
masqBit := 5
|
||||||
|
ch := genSetMarkChain(masqBit)
|
||||||
|
Expect(ch).To(Equal(chain{
|
||||||
|
table: "nat",
|
||||||
|
name: "CNI-HOSTPORT-SETMARK",
|
||||||
|
rules: [][]string{{
|
||||||
|
"-m", "comment",
|
||||||
|
"--comment", "CNI portfwd masquerade mark",
|
||||||
|
"-j", "MARK",
|
||||||
|
"--set-xmark", "0x20/0x20",
|
||||||
|
}},
|
||||||
|
}))
|
||||||
|
|
||||||
|
ch = genMarkMasqChain(masqBit)
|
||||||
|
Expect(ch).To(Equal(chain{
|
||||||
|
table: "nat",
|
||||||
|
name: "CNI-HOSTPORT-MASQ",
|
||||||
|
entryChains: []string{"POSTROUTING"},
|
||||||
|
entryRules: [][]string{{
|
||||||
|
"-m", "comment",
|
||||||
|
"--comment", "CNI portfwd requiring masquerade",
|
||||||
|
}},
|
||||||
|
rules: [][]string{{
|
||||||
|
"-m", "mark",
|
||||||
|
"--mark", "0x20/0x20",
|
||||||
|
"-j", "MASQUERADE",
|
||||||
|
}},
|
||||||
|
prependEntry: true,
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
Loading…
x
Reference in New Issue
Block a user