def _test_global_peers(self, backend='bird'):
        """
        Test global BGP peer configuration.

        Test by turning off the mesh and configuring the mesh as
        a set of global peers.
        """
        with DockerHost('host1',
                        additional_docker_options=CLUSTER_STORE_DOCKER_OPTIONS,
                        start_calico=False) as host1, \
             DockerHost('host2',
                        additional_docker_options=CLUSTER_STORE_DOCKER_OPTIONS,
                        start_calico=False) as host2:
            # Start both hosts using specific AS numbers.
            host1.start_calico_node("--backend=%s --as=%s" %
                                    (backend, LARGE_AS_NUM))
            host2.start_calico_node("--backend=%s --as=%s" %
                                    (backend, LARGE_AS_NUM))

            # Create a network and a couple of workloads on each host.
            network1 = host1.create_network("subnet1",
                                            subnet=DEFAULT_IPV4_POOL_CIDR)
            workload_host1 = host1.create_workload("workload1",
                                                   network=network1,
                                                   ip=DEFAULT_IPV4_ADDR_1)
            workload_host2 = host2.create_workload("workload2",
                                                   network=network1,
                                                   ip=DEFAULT_IPV4_ADDR_2)

            # Allow network to converge
            self.assert_true(
                workload_host1.check_can_ping(DEFAULT_IPV4_ADDR_2, retries=10))

            # Turn the node-to-node mesh off and wait for connectivity to drop.
            host1.calicoctl("config set nodeToNodeMesh off")
            self.assert_true(
                workload_host1.check_cant_ping(DEFAULT_IPV4_ADDR_2,
                                               retries=10))

            # Configure global peers to explicitly set up a mesh.  This means
            # each node will try to peer with itself which will fail.
            create_bgp_peer(host1, 'global', host2.ip, LARGE_AS_NUM)
            create_bgp_peer(host2, 'global', host1.ip, LARGE_AS_NUM)

            # Allow network to converge
            self.assert_true(
                workload_host1.check_can_ping(DEFAULT_IPV4_ADDR_2, retries=10))

            # Check connectivity in both directions
            self.assert_ip_connectivity(
                workload_list=[workload_host1, workload_host2],
                ip_pass_list=[DEFAULT_IPV4_ADDR_1, DEFAULT_IPV4_ADDR_2])

            # Check the BGP status on each host.  Connections from a node to
            # itself will be idle since this is invalid BGP configuration.
            check_bird_status(host1, [("global", host1.ip, ["Idle", "Active"]),
                                      ("global", host2.ip, "Established")])
            check_bird_status(host2,
                              [("global", host1.ip, "Established"),
                               ("global", host2.ip, ["Idle", "Active"])])
    def test_global_peers(self):
        """
        Test global BGP peer configuration.

        Test by turning off the mesh and configuring the mesh as
        a set of global peers.
        """
        with DockerHost('host1', start_calico=False) as host1, \
             DockerHost('host2', start_calico=False) as host2:

            # Start both hosts using specific AS numbers.
            host1.start_calico_node("--as=%s" % LARGE_AS_NUM)
            host2.start_calico_node("--as=%s" % LARGE_AS_NUM)

            # Create the network on host1, but it should be usable from all
            # hosts.
            workload_host1 = host1.create_workload("workload1")
            workload_host2 = host2.create_workload("workload2")

            # Create a profile to associate with both workloads
            host1.calicoctl("profile add TEST_GROUP")

            # Add the workloads to Calico networking
            host1.calicoctl("container add %s %s" %
                            (workload_host1, DEFAULT_IPV4_ADDR_1))
            host2.calicoctl("container add %s %s" %
                            (workload_host2, DEFAULT_IPV4_ADDR_2))

            # Now add the profiles - one using set and one using append
            host1.calicoctl("container %s profile set TEST_GROUP" %
                            workload_host1)
            host2.calicoctl("container %s profile append TEST_GROUP" %
                            workload_host2)

            # Allow network to converge
            workload_host1.assert_can_ping(DEFAULT_IPV4_ADDR_2, retries=10)

            # Turn the node-to-node mesh off and wait for connectivity to drop.
            host1.calicoctl("bgp node-mesh off")
            workload_host1.assert_cant_ping(DEFAULT_IPV4_ADDR_2, retries=10)

            # Configure global peers to explicitly set up a mesh.  This means
            # each node will try to peer with itself which will fail.
            host1.calicoctl("bgp peer add %s as %s" % (host2.ip, LARGE_AS_NUM))
            host1.calicoctl("bgp peer add %s as %s" % (host1.ip, LARGE_AS_NUM))

            # Allow network to converge
            workload_host1.assert_can_ping(DEFAULT_IPV4_ADDR_2, retries=10)

            # Check connectivity in both directions
            self.assert_ip_connectivity(
                workload_list=[workload_host1, workload_host2],
                ip_pass_list=[DEFAULT_IPV4_ADDR_1, DEFAULT_IPV4_ADDR_2])

            # Check the BGP status on each host.  Connections from a node to
            # itself will be idle since this is invalid BGP configuration.
            check_bird_status(host1, [("global", host1.ip, "Idle"),
                                      ("global", host2.ip, "Established")])
            check_bird_status(host2, [("global", host1.ip, "Established"),
                                      ("global", host2.ip, "Idle")])
    def test_node_peers(self):
        """
        Test per-node BGP peer configuration.

        Test by turning off the mesh and configuring the mesh as
        a set of per node peers.
        """
        with DockerHost('host1', start_calico=False) as host1, \
             DockerHost('host2', start_calico=False) as host2:

            # Start both hosts using specific AS numbers.
            host1.start_calico_node("--as=%s" % LARGE_AS_NUM)
            host2.start_calico_node("--as=%s" % LARGE_AS_NUM)

            # Create a profile to associate with both workloads
            host1.calicoctl("profile add TEST_GROUP")

            # Create the network on host1, but it should be usable from all
            # hosts.
            workload_host1 = host1.create_workload("workload1",
                                                   network=NET_NONE)
            workload_host2 = host2.create_workload("workload2",
                                                   network=NET_NONE)

            # Add the workloads to Calico networking
            host1.calicoctl("container add %s %s" % (workload_host1,
                                                     DEFAULT_IPV4_ADDR_1))
            host2.calicoctl("container add %s %s" % (workload_host2,
                                                     DEFAULT_IPV4_ADDR_2))

            # Now add the profiles - one using set and one using append
            host1.calicoctl("container %s profile set TEST_GROUP" % workload_host1)
            host2.calicoctl("container %s profile append TEST_GROUP" % workload_host2)

            # Allow network to converge
            workload_host1.assert_can_ping(DEFAULT_IPV4_ADDR_2, retries=10)

            # Turn the node-to-node mesh off and wait for connectivity to drop.
            host1.calicoctl("bgp node-mesh off")
            workload_host1.assert_cant_ping(DEFAULT_IPV4_ADDR_2, retries=10)

            # Configure per-node peers to explicitly set up a mesh.
            host1.calicoctl("node bgp peer add %s as %s" % (host2.ip,
                                                            LARGE_AS_NUM))
            host2.calicoctl("node bgp peer add %s as %s" % (host1.ip,
                                                            LARGE_AS_NUM))

            # Allow network to converge
            workload_host1.assert_can_ping(DEFAULT_IPV4_ADDR_2, retries=10)

            # Check connectivity in both directions
            self.assert_ip_connectivity(workload_list=[workload_host1,
                                                       workload_host2],
                                        ip_pass_list=[DEFAULT_IPV4_ADDR_1,
                                                      DEFAULT_IPV4_ADDR_2])

            # Check the BGP status on each host.
            check_bird_status(host1, [("node specific", host2.ip, "Established")])
            check_bird_status(host2, [("node specific", host1.ip, "Established")])
    def test_global_peers(self):
        """
        Test global BGP peer configuration.

        Test by turning off the mesh and configuring the mesh as
        a set of global peers.
        """
        with DockerHost('host1', start_calico=False) as host1, \
             DockerHost('host2', start_calico=False) as host2:

            # Start both hosts using specific AS numbers.
            host1.start_calico_node(as_num=LARGE_AS_NUM)
            host2.start_calico_node(as_num=LARGE_AS_NUM)

            # Create the network on host1, but it should be usable from all
            # hosts.
            workload_host1 = host1.create_workload("workload1")
            workload_host2 = host2.create_workload("workload2")

            # Create a profile to associate with both workloads
            host1.calicoctl("profile add TEST_GROUP")

            # Add the workloads to Calico networking
            host1.calicoctl("container add %s %s" % (workload_host1,
                                                     DEFAULT_IPV4_ADDR_1))
            host2.calicoctl("container add %s %s" % (workload_host2,
                                                     DEFAULT_IPV4_ADDR_2))

            # Now add the profiles - one using set and one using append
            host1.calicoctl("container %s profile set TEST_GROUP" % workload_host1)
            host2.calicoctl("container %s profile append TEST_GROUP" % workload_host2)

            # Allow network to converge
            workload_host1.assert_can_ping(DEFAULT_IPV4_ADDR_2, retries=10)

            # Turn the node-to-node mesh off and wait for connectivity to drop.
            host1.calicoctl("bgp node-mesh off")
            workload_host1.assert_cant_ping(DEFAULT_IPV4_ADDR_2, retries=10)

            # Configure global peers to explicitly set up a mesh.  This means
            # each node will try to peer with itself which will fail.
            host1.calicoctl("bgp peer add %s as %s" % (host2.ip, LARGE_AS_NUM))
            host1.calicoctl("bgp peer add %s as %s" % (host1.ip, LARGE_AS_NUM))

            # Allow network to converge
            workload_host1.assert_can_ping(DEFAULT_IPV4_ADDR_2, retries=10)

            # Check connectivity in both directions
            self.assert_ip_connectivity(workload_list=[workload_host1,
                                                       workload_host2],
                                        ip_pass_list=[DEFAULT_IPV4_ADDR_1,
                                                      DEFAULT_IPV4_ADDR_2])

            # Check the BGP status on each host.  Connections from a node to
            # itself will be idle since this is invalid BGP configuration.
            check_bird_status(host1, [("global", host1.ip, "Idle"),
                                       ("global", host2.ip, "Established")])
            check_bird_status(host2, [("global", host1.ip, "Established"),
                                       ("global", host2.ip, "Idle")])
