blob: a030668cb61220629e2df17a793b2d1a4fa0cd80 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <signal.h>
#include <unistd.h>
#include <linux/version.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <gtest/gtest.h>
#include <process/clock.hpp>
#include <process/gtest.hpp>
#include <process/reap.hpp>
#include <stout/foreach.hpp>
#include <stout/gtest.hpp>
#include <stout/hashmap.hpp>
#include <stout/ip.hpp>
#include <stout/mac.hpp>
#include <stout/net.hpp>
#include <stout/stringify.hpp>
#include "linux/routing/handle.hpp"
#include "linux/routing/route.hpp"
#include "linux/routing/utils.hpp"
#include "linux/routing/diagnosis/diagnosis.hpp"
#include "linux/routing/filter/basic.hpp"
#include "linux/routing/filter/handle.hpp"
#include "linux/routing/filter/icmp.hpp"
#include "linux/routing/filter/ip.hpp"
#include "linux/routing/link/link.hpp"
#include "linux/routing/link/veth.hpp"
#include "linux/routing/queueing/fq_codel.hpp"
#include "linux/routing/queueing/htb.hpp"
#include "linux/routing/queueing/ingress.hpp"
#include "linux/routing/queueing/statistics.hpp"
using namespace process;
using namespace routing;
using namespace routing::filter;
using namespace routing::queueing;
using std::endl;
using std::set;
using std::string;
using std::vector;
namespace mesos {
namespace internal {
namespace tests {
class RoutingTest : public ::testing::Test {};
TEST_F(RoutingTest, PortRange)
{
Try<ip::PortRange> ports = ip::PortRange::fromBeginEnd(1, 0);
EXPECT_ERROR(ports);
ports = ip::PortRange::fromBeginEnd(4, 11);
EXPECT_ERROR(ports);
ports = ip::PortRange::fromBeginEnd(4, 7);
ASSERT_SOME(ports);
EXPECT_EQ(4u, ports->begin());
EXPECT_EQ(7u, ports->end());
EXPECT_EQ(0xfffc, ports->mask());
EXPECT_EQ("[4,7]", stringify(ports.get()));
ports = ip::PortRange::fromBeginEnd(10, 10);
ASSERT_SOME(ports);
EXPECT_EQ(10u, ports->begin());
EXPECT_EQ(10u, ports->end());
EXPECT_EQ(0xffff, ports->mask());
EXPECT_EQ("[10,10]", stringify(ports.get()));
ports = ip::PortRange::fromBeginMask(20, 0xffff);
ASSERT_SOME(ports);
EXPECT_EQ(20u, ports->begin());
EXPECT_EQ(20u, ports->end());
EXPECT_EQ(0xffff, ports->mask());
EXPECT_EQ("[20,20]", stringify(ports.get()));
ports = ip::PortRange::fromBeginMask(1024, 0xfff8);
ASSERT_SOME(ports);
EXPECT_EQ(1024u, ports->begin());
EXPECT_EQ(1031u, ports->end());
EXPECT_EQ(0xfff8, ports->mask());
EXPECT_EQ("[1024,1031]", stringify(ports.get()));
}
TEST_F(RoutingTest, LinkIndex)
{
Try<set<string>> links = net::links();
ASSERT_SOME(links);
foreach (const string& link, links.get()) {
EXPECT_SOME_NE(0, link::index(link));
}
EXPECT_NONE(link::index("not-exist"));
}
TEST_F(RoutingTest, LinkName)
{
Try<set<string>> links = net::links();
ASSERT_SOME(links);
foreach (const string& link, links.get()) {
EXPECT_SOME_NE(0, link::index(link));
EXPECT_SOME_EQ(link, link::name(link::index(link).get()));
}
}
TEST_F(RoutingTest, LinkStatistics)
{
Try<set<string>> links = net::links();
ASSERT_SOME(links);
foreach (const string& link, links.get()) {
Result<hashmap<string, uint64_t>> statistics = link::statistics(link);
ASSERT_SOME(statistics);
EXPECT_TRUE(statistics->contains("rx_packets"));
EXPECT_TRUE(statistics->contains("rx_bytes"));
EXPECT_TRUE(statistics->contains("tx_packets"));
EXPECT_TRUE(statistics->contains("tx_bytes"));
}
EXPECT_NONE(link::statistics("not-exist"));
}
TEST_F(RoutingTest, LinkExists)
{
Try<set<string>> links = net::links();
ASSERT_SOME(links);
foreach (const string& link, links.get()) {
EXPECT_SOME_TRUE(link::exists(link));
}
EXPECT_SOME_FALSE(link::exists("not-exist"));
}
TEST_F(RoutingTest, Eth0)
{
Result<string> eth0 = link::eth0();
EXPECT_FALSE(eth0.isError());
if (eth0.isSome()) {
ASSERT_SOME_TRUE(link::exists(eth0.get()));
}
}
TEST_F(RoutingTest, Lo)
{
Result<string> lo = link::lo();
EXPECT_FALSE(lo.isError());
if (lo.isSome()) {
ASSERT_SOME_TRUE(link::exists(lo.get()));
}
}
TEST_F(RoutingTest, RouteTable)
{
Try<vector<route::Rule>> table = route::table();
EXPECT_SOME(table);
Result<net::IP> gateway = route::defaultGateway();
EXPECT_FALSE(gateway.isError());
}
class RoutingAdvancedTest : public RoutingTest
{
protected:
virtual void SetUp()
{
ASSERT_SOME(routing::check())
<< "-------------------------------------------------------------\n"
<< "We cannot run any routing advanced tests because either your\n"
<< "libnl library or kernel is not new enough. You can either\n"
<< "upgrade, or disable this test case\n"
<< "-------------------------------------------------------------";
}
};
TEST_F(RoutingAdvancedTest, INETSockets)
{
Try<vector<diagnosis::socket::Info>> infos =
diagnosis::socket::infos(AF_INET, diagnosis::socket::state::ALL);
EXPECT_SOME(infos);
foreach (const diagnosis::socket::Info& info, infos.get()) {
// Both source and destination IPs should be present since
// 'AF_INET' is asked for.
EXPECT_SOME(info.sourceIP);
EXPECT_SOME(info.destinationIP);
}
}
constexpr char TEST_VETH_LINK[] = "veth-test";
constexpr char TEST_PEER_LINK[] = "veth-peer";
// Tests that require setting up virtual ethernet on host.
class RoutingVethTest : public RoutingAdvancedTest
{
protected:
void SetUp() override
{
RoutingAdvancedTest::SetUp();
// Clean up the test links, in case it wasn't cleaned up properly
// from previous tests.
link::remove(TEST_VETH_LINK);
ASSERT_SOME_FALSE(link::exists(TEST_VETH_LINK));
ASSERT_SOME_FALSE(link::exists(TEST_PEER_LINK));
}
void TearDown() override
{
link::remove(TEST_VETH_LINK);
}
};
TEST_F(RoutingVethTest, ROOT_LinkCreate)
{
ASSERT_SOME(link::veth::create(TEST_VETH_LINK, TEST_PEER_LINK, None()));
EXPECT_SOME_TRUE(link::exists(TEST_VETH_LINK));
EXPECT_SOME_TRUE(link::exists(TEST_PEER_LINK));
EXPECT_SOME_NE(0, link::index(TEST_VETH_LINK));
EXPECT_SOME_NE(0, link::index(TEST_PEER_LINK));
// Test the case where the veth (with the same name) already exists.
EXPECT_SOME_FALSE(link::veth::create(TEST_VETH_LINK, TEST_PEER_LINK, None()));
}
TEST_F(RoutingVethTest, ROOT_LinkRemove)
{
ASSERT_SOME(link::veth::create(TEST_VETH_LINK, TEST_PEER_LINK, None()));
EXPECT_SOME_TRUE(link::remove(TEST_VETH_LINK));
EXPECT_SOME_FALSE(link::remove(TEST_VETH_LINK));
EXPECT_SOME_FALSE(link::remove(TEST_PEER_LINK));
}
// An old glibc might not have this symbol.
#ifndef CLONE_NEWNET
#define CLONE_NEWNET 0x40000000
#endif
// Entry point of the child process (used in clone()).
static int child(void*)
{
// Wait to be killed.
while (true) {
sleep(1);
}
// Should not reach here.
ABORT("Child process should not reach here");
}
TEST_F(RoutingVethTest, ROOT_LinkCreatePid)
{
// Stack used in the child process.
unsigned long long stack[32];
pid_t pid = ::clone(child, &stack[31], CLONE_NEWNET | SIGCHLD, nullptr);
ASSERT_NE(-1, pid);
// In parent process.
ASSERT_SOME(link::veth::create(TEST_VETH_LINK, TEST_PEER_LINK, pid));
EXPECT_SOME_TRUE(link::exists(TEST_VETH_LINK));
// The peer should not exist in parent network namespace.
EXPECT_SOME_FALSE(link::exists(TEST_PEER_LINK));
// TODO(jieyu): Enter the child network namespace and make sure that
// the TEST_PEER_LINK is there.
EXPECT_SOME_NE(0, link::index(TEST_VETH_LINK));
// Kill the child process.
ASSERT_NE(-1, kill(pid, SIGKILL));
// Wait for the child process.
AWAIT_EXPECT_WTERMSIG_EQ(SIGKILL, reap(pid));
}
TEST_F(RoutingVethTest, ROOT_LinkWait)
{
AWAIT_READY(link::removed(TEST_VETH_LINK));
ASSERT_SOME(link::veth::create(TEST_VETH_LINK, TEST_PEER_LINK, None()));
EXPECT_SOME_TRUE(link::exists(TEST_VETH_LINK));
EXPECT_SOME_TRUE(link::exists(TEST_PEER_LINK));
Future<Nothing> removed = link::removed(TEST_VETH_LINK);
EXPECT_TRUE(removed.isPending());
ASSERT_SOME_TRUE(link::remove(TEST_VETH_LINK));
AWAIT_READY(removed);
}
TEST_F(RoutingVethTest, ROOT_LinkSetUp)
{
ASSERT_SOME(link::veth::create(TEST_VETH_LINK, TEST_PEER_LINK, None()));
EXPECT_SOME_TRUE(link::exists(TEST_VETH_LINK));
EXPECT_SOME_TRUE(link::exists(TEST_PEER_LINK));
EXPECT_SOME_FALSE(link::isUp(TEST_VETH_LINK));
EXPECT_SOME_TRUE(link::setUp(TEST_VETH_LINK));
EXPECT_SOME_TRUE(link::isUp(TEST_VETH_LINK));
EXPECT_SOME_FALSE(link::isUp(TEST_PEER_LINK));
EXPECT_SOME_TRUE(link::setUp(TEST_PEER_LINK));
EXPECT_SOME_TRUE(link::isUp(TEST_PEER_LINK));
EXPECT_NONE(link::isUp("non-exist"));
EXPECT_SOME_FALSE(link::setUp("non-exist"));
}
TEST_F(RoutingVethTest, ROOT_LinkSetMAC)
{
ASSERT_SOME(link::veth::create(TEST_VETH_LINK, TEST_PEER_LINK, None()));
EXPECT_SOME_TRUE(link::exists(TEST_VETH_LINK));
EXPECT_SOME_TRUE(link::exists(TEST_PEER_LINK));
uint8_t bytes[6] = {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc};
EXPECT_SOME_TRUE(link::setMAC(TEST_VETH_LINK, net::MAC(bytes)));
EXPECT_SOME_TRUE(link::setMAC(TEST_PEER_LINK, net::MAC(bytes)));
Result<net::MAC> mac = net::mac(TEST_VETH_LINK);
ASSERT_SOME(mac);
EXPECT_EQ(mac.get(), net::MAC(bytes));
mac = net::mac(TEST_PEER_LINK);
ASSERT_SOME(mac);
EXPECT_EQ(mac.get(), net::MAC(bytes));
EXPECT_SOME_FALSE(link::setMAC("non-exist", net::MAC(bytes)));
// Kernel will reject a multicast MAC address.
uint8_t multicast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
EXPECT_ERROR(link::setMAC(TEST_VETH_LINK, net::MAC(multicast)));
}
TEST_F(RoutingVethTest, ROOT_LinkMTU)
{
ASSERT_SOME(link::veth::create(TEST_VETH_LINK, TEST_PEER_LINK, None()));
EXPECT_SOME_TRUE(link::exists(TEST_VETH_LINK));
EXPECT_SOME_TRUE(link::exists(TEST_PEER_LINK));
EXPECT_SOME_TRUE(link::setMTU(TEST_VETH_LINK, 10000));
Result<unsigned int> mtu = link::mtu(TEST_VETH_LINK);
ASSERT_SOME(mtu);
EXPECT_EQ(10000u, mtu.get());
EXPECT_NONE(link::mtu("not-exist"));
EXPECT_SOME_FALSE(link::setMTU("not-exist", 1500));
}
TEST_F(RoutingVethTest, ROOT_IngressQdisc)
{
// Test for a qdisc on a nonexistent interface should fail.
EXPECT_SOME_FALSE(ingress::exists("noSuchInterface"));
EXPECT_SOME(link::veth::create(TEST_VETH_LINK, TEST_PEER_LINK, None()));
EXPECT_SOME_TRUE(link::exists(TEST_VETH_LINK));
EXPECT_SOME_TRUE(link::exists(TEST_PEER_LINK));
// Interface exists but does not have an ingress qdisc.
EXPECT_SOME_FALSE(ingress::exists(TEST_VETH_LINK));
EXPECT_SOME_FALSE(ingress::exists(TEST_PEER_LINK));
// Interfaces without qdisc established no data.
EXPECT_NONE(ingress::statistics(TEST_VETH_LINK));
EXPECT_NONE(ingress::statistics(TEST_PEER_LINK));
// Try to create an ingress qdisc on a nonexistent interface.
EXPECT_ERROR(ingress::create("noSuchInterface"));
// Create an ingress qdisc on an existing interface.
EXPECT_SOME_TRUE(ingress::create(TEST_VETH_LINK));
// Interface exists and has an ingress qdisc.
EXPECT_SOME_TRUE(ingress::exists(TEST_VETH_LINK));
EXPECT_SOME_FALSE(ingress::exists(TEST_PEER_LINK));
// Interfaces which exist return at least the core statisitcs.
Result<hashmap<string, uint64_t>> stats = ingress::statistics(TEST_VETH_LINK);
ASSERT_SOME(stats);
EXPECT_TRUE(stats->contains(statistics::PACKETS));
EXPECT_TRUE(stats->contains(statistics::BYTES));
EXPECT_TRUE(stats->contains(statistics::RATE_BPS));
EXPECT_TRUE(stats->contains(statistics::RATE_PPS));
EXPECT_TRUE(stats->contains(statistics::QLEN));
EXPECT_TRUE(stats->contains(statistics::BACKLOG));
EXPECT_TRUE(stats->contains(statistics::DROPS));
EXPECT_TRUE(stats->contains(statistics::REQUEUES));
EXPECT_TRUE(stats->contains(statistics::OVERLIMITS));
// Interface without qdisc returns no data.
EXPECT_NONE(ingress::statistics(TEST_PEER_LINK));
// Try to create a second ingress qdisc on an existing interface.
EXPECT_SOME_FALSE(ingress::create(TEST_VETH_LINK));
EXPECT_SOME_TRUE(ingress::exists(TEST_VETH_LINK));
EXPECT_SOME_FALSE(ingress::exists(TEST_PEER_LINK));
// Remove the ingress qdisc.
EXPECT_SOME_TRUE(ingress::remove(TEST_VETH_LINK));
EXPECT_SOME_FALSE(ingress::exists(TEST_VETH_LINK));
EXPECT_SOME_FALSE(ingress::exists(TEST_PEER_LINK));
// Try to remove it from a nonexistent interface.
EXPECT_SOME_FALSE(ingress::remove("noSuchInterface"));
// Remove the ingress qdisc when it does not exist.
EXPECT_SOME_FALSE(ingress::remove(TEST_VETH_LINK));
EXPECT_SOME_FALSE(ingress::exists(TEST_VETH_LINK));
EXPECT_SOME_FALSE(ingress::exists(TEST_PEER_LINK));
}
TEST_F(RoutingVethTest, ROOT_HTBQdisc)
{
// Test for a qdisc on a nonexistent interface should fail.
EXPECT_SOME_FALSE(htb::exists("noSuchInterface", EGRESS_ROOT));
EXPECT_SOME(link::veth::create(TEST_VETH_LINK, TEST_PEER_LINK, None()));
EXPECT_SOME_TRUE(link::exists(TEST_VETH_LINK));
EXPECT_SOME_TRUE(link::exists(TEST_PEER_LINK));
// This test uses a common handle throughout
const Handle handle = Handle(1, 0);
// Interface exists but does not have an htb qdisc.
EXPECT_SOME_FALSE(htb::exists(TEST_VETH_LINK, EGRESS_ROOT));
EXPECT_SOME_FALSE(htb::exists(TEST_PEER_LINK, EGRESS_ROOT));
// Interfaces without qdisc established no data.
EXPECT_NONE(htb::statistics(TEST_VETH_LINK, EGRESS_ROOT));
EXPECT_NONE(htb::statistics(TEST_PEER_LINK, EGRESS_ROOT));
// Try to create an htb qdisc on a nonexistent interface.
EXPECT_ERROR(htb::create("noSuchInterface", EGRESS_ROOT, handle));
// Create an htb qdisc on an existing interface.
EXPECT_SOME_TRUE(htb::create(TEST_VETH_LINK, EGRESS_ROOT, handle));
// Interface exists and has an htb qdisc.
EXPECT_SOME_TRUE(htb::exists(TEST_VETH_LINK, EGRESS_ROOT));
EXPECT_SOME_FALSE(htb::exists(TEST_PEER_LINK, EGRESS_ROOT));
// Interfaces which exist return at least the core statisitcs.
Result<hashmap<string, uint64_t>> stats =
htb::statistics(TEST_VETH_LINK, EGRESS_ROOT);
ASSERT_SOME(stats);
EXPECT_TRUE(stats->contains(statistics::PACKETS));
EXPECT_TRUE(stats->contains(statistics::BYTES));
EXPECT_TRUE(stats->contains(statistics::RATE_BPS));
EXPECT_TRUE(stats->contains(statistics::RATE_PPS));
EXPECT_TRUE(stats->contains(statistics::QLEN));
EXPECT_TRUE(stats->contains(statistics::BACKLOG));
EXPECT_TRUE(stats->contains(statistics::DROPS));
EXPECT_TRUE(stats->contains(statistics::REQUEUES));
EXPECT_TRUE(stats->contains(statistics::OVERLIMITS));
// Interface without htb qdisc returns no data.
EXPECT_NONE(htb::statistics(TEST_PEER_LINK, EGRESS_ROOT));
// Try to create a second htb qdisc on an existing interface.
EXPECT_SOME_FALSE(htb::create(TEST_VETH_LINK, EGRESS_ROOT, handle));
EXPECT_SOME_TRUE(htb::exists(TEST_VETH_LINK, EGRESS_ROOT));
EXPECT_SOME_FALSE(htb::exists(TEST_PEER_LINK, EGRESS_ROOT));
// Remove the htb qdisc.
EXPECT_SOME_TRUE(htb::remove(TEST_VETH_LINK, EGRESS_ROOT));
EXPECT_SOME_FALSE(htb::exists(TEST_VETH_LINK, EGRESS_ROOT));
EXPECT_SOME_FALSE(htb::exists(TEST_PEER_LINK, EGRESS_ROOT));
// Try to remove it from a nonexistent interface.
EXPECT_SOME_FALSE(htb::remove("noSuchInterface", EGRESS_ROOT));
// Remove the htb qdisc when it does not exist.
EXPECT_SOME_FALSE(htb::remove(TEST_VETH_LINK, EGRESS_ROOT));
EXPECT_SOME_FALSE(htb::exists(TEST_VETH_LINK, EGRESS_ROOT));
EXPECT_SOME_FALSE(htb::exists(TEST_PEER_LINK, EGRESS_ROOT));
// Try to create an htb qdisc on a nonexistent interface and
// default handle.
EXPECT_ERROR(htb::create("noSuchInterface", EGRESS_ROOT, None()));
// Create an htb qdisc on an existing interface.
EXPECT_SOME_TRUE(htb::create(TEST_VETH_LINK, EGRESS_ROOT, None()));
// Interface exists and has an htb qdisc.
EXPECT_SOME_TRUE(htb::exists(TEST_VETH_LINK, EGRESS_ROOT));
EXPECT_SOME_FALSE(htb::exists(TEST_PEER_LINK, EGRESS_ROOT));
// Remove the htb qdisc.
EXPECT_SOME_TRUE(htb::remove(TEST_VETH_LINK, EGRESS_ROOT));
EXPECT_SOME_FALSE(htb::exists(TEST_VETH_LINK, EGRESS_ROOT));
EXPECT_SOME_FALSE(htb::exists(TEST_PEER_LINK, EGRESS_ROOT));
}
TEST_F(RoutingVethTest, ROOT_FqCodeQdisc)
{
// Test for a qdisc on a nonexistent interface should fail.
EXPECT_SOME_FALSE(fq_codel::exists("noSuchInterface", EGRESS_ROOT));
EXPECT_SOME(link::veth::create(TEST_VETH_LINK, TEST_PEER_LINK, None()));
EXPECT_SOME_TRUE(link::exists(TEST_VETH_LINK));
EXPECT_SOME_TRUE(link::exists(TEST_PEER_LINK));
// This test uses a common handle throughout
const Handle handle = Handle(1, 0);
// Interface exists but does not have an fq_codel qdisc.
EXPECT_SOME_FALSE(fq_codel::exists(TEST_VETH_LINK, EGRESS_ROOT));
EXPECT_SOME_FALSE(fq_codel::exists(TEST_PEER_LINK, EGRESS_ROOT));
// Interfaces without qdisc established no data.
EXPECT_NONE(fq_codel::statistics(TEST_VETH_LINK, EGRESS_ROOT));
EXPECT_NONE(fq_codel::statistics(TEST_PEER_LINK, EGRESS_ROOT));
// Try to create an fq_codel qdisc on a nonexistent interface.
EXPECT_ERROR(fq_codel::create("noSuchInterface", EGRESS_ROOT, handle));
// Create an fq_codel qdisc on an existing interface.
EXPECT_SOME_TRUE(fq_codel::create(TEST_VETH_LINK, EGRESS_ROOT, handle));
// Interface exists and has an fq_codel qdisc.
EXPECT_SOME_TRUE(fq_codel::exists(TEST_VETH_LINK, EGRESS_ROOT));
EXPECT_SOME_FALSE(fq_codel::exists(TEST_PEER_LINK, EGRESS_ROOT));
// Interfaces which exist return at least the core statisitcs.
Result<hashmap<string, uint64_t>> stats =
fq_codel::statistics(TEST_VETH_LINK, EGRESS_ROOT);
ASSERT_SOME(stats);
EXPECT_TRUE(stats->contains(statistics::PACKETS));
EXPECT_TRUE(stats->contains(statistics::BYTES));
EXPECT_TRUE(stats->contains(statistics::RATE_BPS));
EXPECT_TRUE(stats->contains(statistics::RATE_PPS));
EXPECT_TRUE(stats->contains(statistics::QLEN));
EXPECT_TRUE(stats->contains(statistics::BACKLOG));
EXPECT_TRUE(stats->contains(statistics::DROPS));
EXPECT_TRUE(stats->contains(statistics::REQUEUES));
EXPECT_TRUE(stats->contains(statistics::OVERLIMITS));
// Interface without fq_codel qdisc returns no data.
EXPECT_NONE(fq_codel::statistics(TEST_PEER_LINK, EGRESS_ROOT));
// Try to create a second fq_codel qdisc on an existing interface.
EXPECT_SOME_FALSE(fq_codel::create(TEST_VETH_LINK, EGRESS_ROOT, handle));
EXPECT_SOME_TRUE(fq_codel::exists(TEST_VETH_LINK, EGRESS_ROOT));
EXPECT_SOME_FALSE(fq_codel::exists(TEST_PEER_LINK, EGRESS_ROOT));
// Remove the fq_codel qdisc.
EXPECT_SOME_TRUE(fq_codel::remove(TEST_VETH_LINK, EGRESS_ROOT));
EXPECT_SOME_FALSE(fq_codel::exists(TEST_VETH_LINK, EGRESS_ROOT));
EXPECT_SOME_FALSE(fq_codel::exists(TEST_PEER_LINK, EGRESS_ROOT));
// Try to remove it from a nonexistent interface.
EXPECT_SOME_FALSE(fq_codel::remove("noSuchInterface", EGRESS_ROOT));
// Remove the fq_codel qdisc when it does not exist.
EXPECT_SOME_FALSE(fq_codel::remove(TEST_VETH_LINK, EGRESS_ROOT));
EXPECT_SOME_FALSE(fq_codel::exists(TEST_VETH_LINK, EGRESS_ROOT));
EXPECT_SOME_FALSE(fq_codel::exists(TEST_PEER_LINK, EGRESS_ROOT));
// Try to create an fq_codel qdisc on a nonexistent interface and
// default handle.
EXPECT_ERROR(fq_codel::create("noSuchInterface", EGRESS_ROOT, None()));
// Create an fq_codel qdisc on an existing interface.
EXPECT_SOME_TRUE(fq_codel::create(TEST_VETH_LINK, EGRESS_ROOT, None()));
// Interface exists and has an fq_codel qdisc.
EXPECT_SOME_TRUE(fq_codel::exists(TEST_VETH_LINK, EGRESS_ROOT));
EXPECT_SOME_FALSE(fq_codel::exists(TEST_PEER_LINK, EGRESS_ROOT));
// Remove the fq_codel qdisc.
EXPECT_SOME_TRUE(fq_codel::remove(TEST_VETH_LINK, EGRESS_ROOT));
EXPECT_SOME_FALSE(fq_codel::exists(TEST_VETH_LINK, EGRESS_ROOT));
EXPECT_SOME_FALSE(fq_codel::exists(TEST_PEER_LINK, EGRESS_ROOT));
}
TEST_F(RoutingVethTest, ROOT_FqCodelClassifier)
{
ASSERT_SOME(link::veth::create(TEST_VETH_LINK, TEST_PEER_LINK, None()));
EXPECT_SOME_TRUE(link::exists(TEST_VETH_LINK));
EXPECT_SOME_TRUE(link::exists(TEST_PEER_LINK));
const Handle handle = Handle(1, 0);
ASSERT_SOME_TRUE(fq_codel::create(TEST_VETH_LINK, EGRESS_ROOT, handle));
EXPECT_SOME_TRUE(basic::create(
TEST_VETH_LINK,
handle,
ETH_P_ALL,
None(),
Handle(handle, 0)));
EXPECT_SOME_TRUE(basic::exists(TEST_VETH_LINK, handle, ETH_P_ALL));
EXPECT_SOME_TRUE(basic::create(
TEST_VETH_LINK,
handle,
ETH_P_ARP,
None(),
Handle(handle, 0)));
// There is a kernel bug which could cause this test fail. Please
// make sure your kernel, if newer than 3.14, has commit:
// b057df24a7536cce6c372efe9d0e3d1558afedf4
// (https://git.kernel.org/cgit/linux/kernel/git/davem/net.git).
// Please fix your kernel if you see this failure.
EXPECT_SOME_TRUE(basic::exists(TEST_VETH_LINK, handle, ETH_P_ARP));
EXPECT_SOME_TRUE(icmp::create(
TEST_VETH_LINK,
handle,
icmp::Classifier(None()),
None(),
Handle(handle, 0)));
EXPECT_SOME_TRUE(icmp::exists(
TEST_VETH_LINK,
handle,
icmp::Classifier(None())));
Result<net::MAC> mac = net::mac(TEST_VETH_LINK);
ASSERT_SOME(mac);
net::IP ip = net::IP(0x01020304); // 1.2.3.4
Try<ip::PortRange> sourcePorts =
ip::PortRange::fromBeginEnd(1024, 1027);
ASSERT_SOME(sourcePorts);
Try<ip::PortRange> destinationPorts =
ip::PortRange::fromBeginEnd(2000, 2000);
ASSERT_SOME(destinationPorts);
ip::Classifier classifier =
ip::Classifier(
mac.get(),
ip,
sourcePorts.get(),
destinationPorts.get());
EXPECT_SOME_TRUE(ip::create(
TEST_VETH_LINK,
handle,
classifier,
None(),
Handle(handle, 1)));
EXPECT_SOME_TRUE(ip::exists(TEST_VETH_LINK, handle, classifier));
}
TEST_F(RoutingVethTest, ROOT_ARPFilterCreate)
{
ASSERT_SOME(link::veth::create(TEST_VETH_LINK, TEST_PEER_LINK, None()));
EXPECT_SOME_TRUE(link::exists(TEST_VETH_LINK));
EXPECT_SOME_TRUE(link::exists(TEST_PEER_LINK));
ASSERT_SOME_TRUE(ingress::create(TEST_VETH_LINK));
EXPECT_SOME_TRUE(basic::create(
TEST_VETH_LINK,
ingress::HANDLE,
ETH_P_ARP,
None(),
action::Redirect(TEST_PEER_LINK)));
EXPECT_SOME_TRUE(basic::exists(TEST_VETH_LINK, ingress::HANDLE, ETH_P_ARP));
}
TEST_F(RoutingVethTest, ROOT_ARPFilterCreateDuplicated)
{
ASSERT_SOME(link::veth::create(TEST_VETH_LINK, TEST_PEER_LINK, None()));
EXPECT_SOME_TRUE(link::exists(TEST_VETH_LINK));
EXPECT_SOME_TRUE(link::exists(TEST_PEER_LINK));
ASSERT_SOME_TRUE(ingress::create(TEST_VETH_LINK));
set<string> links;
links.insert(TEST_PEER_LINK);
EXPECT_SOME_TRUE(basic::create(
TEST_VETH_LINK,
ingress::HANDLE,
ETH_P_ARP,
None(),
action::Mirror(links)));
EXPECT_SOME_TRUE(basic::exists(TEST_VETH_LINK, ingress::HANDLE, ETH_P_ARP));
EXPECT_SOME_FALSE(basic::create(
TEST_VETH_LINK,
ingress::HANDLE,
ETH_P_ARP,
None(),
action::Redirect(TEST_PEER_LINK)));
}
TEST_F(RoutingVethTest, ROOT_ARPFilterRemove)
{
ASSERT_SOME(link::veth::create(TEST_VETH_LINK, TEST_PEER_LINK, None()));
EXPECT_SOME_TRUE(link::exists(TEST_VETH_LINK));
EXPECT_SOME_TRUE(link::exists(TEST_PEER_LINK));
ASSERT_SOME_TRUE(ingress::create(TEST_VETH_LINK));
set<string> links;
links.insert(TEST_PEER_LINK);
EXPECT_SOME_TRUE(basic::create(
TEST_VETH_LINK,
ingress::HANDLE,
ETH_P_ARP,
None(),
action::Mirror(links)));
EXPECT_SOME_TRUE(basic::exists(TEST_VETH_LINK, ingress::HANDLE, ETH_P_ARP));
EXPECT_SOME_TRUE(basic::remove(TEST_VETH_LINK, ingress::HANDLE, ETH_P_ARP));
EXPECT_SOME_FALSE(basic::exists(TEST_VETH_LINK, ingress::HANDLE, ETH_P_ARP));
}
TEST_F(RoutingVethTest, ROOT_ARPFilterUpdate)
{
ASSERT_SOME(link::veth::create(TEST_VETH_LINK, TEST_PEER_LINK, None()));
EXPECT_SOME_TRUE(link::exists(TEST_VETH_LINK));
EXPECT_SOME_TRUE(link::exists(TEST_PEER_LINK));
ASSERT_SOME_TRUE(ingress::create(TEST_VETH_LINK));
set<string> links;
links.insert(TEST_PEER_LINK);
EXPECT_SOME_FALSE(basic::update(
TEST_VETH_LINK,
ingress::HANDLE,
ETH_P_ARP,
action::Mirror(links)));
EXPECT_SOME_TRUE(basic::create(
TEST_VETH_LINK,
ingress::HANDLE,
ETH_P_ARP,
None(),
action::Redirect(TEST_PEER_LINK)));
EXPECT_SOME_TRUE(basic::exists(TEST_VETH_LINK, ingress::HANDLE, ETH_P_ARP));
EXPECT_SOME_TRUE(basic::update(
TEST_VETH_LINK,
ingress::HANDLE,
ETH_P_ARP,
action::Mirror(links)));
EXPECT_SOME_TRUE(basic::exists(TEST_VETH_LINK, ingress::HANDLE, ETH_P_ARP));
}
TEST_F(RoutingVethTest, ROOT_ICMPFilterCreate)
{
ASSERT_SOME(link::veth::create(TEST_VETH_LINK, TEST_PEER_LINK, None()));
EXPECT_SOME_TRUE(link::exists(TEST_VETH_LINK));
EXPECT_SOME_TRUE(link::exists(TEST_PEER_LINK));
ASSERT_SOME_TRUE(ingress::create(TEST_VETH_LINK));
net::IP ip = net::IP(0x01020304); // 1.2.3.4
EXPECT_SOME_TRUE(icmp::create(
TEST_VETH_LINK,
ingress::HANDLE,
icmp::Classifier(ip),
None(),
action::Redirect(TEST_PEER_LINK)));
EXPECT_SOME_TRUE(icmp::exists(
TEST_VETH_LINK,
ingress::HANDLE,
icmp::Classifier(ip)));
Result<vector<icmp::Classifier>> classifiers =
icmp::classifiers(TEST_VETH_LINK, ingress::HANDLE);
ASSERT_SOME(classifiers);
ASSERT_EQ(1u, classifiers->size());
EXPECT_SOME_EQ(ip, classifiers->front().destinationIP);
}
TEST_F(RoutingVethTest, ROOT_ICMPFilterCreateDuplicated)
{
ASSERT_SOME(link::veth::create(TEST_VETH_LINK, TEST_PEER_LINK, None()));
EXPECT_SOME_TRUE(link::exists(TEST_VETH_LINK));
EXPECT_SOME_TRUE(link::exists(TEST_PEER_LINK));
ASSERT_SOME_TRUE(ingress::create(TEST_VETH_LINK));
set<string> links;
links.insert(TEST_PEER_LINK);
EXPECT_SOME_TRUE(icmp::create(
TEST_VETH_LINK,
ingress::HANDLE,
icmp::Classifier(None()),
None(),
action::Mirror(links)));
EXPECT_SOME_TRUE(icmp::exists(
TEST_VETH_LINK,
ingress::HANDLE,
icmp::Classifier(None())));
EXPECT_SOME_FALSE(icmp::create(
TEST_VETH_LINK,
ingress::HANDLE,
icmp::Classifier(None()),
None(),
action::Mirror(links)));
}
TEST_F(RoutingVethTest, ROOT_ICMPFilterCreateMultiple)
{
ASSERT_SOME(link::veth::create(TEST_VETH_LINK, TEST_PEER_LINK, None()));
EXPECT_SOME_TRUE(link::exists(TEST_VETH_LINK));
EXPECT_SOME_TRUE(link::exists(TEST_PEER_LINK));
ASSERT_SOME_TRUE(ingress::create(TEST_VETH_LINK));
net::IP ip1 = net::IP(0x01020304); // 1.2.3.4
net::IP ip2 = net::IP(0x05060708); // 5.6.7.8
EXPECT_SOME_TRUE(icmp::create(
TEST_VETH_LINK,
ingress::HANDLE,
icmp::Classifier(ip1),
Priority(1, 1),
action::Redirect(TEST_PEER_LINK)));
EXPECT_SOME_TRUE(icmp::create(
TEST_VETH_LINK,
ingress::HANDLE,
icmp::Classifier(ip2),
Priority(1, 2),
action::Redirect(TEST_PEER_LINK)));
Result<vector<icmp::Classifier>> classifiers =
icmp::classifiers(TEST_VETH_LINK, ingress::HANDLE);
ASSERT_SOME(classifiers);
ASSERT_EQ(2u, classifiers->size());
EXPECT_SOME_EQ(ip1, classifiers->front().destinationIP);
EXPECT_SOME_EQ(ip2, classifiers->back().destinationIP);
}
TEST_F(RoutingVethTest, ROOT_ICMPFilterRemove)
{
ASSERT_SOME(link::veth::create(
TEST_VETH_LINK, TEST_PEER_LINK, None()));
EXPECT_SOME_TRUE(link::exists(TEST_VETH_LINK));
EXPECT_SOME_TRUE(link::exists(TEST_PEER_LINK));
ASSERT_SOME_TRUE(ingress::create(TEST_VETH_LINK));
EXPECT_SOME_TRUE(icmp::create(
TEST_VETH_LINK,
ingress::HANDLE,
icmp::Classifier(None()),
None(),
action::Redirect(TEST_PEER_LINK)));
EXPECT_SOME_TRUE(icmp::exists(
TEST_VETH_LINK,
ingress::HANDLE,
icmp::Classifier(None())));
EXPECT_SOME_TRUE(icmp::remove(
TEST_VETH_LINK,
ingress::HANDLE,
icmp::Classifier(None())));
EXPECT_SOME_FALSE(icmp::exists(
TEST_VETH_LINK,
ingress::HANDLE,
icmp::Classifier(None())));
}
TEST_F(RoutingVethTest, ROOT_ICMPFilterUpdate)
{
ASSERT_SOME(link::veth::create(TEST_VETH_LINK, TEST_PEER_LINK, None()));
EXPECT_SOME_TRUE(link::exists(TEST_VETH_LINK));
EXPECT_SOME_TRUE(link::exists(TEST_PEER_LINK));
ASSERT_SOME_TRUE(ingress::create(TEST_VETH_LINK));
net::IP ip = net::IP(0x01020304); // 1.2.3.4
set<string> links;
links.insert(TEST_PEER_LINK);
EXPECT_SOME_FALSE(icmp::update(
TEST_VETH_LINK,
ingress::HANDLE,
icmp::Classifier(None()),
action::Mirror(links)));
EXPECT_SOME_TRUE(icmp::create(
TEST_VETH_LINK,
ingress::HANDLE,
icmp::Classifier(None()),
None(),
action::Redirect(TEST_PEER_LINK)));
EXPECT_SOME_TRUE(icmp::exists(
TEST_VETH_LINK,
ingress::HANDLE,
icmp::Classifier(None())));
EXPECT_SOME_FALSE(icmp::update(
TEST_VETH_LINK,
ingress::HANDLE,
icmp::Classifier(ip),
action::Mirror(links)));
EXPECT_SOME_TRUE(icmp::update(
TEST_VETH_LINK,
ingress::HANDLE,
icmp::Classifier(None()),
action::Mirror(links)));
EXPECT_SOME_TRUE(icmp::exists(
TEST_VETH_LINK,
ingress::HANDLE,
icmp::Classifier(None())));
EXPECT_SOME_FALSE(icmp::exists(
TEST_VETH_LINK,
ingress::HANDLE,
icmp::Classifier(ip)));
}
TEST_F(RoutingVethTest, ROOT_IPFilterCreate)
{
ASSERT_SOME(link::veth::create(TEST_VETH_LINK, TEST_PEER_LINK, None()));
EXPECT_SOME_TRUE(link::exists(TEST_VETH_LINK));
EXPECT_SOME_TRUE(link::exists(TEST_PEER_LINK));
ASSERT_SOME_TRUE(ingress::create(TEST_VETH_LINK));
Result<net::MAC> mac = net::mac(TEST_VETH_LINK);
ASSERT_SOME(mac);
net::IP ip = net::IP(0x01020304); // 1.2.3.4
Try<ip::PortRange> sourcePorts =
ip::PortRange::fromBeginEnd(1024, 1027);
ASSERT_SOME(sourcePorts);
Try<ip::PortRange> destinationPorts =
ip::PortRange::fromBeginEnd(2000, 2000);
ASSERT_SOME(destinationPorts);
ip::Classifier classifier =
ip::Classifier(
mac.get(),
ip,
sourcePorts.get(),
destinationPorts.get());
EXPECT_SOME_TRUE(ip::create(
TEST_VETH_LINK,
ingress::HANDLE,
classifier,
None(),
action::Redirect(TEST_PEER_LINK)));
EXPECT_SOME_TRUE(ip::exists(TEST_VETH_LINK, ingress::HANDLE, classifier));
Result<vector<ip::Classifier>> classifiers =
ip::classifiers(TEST_VETH_LINK, ingress::HANDLE);
ASSERT_SOME(classifiers);
ASSERT_EQ(1u, classifiers->size());
EXPECT_SOME_EQ(mac.get(), classifiers->front().destinationMAC);
EXPECT_SOME_EQ(ip, classifiers->front().destinationIP);
EXPECT_SOME_EQ(
sourcePorts.get(),
classifiers->front().sourcePorts);
EXPECT_SOME_EQ(
destinationPorts.get(),
classifiers->front().destinationPorts);
}
TEST_F(RoutingVethTest, ROOT_IPFilterCreate2)
{
ASSERT_SOME(link::veth::create(TEST_VETH_LINK, TEST_PEER_LINK, None()));
EXPECT_SOME_TRUE(link::exists(TEST_VETH_LINK));
EXPECT_SOME_TRUE(link::exists(TEST_PEER_LINK));
ASSERT_SOME_TRUE(ingress::create(TEST_VETH_LINK));
net::IP ip(0x12345678);
EXPECT_SOME_TRUE(ip::create(
TEST_VETH_LINK,
ingress::HANDLE,
ip::Classifier(None(), ip, None(), None()),
None(),
action::Redirect(TEST_PEER_LINK)));
EXPECT_SOME_TRUE(ip::exists(
TEST_VETH_LINK,
ingress::HANDLE,
ip::Classifier(None(), ip, None(), None())));
Result<vector<ip::Classifier>> classifiers =
ip::classifiers(TEST_VETH_LINK, ingress::HANDLE);
ASSERT_SOME(classifiers);
ASSERT_EQ(1u, classifiers->size());
EXPECT_NONE(classifiers->front().destinationMAC);
EXPECT_SOME_EQ(ip, classifiers->front().destinationIP);
EXPECT_NONE(classifiers->front().sourcePorts);
EXPECT_NONE(classifiers->front().destinationPorts);
}
TEST_F(RoutingVethTest, ROOT_IPFilterCreateDuplicated)
{
ASSERT_SOME(link::veth::create(TEST_VETH_LINK, TEST_PEER_LINK, None()));
EXPECT_SOME_TRUE(link::exists(TEST_VETH_LINK));
EXPECT_SOME_TRUE(link::exists(TEST_PEER_LINK));
ASSERT_SOME_TRUE(ingress::create(TEST_VETH_LINK));
Result<net::MAC> mac = net::mac(TEST_VETH_LINK);
ASSERT_SOME(mac);
net::IP ip = net::IP(0x01020304); // 1.2.3.4
Try<ip::PortRange> sourcePorts =
ip::PortRange::fromBeginEnd(1024, 1027);
ASSERT_SOME(sourcePorts);
Try<ip::PortRange> destinationPorts =
ip::PortRange::fromBeginEnd(2000, 2000);
ASSERT_SOME(destinationPorts);
ip::Classifier classifier =
ip::Classifier(
mac.get(),
ip,
sourcePorts.get(),
destinationPorts.get());
EXPECT_SOME_TRUE(ip::create(
TEST_VETH_LINK,
ingress::HANDLE,
classifier,
None(),
action::Redirect(TEST_PEER_LINK)));
EXPECT_SOME_TRUE(ip::exists(TEST_VETH_LINK, ingress::HANDLE, classifier));
EXPECT_SOME_FALSE(ip::create(
TEST_VETH_LINK,
ingress::HANDLE,
classifier,
None(),
action::Redirect(TEST_PEER_LINK)));
}
TEST_F(RoutingVethTest, ROOT_IPFilterCreateMultiple)
{
ASSERT_SOME(link::veth::create(TEST_VETH_LINK, TEST_PEER_LINK, None()));
EXPECT_SOME_TRUE(link::exists(TEST_VETH_LINK));
EXPECT_SOME_TRUE(link::exists(TEST_PEER_LINK));
ASSERT_SOME_TRUE(ingress::create(TEST_VETH_LINK));
Result<net::MAC> mac = net::mac(TEST_VETH_LINK);
ASSERT_SOME(mac);
net::IP ip = net::IP(0x01020304); // 1.2.3.4
Try<ip::PortRange> sourcePorts1 =
ip::PortRange::fromBeginEnd(1024, 1027);
ASSERT_SOME(sourcePorts1);
Try<ip::PortRange> destinationPorts1 =
ip::PortRange::fromBeginEnd(2000, 2000);
ASSERT_SOME(destinationPorts1);
Try<ip::PortRange> sourcePorts2 =
ip::PortRange::fromBeginEnd(3024, 3025);
ASSERT_SOME(sourcePorts2);
Try<ip::PortRange> destinationPorts2 =
ip::PortRange::fromBeginEnd(4000, 4003);
ASSERT_SOME(destinationPorts2);
ip::Classifier classifier1 =
ip::Classifier(
mac.get(),
ip,
sourcePorts1.get(),
destinationPorts1.get());
ip::Classifier classifier2 =
ip::Classifier(
mac.get(),
ip,
sourcePorts2.get(),
destinationPorts2.get());
EXPECT_SOME_TRUE(ip::create(
TEST_VETH_LINK,
ingress::HANDLE,
classifier1,
Priority(2, 1),
action::Redirect(TEST_PEER_LINK)));
EXPECT_SOME_TRUE(ip::create(
TEST_VETH_LINK,
ingress::HANDLE,
classifier2,
Priority(2, 2),
action::Redirect(TEST_PEER_LINK)));
Result<vector<ip::Classifier>> classifiers =
ip::classifiers(TEST_VETH_LINK, ingress::HANDLE);
ASSERT_SOME(classifiers);
ASSERT_EQ(2u, classifiers->size());
EXPECT_SOME_EQ(mac.get(), classifiers->front().destinationMAC);
EXPECT_SOME_EQ(ip, classifiers->front().destinationIP);
EXPECT_SOME_EQ(
sourcePorts1.get(),
classifiers->front().sourcePorts);
EXPECT_SOME_EQ(
destinationPorts1.get(),
classifiers->front().destinationPorts);
EXPECT_SOME_EQ(mac.get(), classifiers->back().destinationMAC);
EXPECT_SOME_EQ(ip, classifiers->back().destinationIP);
EXPECT_SOME_EQ(
sourcePorts2.get(),
classifiers->back().sourcePorts);
EXPECT_SOME_EQ(
destinationPorts2.get(),
classifiers->back().destinationPorts);
}
TEST_F(RoutingVethTest, ROOT_IPFilterRemove)
{
ASSERT_SOME(link::veth::create(TEST_VETH_LINK, TEST_PEER_LINK, None()));
EXPECT_SOME_TRUE(link::exists(TEST_VETH_LINK));
EXPECT_SOME_TRUE(link::exists(TEST_PEER_LINK));
ASSERT_SOME_TRUE(ingress::create(TEST_VETH_LINK));
Result<net::MAC> mac = net::mac(TEST_VETH_LINK);
ASSERT_SOME(mac);
net::IP ip = net::IP(0x01020304); // 1.2.3.4
Try<ip::PortRange> sourcePorts1 =
ip::PortRange::fromBeginEnd(1024, 1027);
ASSERT_SOME(sourcePorts1);
Try<ip::PortRange> destinationPorts1 =
ip::PortRange::fromBeginEnd(2000, 2000);
ASSERT_SOME(destinationPorts1);
Try<ip::PortRange> sourcePorts2 =
ip::PortRange::fromBeginEnd(3024, 3025);
ASSERT_SOME(sourcePorts2);
Try<ip::PortRange> destinationPorts2 =
ip::PortRange::fromBeginEnd(4000, 4003);
ASSERT_SOME(destinationPorts2);
ip::Classifier classifier1 =
ip::Classifier(
mac.get(),
ip,
sourcePorts1.get(),
destinationPorts1.get());
ip::Classifier classifier2 =
ip::Classifier(
mac.get(),
ip,
sourcePorts2.get(),
destinationPorts2.get());
EXPECT_SOME_TRUE(ip::create(
TEST_VETH_LINK,
ingress::HANDLE,
classifier1,
None(),
action::Redirect(TEST_PEER_LINK)));
EXPECT_SOME_TRUE(ip::create(
TEST_VETH_LINK,
ingress::HANDLE,
classifier2,
None(),
action::Redirect(TEST_PEER_LINK)));
EXPECT_SOME_TRUE(ip::remove(TEST_VETH_LINK, ingress::HANDLE, classifier1));
EXPECT_SOME_FALSE(ip::exists(TEST_VETH_LINK, ingress::HANDLE, classifier1));
EXPECT_SOME_TRUE(ip::remove(TEST_VETH_LINK, ingress::HANDLE, classifier2));
EXPECT_SOME_FALSE(ip::exists(TEST_VETH_LINK, ingress::HANDLE, classifier2));
Result<vector<ip::Classifier>> classifiers =
ip::classifiers(TEST_VETH_LINK, ingress::HANDLE);
ASSERT_SOME(classifiers);
EXPECT_TRUE(classifiers->empty());
}
// Test the workaround introduced for MESOS-1617.
TEST_F(RoutingVethTest, ROOT_HandleGeneration)
{
ASSERT_SOME(link::veth::create(TEST_VETH_LINK, TEST_PEER_LINK, None()));
EXPECT_SOME_TRUE(link::exists(TEST_VETH_LINK));
EXPECT_SOME_TRUE(link::exists(TEST_PEER_LINK));
ASSERT_SOME_TRUE(ingress::create(TEST_VETH_LINK));
Result<net::MAC> mac = net::mac(TEST_VETH_LINK);
ASSERT_SOME(mac);
net::IP ip = net::IP(0x01020304); // 1.2.3.4
Try<ip::PortRange> sourcePorts1 =
ip::PortRange::fromBeginEnd(1024, 1027);
ASSERT_SOME(sourcePorts1);
Try<ip::PortRange> destinationPorts1 =
ip::PortRange::fromBeginEnd(2000, 2000);
ASSERT_SOME(destinationPorts1);
Try<ip::PortRange> sourcePorts2 =
ip::PortRange::fromBeginEnd(3024, 3025);
ASSERT_SOME(sourcePorts2);
Try<ip::PortRange> destinationPorts2 =
ip::PortRange::fromBeginEnd(4000, 4003);
ASSERT_SOME(destinationPorts2);
ip::Classifier classifier1 =
ip::Classifier(
mac.get(),
ip,
sourcePorts1.get(),
destinationPorts1.get());
ip::Classifier classifier2 =
ip::Classifier(
mac.get(),
ip,
sourcePorts2.get(),
destinationPorts2.get());
// Use handle 800:00:fff for the first filter.
EXPECT_SOME_TRUE(ip::create(
TEST_VETH_LINK,
ingress::HANDLE,
classifier1,
Priority(2, 1),
U32Handle(0x800, 0x0, 0xfff),
action::Redirect(TEST_PEER_LINK)));
// With the workaround, this filter should be assigned a handle
// different than 800:00:fff.
EXPECT_SOME_TRUE(ip::create(
TEST_VETH_LINK,
ingress::HANDLE,
classifier2,
Priority(2, 1),
action::Redirect(TEST_PEER_LINK)));
// Try to remove the second filter. If we don't have the workaround,
// removing the second filter will return false since the kernel
// will find the handle matches the first filter.
EXPECT_SOME_TRUE(ip::remove(TEST_VETH_LINK, ingress::HANDLE, classifier2));
}
} // namespace tests {
} // namespace internal {
} // namespace mesos {