Beispiel #5
0
    def test_bgp_backends(self):
        """
        Test using different BGP backends.

        We run a multi-host test for this to test peering between two gobgp
        backends and a single BIRD backend.
        """
        with DockerHost('host1',
                        additional_docker_options=CLUSTER_STORE_DOCKER_OPTIONS,
                        start_calico=False) as host1, \
             DockerHost('host2',
                        additional_docker_options=CLUSTER_STORE_DOCKER_OPTIONS,
                        start_calico=False) as host2, \
             DockerHost('host3',
                        additional_docker_options=CLUSTER_STORE_DOCKER_OPTIONS,
                        start_calico=True) as host3:

            # Set the default AS number.
            update_bgp_config(host1, asNum=LARGE_AS_NUM)

            # Start host1 using the inherited AS, and host2 using a specified
            # AS (same as default).  These hosts use the gobgp backend, whereas
            # host3 uses BIRD.
            host1.start_calico_node("--backend=gobgp")
            host2.start_calico_node("--backend=gobgp --as=%s" % LARGE_AS_NUM)

            # Create a network and a couple of workloads on each host.
            network1 = host1.create_network("subnet1",
                                            subnet=DEFAULT_IPV4_POOL_CIDR)
            workload_host1 = host1.create_workload("workload1",
                                                   network=network1,
                                                   ip=DEFAULT_IPV4_ADDR_1)
            workload_host2 = host2.create_workload("workload2",
                                                   network=network1,
                                                   ip=DEFAULT_IPV4_ADDR_2)
            workload_host3 = host3.create_workload("workload3",
                                                   network=network1,
                                                   ip=DEFAULT_IPV4_ADDR_3)

            # Allow network to converge
            self.assert_true(
                workload_host1.check_can_ping(workload_host2.ip, retries=10))

            # Check connectivity in both directions
            self.assert_ip_connectivity(
                workload_list=[workload_host1, workload_host2, workload_host3],
                ip_pass_list=[
                    workload_host1.ip, workload_host2.ip, workload_host3.ip
                ])

            # Check the BGP status on the BIRD/GoBGP host.
            hosts = [host1, host2, host3]
            for target in hosts:
                expected = [("node-to-node mesh", h.ip, "Established")
                            for h in hosts if h is not target]
                check_bird_status(target, expected)
Beispiel #6
0
    def test_node_peers(self):
        """
        Test per-node BGP peer configuration.

        Test by turning off the mesh and configuring the mesh as
        a set of per node peers.
        """
        with DockerHost('host1',
                        additional_docker_options=ADDITIONAL_DOCKER_OPTIONS,
                        start_calico=False) as host1, \
             DockerHost('host2',
                        additional_docker_options=ADDITIONAL_DOCKER_OPTIONS,
                        start_calico=False) as host2:

            # Start both hosts using specific AS numbers.
            host1.start_calico_node("--as=%s" % LARGE_AS_NUM)
            host2.start_calico_node("--as=%s" % LARGE_AS_NUM)

            # Create a network and a couple of workloads on each host.
            network1 = host1.create_network("subnet1",
                                            subnet=DEFAULT_IPV4_POOL_CIDR)
            workload_host1 = host1.create_workload("workload1",
                                                   network=network1,
                                                   ip=DEFAULT_IPV4_ADDR_1)
            workload_host2 = host2.create_workload("workload2",
                                                   network=network1,
                                                   ip=DEFAULT_IPV4_ADDR_2)

            # Allow network to converge
            self.assert_true(
                workload_host1.check_can_ping(DEFAULT_IPV4_ADDR_2, retries=10))

            # Turn the node-to-node mesh off and wait for connectivity to drop.
            host1.calicoctl("config set nodeToNodeMesh off")
            self.assert_true(
                workload_host1.check_cant_ping(DEFAULT_IPV4_ADDR_2,
                                               retries=10))

            # Configure node specific peers to explicitly set up a mesh.
            create_bgp_peer(host1, 'node', host2.ip, LARGE_AS_NUM)
            create_bgp_peer(host2, 'node', host1.ip, LARGE_AS_NUM)

            # Allow network to converge
            self.assert_true(
                workload_host1.check_can_ping(DEFAULT_IPV4_ADDR_2, retries=10))

            # Check connectivity in both directions
            self.assert_ip_connectivity(
                workload_list=[workload_host1, workload_host2],
                ip_pass_list=[DEFAULT_IPV4_ADDR_1, DEFAULT_IPV4_ADDR_2])

            # Check the BGP status on each host.
            check_bird_status(host1,
                              [("node specific", host2.ip, "Established")])
            check_bird_status(host2,
                              [("node specific", host1.ip, "Established")])
Beispiel #7
0
    def _test_single_route_reflector(self,
                                     backend='bird',
                                     bgpconfig_as_num=64514,
                                     peer_as_num=64514):
        """
        Run a multi-host test using a single route reflector and global
        peering.
        """
        with DockerHost('host1',
                        additional_docker_options=CLUSTER_STORE_DOCKER_OPTIONS,
                        start_calico=False) as host1, \
             DockerHost('host2',
                        additional_docker_options=CLUSTER_STORE_DOCKER_OPTIONS,
                        start_calico=False) as host2, \
             RouteReflectorCluster(1, 1) as rrc:

            # Start both hosts using specific backends.
            host1.start_calico_node("--backend=%s" % backend)
            host2.start_calico_node("--backend=%s" % backend)

            # Set the default AS number - as this is used by the RR mesh, and
            # turn off the node-to-node mesh (do this from any host).
            update_bgp_config(host1, nodeMesh=False, asNum=bgpconfig_as_num)

            # Create a workload on each host in the same network.
            network1 = host1.create_network("subnet1")
            workload_host1 = host1.create_workload("workload1",
                                                   network=network1)
            workload_host2 = host2.create_workload("workload2",
                                                   network=network1)

            # Allow network to converge (which it won't)
            self.assert_false(
                workload_host1.check_can_ping(workload_host2.ip, retries=5))

            # Set global config telling all calico nodes to peer with the
            # route reflector.  This can be run from either host.
            rg = rrc.get_redundancy_group()
            assert len(rg) == 1
            create_bgp_peer(host1, "global", rg[0].ip, peer_as_num)

            # Allow network to converge (which it now will).
            retry_until_success(host1.assert_is_ready, retries=30, felix=False)
            retry_until_success(host2.assert_is_ready, retries=30, felix=False)
            check_bird_status(host1, [("global", rg[0].ip, "Established")])
            check_bird_status(host2, [("global", rg[0].ip, "Established")])
            self.assert_true(
                workload_host1.check_can_ping(workload_host2.ip, retries=20))

            # And check connectivity in both directions.
            self.assert_ip_connectivity(
                workload_list=[workload_host1, workload_host2],
                ip_pass_list=[workload_host1.ip, workload_host2.ip])
    def test_as_num(self):
        """
        Test using different AS number for the node-to-node mesh.

        We run a multi-host test for this as we need to set up real BGP peers.
        """
        with DockerHost('host1', start_calico=False) as host1, \
             DockerHost('host2', start_calico=False) as host2:

            # Set the default AS number.
            host1.calicoctl("bgp default-node-as %s" % LARGE_AS_NUM)

            # Start host1 using the inherited AS, and host2 using a specified
            # AS (same as default).
            host1.start_calico_node()
            host2.start_calico_node(as_num=LARGE_AS_NUM)

            # Create a profile to associate with both workloads
            host1.calicoctl("profile add TEST_GROUP")

            # Create the network on host1, but it should be usable from all
            # hosts.
            workload_host1 = host1.create_workload("workload1")
            workload_host2 = host2.create_workload("workload2")

            # Add the workloads to Calico networking
            host1.calicoctl("container add %s %s" %
                            (workload_host1, DEFAULT_IPV4_ADDR_1))
            host2.calicoctl("container add %s %s" %
                            (workload_host2, DEFAULT_IPV4_ADDR_2))

            # Now add the profiles - one using set and one using append
            host1.calicoctl("container %s profile set TEST_GROUP" %
                            workload_host1)
            host2.calicoctl("container %s profile append TEST_GROUP" %
                            workload_host2)

            # Allow network to converge
            workload_host1.assert_can_ping(DEFAULT_IPV4_ADDR_2, retries=10)

            # Check connectivity in both directions
            self.assert_ip_connectivity(
                workload_list=[workload_host1, workload_host2],
                ip_pass_list=[DEFAULT_IPV4_ADDR_1, DEFAULT_IPV4_ADDR_2])

            # Check the BGP status on each host.
            check_bird_status(host1,
                              [("node-to-node mesh", host2.ip, "Established")])
            check_bird_status(host2,
                              [("node-to-node mesh", host1.ip, "Established")])
    def test_as_num(self):
        """
        Test using different AS number for the node-to-node mesh.

        We run a multi-host test for this as we need to set up real BGP peers.
        """
        with DockerHost('host1', start_calico=False) as host1, \
             DockerHost('host2', start_calico=False) as host2:

            # Set the default AS number.
            host1.calicoctl("bgp default-node-as %s" % LARGE_AS_NUM)

            # Start host1 using the inherited AS, and host2 using a specified
            # AS (same as default).
            host1.start_calico_node()
            host2.start_calico_node("--as=%s" % LARGE_AS_NUM)

            # Create a profile to associate with both workloads
            host1.calicoctl("profile add TEST_GROUP")

            # Create the network on host1, but it should be usable from all
            # hosts.
            workload_host1 = host1.create_workload("workload1")
            workload_host2 = host2.create_workload("workload2")

            # Add the workloads to Calico networking
            host1.calicoctl(
                "container add %s %s" % (workload_host1, DEFAULT_IPV4_ADDR_1))
            host2.calicoctl(
                "container add %s %s" % (workload_host2, DEFAULT_IPV4_ADDR_2))

            # Now add the profiles - one using set and one using append
            host1.calicoctl(
                "container %s profile set TEST_GROUP" % workload_host1)
            host2.calicoctl(
                "container %s profile append TEST_GROUP" % workload_host2)

            # Allow network to converge
            workload_host1.assert_can_ping(DEFAULT_IPV4_ADDR_2, retries=10)

            # Check connectivity in both directions
            self.assert_ip_connectivity(
                workload_list=[workload_host1, workload_host2],
                ip_pass_list=[DEFAULT_IPV4_ADDR_1, DEFAULT_IPV4_ADDR_2])

            # Check the BGP status on each host.
            check_bird_status(host1,
                              [("node-to-node mesh", host2.ip, "Established")])
            check_bird_status(host2,
                              [("node-to-node mesh", host1.ip, "Established")])
    def test_bgp_backends(self):
        """
        Test using different BGP backends.

        We run a multi-host test for this to test peering between two gobgp
        backends and a single BIRD backend.
        """
        with DockerHost('host1',
                        additional_docker_options=ADDITIONAL_DOCKER_OPTIONS,
                        start_calico=False) as host1, \
             DockerHost('host2',
                        additional_docker_options=ADDITIONAL_DOCKER_OPTIONS,
                        start_calico=False) as host2, \
             DockerHost('host3',
                        additional_docker_options=ADDITIONAL_DOCKER_OPTIONS,
                        start_calico=True) as host3:

            # Set the default AS number.
            host1.calicoctl("config set asNumber %s" % LARGE_AS_NUM)

            # Start host1 using the inherited AS, and host2 using a specified
            # AS (same as default).  These hosts use the gobgp backend, whereas
            # host3 uses BIRD.
            host1.start_calico_node("--backend=gobgp")
            host2.start_calico_node("--backend=gobgp --as=%s" % LARGE_AS_NUM)

            # Create a network and a couple of workloads on each host.
            network1 = host1.create_network("subnet1")
            workload_host1 = host1.create_workload("workload1",
                                                   network=network1)
            workload_host2 = host2.create_workload("workload2",
                                                   network=network1)
            workload_host3 = host3.create_workload("workload3",
                                                   network=network1)

            # Allow network to converge
            self.assert_true(
                workload_host1.check_can_ping(workload_host2.ip, retries=10))

            # Check connectivity in both directions
            self.assert_ip_connectivity(
                workload_list=[workload_host1, workload_host2, workload_host3],
                ip_pass_list=[
                    workload_host1.ip, workload_host2.ip, workload_host3.ip
                ])

            # Check the BGP status on the BIRD host.
            check_bird_status(host3,
                              [("node-to-node mesh", host1.ip, "Established"),
                               ("node-to-node mesh", host2.ip, "Established")])
    def _test_global_peers(self, backend='bird'):
        """
        Test global BGP peer configuration.

        Test by turning off the mesh and configuring the mesh as
        a set of global peers.
        """
        with DockerHost('host1',
                        additional_docker_options=CLUSTER_STORE_DOCKER_OPTIONS,
                        start_calico=False) as host1, \
             DockerHost('host2',
                        additional_docker_options=CLUSTER_STORE_DOCKER_OPTIONS,
                        start_calico=False) as host2:
            # Start both hosts using specific AS numbers.
            host1.start_calico_node("--backend=%s --as=%s" % (backend, LARGE_AS_NUM))
            host2.start_calico_node("--backend=%s --as=%s" % (backend, LARGE_AS_NUM))

            # Create a network and a couple of workloads on each host.
            network1 = host1.create_network("subnet1", subnet=DEFAULT_IPV4_POOL_CIDR)
            workload_host1 = host1.create_workload("workload1", network=network1, ip=DEFAULT_IPV4_ADDR_1)
            workload_host2 = host2.create_workload("workload2", network=network1, ip=DEFAULT_IPV4_ADDR_2)

            # Allow network to converge
            self.assert_true(workload_host1.check_can_ping(DEFAULT_IPV4_ADDR_2, retries=10))

            # Turn the node-to-node mesh off and wait for connectivity to drop.
            host1.calicoctl("config set nodeToNodeMesh off")
            self.assert_true(workload_host1.check_cant_ping(DEFAULT_IPV4_ADDR_2, retries=10))

            # Configure global peers to explicitly set up a mesh.  This means
            # each node will try to peer with itself which will fail.
            create_bgp_peer(host1, 'global', host2.ip, LARGE_AS_NUM)
            create_bgp_peer(host2, 'global', host1.ip, LARGE_AS_NUM)

            # Allow network to converge
            self.assert_true(workload_host1.check_can_ping(DEFAULT_IPV4_ADDR_2, retries=10))

            # Check connectivity in both directions
            self.assert_ip_connectivity(workload_list=[workload_host1,
                                                       workload_host2],
                                        ip_pass_list=[DEFAULT_IPV4_ADDR_1,
                                                      DEFAULT_IPV4_ADDR_2])

            # Check the BGP status on each host.  Connections from a node to
            # itself will be idle since this is invalid BGP configuration.
            check_bird_status(host1, [("global", host1.ip, ["Idle", "Active"]),
                                       ("global", host2.ip, "Established")])
            check_bird_status(host2, [("global", host1.ip, "Established"),
                                       ("global", host2.ip, ["Idle", "Active"])])
Beispiel #12
0
    def test_bgp_backends(self):
        """
        Test using different BGP backends.

        We run a multi-host test for this to test peering between two gobgp
        backends and a single BIRD backend.
        """
        with DockerHost('host1',
                        additional_docker_options=CLUSTER_STORE_DOCKER_OPTIONS,
                        start_calico=False) as host1, \
             DockerHost('host2',
                        additional_docker_options=CLUSTER_STORE_DOCKER_OPTIONS,
                        start_calico=False) as host2, \
             DockerHost('host3',
                        additional_docker_options=CLUSTER_STORE_DOCKER_OPTIONS,
                        start_calico=True) as host3:

            # Set the default AS number.
            host1.calicoctl("config set asNumber %s" % LARGE_AS_NUM)

            # Start host1 using the inherited AS, and host2 using a specified
            # AS (same as default).  These hosts use the gobgp backend, whereas
            # host3 uses BIRD.
            host1.start_calico_node("--backend=gobgp")
            host2.start_calico_node("--backend=gobgp --as=%s" % LARGE_AS_NUM)

            # Create a network and a couple of workloads on each host.
            network1 = host1.create_network("subnet1", subnet=DEFAULT_IPV4_POOL_CIDR)
            workload_host1 = host1.create_workload("workload1", network=network1, ip=DEFAULT_IPV4_ADDR_1)
            workload_host2 = host2.create_workload("workload2", network=network1, ip=DEFAULT_IPV4_ADDR_2)
            workload_host3 = host3.create_workload("workload3", network=network1, ip=DEFAULT_IPV4_ADDR_3)

            # Allow network to converge
            self.assert_true(workload_host1.check_can_ping(workload_host2.ip, retries=10))

            # Check connectivity in both directions
            self.assert_ip_connectivity(workload_list=[workload_host1,
                                                       workload_host2,
                                                       workload_host3],
                                        ip_pass_list=[workload_host1.ip,
                                                      workload_host2.ip,
                                                      workload_host3.ip])

            # Check the BGP status on the BIRD/GoBGP host.
            hosts = [host1, host2, host3]
            for target in hosts:
                expected = [("node-to-node mesh", h.ip, "Established") for h in hosts if h is not target]
                check_bird_status(target, expected)
    def test_node_peers(self):
        """
        Test per-node BGP peer configuration.

        Test by turning off the mesh and configuring the mesh as
        a set of per node peers.
        """
        with DockerHost('host1',
                        additional_docker_options=ADDITIONAL_DOCKER_OPTIONS,
                        start_calico=False) as host1, \
             DockerHost('host2',
                        additional_docker_options=ADDITIONAL_DOCKER_OPTIONS,
                        start_calico=False) as host2:

            # Start both hosts using specific AS numbers.
            host1.start_calico_node("--as=%s" % LARGE_AS_NUM)
            host2.start_calico_node("--as=%s" % LARGE_AS_NUM)

            # Create a network and a couple of workloads on each host.
            network1 = host1.create_network("subnet1", subnet=DEFAULT_IPV4_POOL_CIDR)
            workload_host1 = host1.create_workload("workload1", network=network1,
                                                   ip=DEFAULT_IPV4_ADDR_1)
            workload_host2 = host2.create_workload("workload2", network=network1,
                                                   ip=DEFAULT_IPV4_ADDR_2)

            # Allow network to converge
            self.assert_true(workload_host1.check_can_ping(DEFAULT_IPV4_ADDR_2, retries=10))

            # Turn the node-to-node mesh off and wait for connectivity to drop.
            host1.calicoctl("config set nodeToNodeMesh off")
            self.assert_true(workload_host1.check_cant_ping(DEFAULT_IPV4_ADDR_2, retries=10))

            # Configure node specific peers to explicitly set up a mesh.
            create_bgp_peer(host1, 'node', host2.ip, LARGE_AS_NUM)
            create_bgp_peer(host2, 'node', host1.ip, LARGE_AS_NUM)

            # Allow network to converge
            self.assert_true(workload_host1.check_can_ping(DEFAULT_IPV4_ADDR_2, retries=10))

            # Check connectivity in both directions
            self.assert_ip_connectivity(workload_list=[workload_host1,
                                                       workload_host2],
                                        ip_pass_list=[DEFAULT_IPV4_ADDR_1,
                                                      DEFAULT_IPV4_ADDR_2])

            # Check the BGP status on each host.
            check_bird_status(host1, [("node specific", host2.ip, "Established")])
            check_bird_status(host2, [("node specific", host1.ip, "Established")])
Beispiel #14
0
    def _test_as_num(self, backend='bird'):
        """
        Test using different AS number for the node-to-node mesh.

        We run a multi-host test for this as we need to set up real BGP peers.
        """
        with DockerHost('host1',
                        additional_docker_options=CLUSTER_STORE_DOCKER_OPTIONS,
                        start_calico=False) as host1, \
             DockerHost('host2',
                        additional_docker_options=CLUSTER_STORE_DOCKER_OPTIONS,
                        start_calico=False) as host2:

            # Set the default AS number.
            update_bgp_config(host1, asNum=LARGE_AS_NUM)

            # Start host1 using the inherited AS, and host2 using a specified
            # AS (same as default).
            host1.start_calico_node("--backend=%s" % backend)
            host2.start_calico_node("--backend=%s --as=%s" %
                                    (backend, LARGE_AS_NUM))

            # Create a network and a couple of workloads on each host.
            network1 = host1.create_network("subnet1",
                                            subnet=DEFAULT_IPV4_POOL_CIDR)
            workload_host1 = host1.create_workload("workload1",
                                                   network=network1,
                                                   ip=DEFAULT_IPV4_ADDR_1)
            workload_host2 = host2.create_workload("workload2",
                                                   network=network1,
                                                   ip=DEFAULT_IPV4_ADDR_2)

            # Allow network to converge
            self.assert_true(
                workload_host1.check_can_ping(DEFAULT_IPV4_ADDR_2, retries=10))

            # Check connectivity in both directions
            self.assert_ip_connectivity(
                workload_list=[workload_host1, workload_host2],
                ip_pass_list=[DEFAULT_IPV4_ADDR_1, DEFAULT_IPV4_ADDR_2])

            # Check the BGP status on each host.
            check_bird_status(host1,
                              [("node-to-node mesh", host2.ip, "Established")])
            check_bird_status(host2,
                              [("node-to-node mesh", host1.ip, "Established")])
    def _test_as_num(self, backend='bird'):
        """
        Test using different AS number for the node-to-node mesh.

        We run a multi-host test for this as we need to set up real BGP peers.
        """
        with DockerHost('host1',
                        additional_docker_options=CLUSTER_STORE_DOCKER_OPTIONS,
                        start_calico=False) as host1, \
             DockerHost('host2',
                        additional_docker_options=CLUSTER_STORE_DOCKER_OPTIONS,
                        start_calico=False) as host2:

            # Set the default AS number.
            host1.calicoctl("config set asNumber %s" % LARGE_AS_NUM)

            # Start host1 using the inherited AS, and host2 using a specified
            # AS (same as default).
            host1.start_calico_node("--backend=%s" % backend)
            host2.start_calico_node("--backend=%s --as=%s" % (backend, LARGE_AS_NUM))

            # Create a network and a couple of workloads on each host.
            network1 = host1.create_network("subnet1", subnet=DEFAULT_IPV4_POOL_CIDR)
            workload_host1 = host1.create_workload("workload1", network=network1, ip=DEFAULT_IPV4_ADDR_1)
            workload_host2 = host2.create_workload("workload2", network=network1, ip=DEFAULT_IPV4_ADDR_2)

            # Allow network to converge
            self.assert_true(workload_host1.check_can_ping(DEFAULT_IPV4_ADDR_2, retries=10))

            # Check connectivity in both directions
            self.assert_ip_connectivity(workload_list=[workload_host1,
                                                       workload_host2],
                                        ip_pass_list=[DEFAULT_IPV4_ADDR_1,
                                                      DEFAULT_IPV4_ADDR_2])

            # Check the BGP status on each host.
            check_bird_status(host1, [("node-to-node mesh", host2.ip, "Established")])
            check_bird_status(host2, [("node-to-node mesh", host1.ip, "Established")])
 def check_connected():
     for target in hosts:
         expected = [("node-to-node mesh", h.ip, "Established") for h in hosts if h is not target]
         _log.debug("expected : %s", expected)
         check_bird_status(target, expected)
Beispiel #17
0
    def _test_gce_int(self, with_ipip, backend, host1, host2, rrc):

        host1.start_calico_node("--backend={0}".format(backend))
        host2.start_calico_node("--backend={0}".format(backend))

        # Before creating any workloads, set the initial IP-in-IP state.
        host1.set_ipip_enabled(with_ipip)

        if rrc:
            # Set the default AS number - as this is used by the RR mesh,
            # and turn off the node-to-node mesh (do this from any host).
            host1.calicoctl("config set asNumber 64513")
            host1.calicoctl("config set nodeToNodeMesh off")
            # Peer from each host to the route reflector.
            for host in [host1, host2]:
                for rr in rrc.get_redundancy_group():
                    create_bgp_peer(host, "node", rr.ip, 64513)

        # Create a network and a workload on each host.
        network1 = host1.create_network("subnet1")
        workload_host1 = host1.create_workload("workload1",
                                               network=network1)
        workload_host2 = host2.create_workload("workload2",
                                               network=network1)

        for _ in [1, 2]:
            # Check we do or don't have connectivity between the workloads,
            # according to the IP-in-IP setting.
            if with_ipip:
                # Allow network to converge.
                self.assert_true(
                    workload_host1.check_can_ping(workload_host2.ip, retries=10))

                # Check connectivity in both directions
                self.assert_ip_connectivity(workload_list=[workload_host1,
                                                           workload_host2],
                                            ip_pass_list=[workload_host1.ip,
                                                          workload_host2.ip])

                # Check that we are using IP-in-IP for some routes.
                assert "tunl0" in host1.execute("ip r")
                assert "tunl0" in host2.execute("ip r")

                # Check that routes are not flapping: the following shell
                # script checks that there is no output for 10s from 'ip
                # monitor', on either host.  The "-le 1" is to allow for
                # something (either 'timeout' or 'ip monitor', not sure) saying
                # 'Terminated' when the 10s are up.  (Note that all commands
                # here are Busybox variants; I tried 'grep -v' to eliminate the
                # Terminated line, but for some reason it didn't work.)
                for host in [host1, host2]:
                    host.execute("changes=`timeout -t 10 ip -t monitor 2>&1`; " +
                                 "echo \"$changes\"; " +
                                 "test `echo \"$changes\" | wc -l` -le 1")
            else:
                # Expect non-connectivity between workloads on different hosts.
                self.assert_false(
                    workload_host1.check_can_ping(workload_host2.ip, retries=10))

            if not rrc:
                # Check the BGP status on each host.
                check_bird_status(host1, [("node-to-node mesh", host2.ip, "Established")])
                check_bird_status(host2, [("node-to-node mesh", host1.ip, "Established")])

            # Flip the IP-in-IP state for the next iteration.
            with_ipip = not with_ipip
            host1.set_ipip_enabled(with_ipip)
Beispiel #18
0
 def check_connected():
     for target in hosts:
         expected = [("node-to-node mesh", h.ip, "Established")
                     for h in hosts if h is not target]
         _log.debug("expected : %s", expected)
         check_bird_status(target, expected)
Beispiel #19
0
    def _test_gce_int(self, with_ipip, backend, host1, host2, rrc):

        host1.start_calico_node("--backend={0}".format(backend))
        host2.start_calico_node("--backend={0}".format(backend))

        # Before creating any workloads, set the initial IP-in-IP state.
        host1.set_ipip_enabled(with_ipip)

        if rrc:
            # Set the default AS number - as this is used by the RR mesh,
            # and turn off the node-to-node mesh (do this from any host).
            update_bgp_config(host1, asNum=64513, nodeMesh=False)
            # Peer from each host to the route reflector.
            for host in [host1, host2]:
                for rr in rrc.get_redundancy_group():
                    create_bgp_peer(host,
                                    "node",
                                    rr.ip,
                                    64513,
                                    metadata={'name': host.name})

        # Create a network and a workload on each host.
        network1 = host1.create_network("subnet1")
        workload_host1 = host1.create_workload("workload1", network=network1)
        workload_host2 = host2.create_workload("workload2", network=network1)

        for _ in [1, 2]:
            # Check we do or don't have connectivity between the workloads,
            # according to the IP-in-IP setting.
            if with_ipip:
                # Allow network to converge.
                self.assert_true(
                    workload_host1.check_can_ping(workload_host2.ip,
                                                  retries=10))

                # Check connectivity in both directions
                self.assert_ip_connectivity(
                    workload_list=[workload_host1, workload_host2],
                    ip_pass_list=[workload_host1.ip, workload_host2.ip])

                for host in [host1, host2]:

                    # Check that we are using IP-in-IP for some routes.
                    assert "tunl0" in host.execute("ip r")

                    # Get current links and addresses, as a baseline for the
                    # following changes test.
                    host.execute("ip l")
                    host.execute("ip a")

                    # Check that routes are not flapping, on either host, by
                    # running 'ip monitor' for 10s and checking that it does
                    # not indicate any changes other than those associated with
                    # an IP address being added to the tunl0 device.
                    ip_changes = host.execute(
                        "timeout -t 10 ip -t monitor 2>&1 || true")
                    lines = ip_changes.split("\n")
                    assert len(lines) >= 1, "No output from ip monitor"
                    expected_lines_following = 0
                    for line in lines:
                        if expected_lines_following > 0:
                            expected_lines_following -= 1
                        elif "Terminated" in line:
                            # "Terminated"
                            pass
                        elif "Timestamp" in line:
                            # e.g. "Timestamp: Wed Nov  1 18:02:38 2017 689895 usec"
                            pass
                        elif ": tunl0" in line:
                            # e.g. "2: tunl0    inet 192.168.128.1/32 scope global tunl0"
                            #      "       valid_lft forever preferred_lft forever"
                            # Indicates IP address being added to the tunl0 device.
                            expected_lines_following = 1
                        elif line.startswith("local") and "dev tunl0" in line:
                            # e.g. "local 192.168.128.1 dev tunl0 table local ..."
                            # Local routing table entry associated with tunl0
                            # device IP address.
                            pass
                        elif "172.17.0.1 dev eth0 lladdr" in line:
                            # Ex: "172.17.0.1 dev eth0 lladdr 02:03:04:05:06:07 REACHABLE"
                            # Indicates that the host just learned the MAC
                            # address of its default gateway.
                            pass
                        else:
                            assert False, "Unexpected ip monitor line: %r" % line

            else:
                # Expect non-connectivity between workloads on different hosts.
                self.assert_false(
                    workload_host1.check_can_ping(workload_host2.ip,
                                                  retries=10))

            if not rrc:
                # Check the BGP status on each host.
                check_bird_status(
                    host1, [("node-to-node mesh", host2.ip, "Established")])
                check_bird_status(
                    host2, [("node-to-node mesh", host1.ip, "Established")])

            # Flip the IP-in-IP state for the next iteration.
            with_ipip = not with_ipip
            host1.set_ipip_enabled(with_ipip)
    def test_bird_readiness(self):
        """
        Test readiness when BGP connections are severed.
        """
        with DockerHost('host1',
                        additional_docker_options=CLUSTER_STORE_DOCKER_OPTIONS) as host1, \
                DockerHost('host2',
                           additional_docker_options=CLUSTER_STORE_DOCKER_OPTIONS) as host2:
            retry_until_success(host1.assert_is_ready, retries=30)
            retry_until_success(host2.assert_is_ready, retries=30)

            # Create a network and a couple of workloads on each host.
            network1 = host1.create_network("subnet1")
            workload_host1 = host1.create_workload("workload1",
                                                   network=network1)
            workload_host2 = host2.create_workload("workload2",
                                                   network=network1)

            # Allow network to converge
            self.assert_true(
                workload_host1.check_can_ping(workload_host2.ip, retries=10))

            # Check connectivity in both directions
            self.assert_ip_connectivity(
                workload_list=[workload_host1, workload_host2],
                ip_pass_list=[workload_host1.ip, workload_host2.ip])

            # Block bgp connectivity between hosts
            host1.execute(
                "iptables -t raw -I PREROUTING  -p tcp -m multiport --dport 179 -j DROP"
            )
            host2.execute(
                "iptables -t raw -I PREROUTING -p tcp -m multiport --dport 179 -j DROP"
            )
            host1.execute("docker exec -it calico-node pkill -9 bird")
            host2.execute("docker exec -it calico-node pkill -9 bird")

            # Check that the readiness script is reporting 'not ready'
            self.assertRaisesRegexp(
                CalledProcessError,
                "calico/node is not ready: BIRD is not ready: BGP not established with",
                host1.execute,
                "docker exec calico-node /bin/calico-node -bird-ready -felix-ready"
            )
            self.assertRaisesRegexp(
                CalledProcessError,
                "calico/node is not ready: BIRD is not ready: BGP not established with",
                host1.execute,
                "docker exec calico-node /bin/calico-node -bird-ready -felix-ready"
            )

            # Restore connectivity
            host1.execute(
                "iptables -t raw -D PREROUTING -p tcp -m multiport --dports 179 -j DROP"
            )
            host2.execute(
                "iptables -t raw -D PREROUTING -p tcp -m multiport --dports 179 -j DROP"
            )

            _log.debug('check connected and retry until "Established"')
            retry_until_success(host1.assert_is_ready, retries=30)
            retry_until_success(host2.assert_is_ready, retries=30)
            check_bird_status(host1,
                              [("node-to-node mesh", host2.ip, "Established")])
            check_bird_status(host2,
                              [("node-to-node mesh", host1.ip, "Established")])
    def test_node_peers(self):
        """
        Test per-node BGP peer configuration.

        Test by turning off the mesh and configuring the mesh as
        a set of per node peers.
        """
        with DockerHost('host1', start_calico=False) as host1, \
             DockerHost('host2', start_calico=False) as host2:

            # Start both hosts using specific AS numbers.
            host1.start_calico_node(as_num=LARGE_AS_NUM)
            host2.start_calico_node(as_num=LARGE_AS_NUM)

            # Create a profile to associate with both workloads
            host1.calicoctl("profile add TEST_GROUP")

            # Create the network on host1, but it should be usable from all
            # hosts.
            workload_host1 = host1.create_workload("workload1",
                                                   network=NET_NONE)
            workload_host2 = host2.create_workload("workload2",
                                                   network=NET_NONE)

            # Add the workloads to Calico networking
            host1.calicoctl("container add %s %s" %
                            (workload_host1, DEFAULT_IPV4_ADDR_1))
            host2.calicoctl("container add %s %s" %
                            (workload_host2, DEFAULT_IPV4_ADDR_2))

            # Now add the profiles - one using set and one using append
            host1.calicoctl("container %s profile set TEST_GROUP" %
                            workload_host1)
            host2.calicoctl("container %s profile append TEST_GROUP" %
                            workload_host2)

            # Allow network to converge
            workload_host1.assert_can_ping(DEFAULT_IPV4_ADDR_2, retries=10)

            # Turn the node-to-node mesh off and wait for connectivity to drop.
            host1.calicoctl("bgp node-mesh off")
            workload_host1.assert_cant_ping(DEFAULT_IPV4_ADDR_2, retries=10)

            # Configure per-node peers to explicitly set up a mesh.
            host1.calicoctl("node bgp peer add %s as %s" %
                            (host2.ip, LARGE_AS_NUM))
            host2.calicoctl("node bgp peer add %s as %s" %
                            (host1.ip, LARGE_AS_NUM))

            # Allow network to converge
            workload_host1.assert_can_ping(DEFAULT_IPV4_ADDR_2, retries=10)

            # Check connectivity in both directions
            self.assert_ip_connectivity(
                workload_list=[workload_host1, workload_host2],
                ip_pass_list=[DEFAULT_IPV4_ADDR_1, DEFAULT_IPV4_ADDR_2])

            # Check the BGP status on each host.
            check_bird_status(host1,
                              [("node specific", host2.ip, "Established")])
            check_bird_status(host2,
                              [("node specific", host1.ip, "Established")])
Beispiel #22
0
    def test_gce(self, with_ipip, backend='bird'):
        """Test with and without IP-in-IP routing on simulated GCE instances.

        In this test we simulate GCE instance routing, where there is a router
        between the instances, and each instance has a /32 address that appears
        not to be directly connected to any subnet.  With that setup,
        connectivity between workloads on different hosts _should_ require
        IP-in-IP to be enabled.  We test that we do get connectivity _with_
        IP-in-IP, that we don't get connectivity _without_ IP-in-IP, and that
        the situation updates dynamically if we toggle IP-in-IP with workloads
        already existing.

        Note that this test targets the BGP implementation, to check that it
        does IP-in-IP routing correctly, and handles the underlying GCE
        routing, and switches dynamically between IP-in-IP and normal routing
        as directed by calicoctl.  (In the BIRD case, these are all points for
        which we've patched the upstream BIRD code.)  But naturally it also
        involves calicoctl and confd, so it isn't _only_ about the BGP code.
        """
        with DockerHost('host1',
                        additional_docker_options=CLUSTER_STORE_DOCKER_OPTIONS,
                        simulate_gce_routing=True,
                        start_calico=False) as host1, \
             DockerHost('host2',
                        additional_docker_options=CLUSTER_STORE_DOCKER_OPTIONS,
                        simulate_gce_routing=True,
                        start_calico=False) as host2:

            host1.start_calico_node("--backend={0}".format(backend))
            host2.start_calico_node("--backend={0}".format(backend))

            # Before creating any workloads, set the initial IP-in-IP state.
            host1.set_ipip_enabled(with_ipip)

            # Create a network and a workload on each host.
            network1 = host1.create_network("subnet1")
            workload_host1 = host1.create_workload("workload1",
                                                   network=network1)
            workload_host2 = host2.create_workload("workload2",
                                                   network=network1)

            for _ in [1, 2]:
                # Check we do or don't have connectivity between the workloads,
                # according to the IP-in-IP setting.
                if with_ipip:
                    # Allow network to converge.
                    self.assert_true(
                        workload_host1.check_can_ping(workload_host2.ip,
                                                      retries=10))

                    # Check connectivity in both directions
                    self.assert_ip_connectivity(
                        workload_list=[workload_host1, workload_host2],
                        ip_pass_list=[workload_host1.ip, workload_host2.ip])

                    # Check that we are using IP-in-IP for some routes.
                    assert "tunl0" in host1.execute("ip r")
                    assert "tunl0" in host2.execute("ip r")
                else:
                    # Expect non-connectivity between workloads on different hosts.
                    self.assert_false(
                        workload_host1.check_can_ping(workload_host2.ip,
                                                      retries=10))

                # Check the BGP status on each host.
                check_bird_status(
                    host1, [("node-to-node mesh", host2.ip, "Established")])
                check_bird_status(
                    host2, [("node-to-node mesh", host1.ip, "Established")])

                # Flip the IP-in-IP state for the next iteration.
                with_ipip = not with_ipip
                host1.set_ipip_enabled(with_ipip)
Beispiel #23
0
    def _test_gce_int(self, with_ipip, backend, host1, host2, rrc):

        host1.start_calico_node("--backend={0}".format(backend))
        host2.start_calico_node("--backend={0}".format(backend))

        # Before creating any workloads, set the initial IP-in-IP state.
        host1.set_ipip_enabled(with_ipip)

        if rrc:
            # Set the default AS number - as this is used by the RR mesh,
            # and turn off the node-to-node mesh (do this from any host).
            host1.calicoctl("config set asNumber 64513")
            host1.calicoctl("config set nodeToNodeMesh off")
            # Peer from each host to the route reflector.
            for host in [host1, host2]:
                for rr in rrc.get_redundancy_group():
                    create_bgp_peer(host, "node", rr.ip, 64513)

        # Create a network and a workload on each host.
        network1 = host1.create_network("subnet1")
        workload_host1 = host1.create_workload("workload1", network=network1)
        workload_host2 = host2.create_workload("workload2", network=network1)

        for _ in [1, 2]:
            # Check we do or don't have connectivity between the workloads,
            # according to the IP-in-IP setting.
            if with_ipip:
                # Allow network to converge.
                self.assert_true(
                    workload_host1.check_can_ping(workload_host2.ip,
                                                  retries=10))

                # Check connectivity in both directions
                self.assert_ip_connectivity(
                    workload_list=[workload_host1, workload_host2],
                    ip_pass_list=[workload_host1.ip, workload_host2.ip])

                # Check that we are using IP-in-IP for some routes.
                assert "tunl0" in host1.execute("ip r")
                assert "tunl0" in host2.execute("ip r")

                # Check that routes are not flapping: the following shell
                # script checks that there is no output for 10s from 'ip
                # monitor', on either host.  The "-le 1" is to allow for
                # something (either 'timeout' or 'ip monitor', not sure) saying
                # 'Terminated' when the 10s are up.  (Note that all commands
                # here are Busybox variants; I tried 'grep -v' to eliminate the
                # Terminated line, but for some reason it didn't work.)
                for host in [host1, host2]:
                    host.execute(
                        "changes=`timeout -t 10 ip -t monitor 2>&1`; " +
                        "echo \"$changes\"; " +
                        "test `echo \"$changes\" | wc -l` -le 1")
            else:
                # Expect non-connectivity between workloads on different hosts.
                self.assert_false(
                    workload_host1.check_can_ping(workload_host2.ip,
                                                  retries=10))

            if not rrc:
                # Check the BGP status on each host.
                check_bird_status(
                    host1, [("node-to-node mesh", host2.ip, "Established")])
                check_bird_status(
                    host2, [("node-to-node mesh", host1.ip, "Established")])

            # Flip the IP-in-IP state for the next iteration.
            with_ipip = not with_ipip
            host1.set_ipip_enabled(with_ipip)