blob: 10730ad5c131c37c46a5d4bd14f3eb31d3c5ef91 [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 <stout/foreach.hpp>
#include <stout/gtest.hpp>
#include <stout/hashmap.hpp>
#include <stout/net.hpp>
#include <stout/stringify.hpp>
#include "linux/routing/route.hpp"
#include "linux/routing/utils.hpp"
#include "linux/routing/filter/arp.hpp"
#include "linux/routing/filter/icmp.hpp"
#include "linux/routing/filter/ip.hpp"
#include "linux/routing/link/link.hpp"
#include "linux/routing/queueing/handle.hpp"
#include "linux/routing/queueing/ingress.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;
static const string TEST_VETH_LINK = "veth-test";
static const string TEST_PEER_LINK = "veth-peer";
class RoutingTest : public ::testing::Test
{
protected:
virtual void SetUp()
{
ASSERT_SOME(routing::check())
<< "-------------------------------------------------------------\n"
<< "We cannot run any routing tests because your libnl\n"
<< "library is not new enough. You can either install a\n"
<< "new libnl library, or disable this test case\n"
<< "-------------------------------------------------------------";
}
};
// Tests that require setting up virtual ethernet on host.
class RoutingVethTest : public RoutingTest
{
protected:
virtual void SetUp()
{
RoutingTest::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));
}
virtual void TearDown()
{
link::remove(TEST_VETH_LINK);
}
};
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.get().begin());
EXPECT_EQ(7u, ports.get().end());
EXPECT_EQ(0xfffc, ports.get().mask());
EXPECT_EQ("[4,7]", stringify(ports.get()));
ports = ip::PortRange::fromBeginEnd(10, 10);
ASSERT_SOME(ports);
EXPECT_EQ(10u, ports.get().begin());
EXPECT_EQ(10u, ports.get().end());
EXPECT_EQ(0xffff, ports.get().mask());
EXPECT_EQ("[10,10]", stringify(ports.get()));
ports = ip::PortRange::fromBeginMask(20, 0xffff);
ASSERT_SOME(ports);
EXPECT_EQ(20u, ports.get().begin());
EXPECT_EQ(20u, ports.get().end());
EXPECT_EQ(0xffff, ports.get().mask());
EXPECT_EQ("[20,20]", stringify(ports.get()));
ports = ip::PortRange::fromBeginMask(1024, 0xfff8);
ASSERT_SOME(ports);
EXPECT_EQ(1024u, ports.get().begin());
EXPECT_EQ(1031u, ports.get().end());
EXPECT_EQ(0xfff8, ports.get().mask());
EXPECT_EQ("[1024,1031]", stringify(ports.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());
}
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.get().contains("rx_packets"));
EXPECT_TRUE(statistics.get().contains("rx_bytes"));
EXPECT_TRUE(statistics.get().contains("tx_packets"));
EXPECT_TRUE(statistics.get().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(RoutingVethTest, ROOT_LinkCreate)
{
ASSERT_SOME(link::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::create(TEST_VETH_LINK, TEST_PEER_LINK, None()));
}
TEST_F(RoutingVethTest, ROOT_LinkRemove)
{
ASSERT_SOME(link::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");
return -1;
}
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, NULL);
ASSERT_NE(-1, pid);
// In parent process.
ASSERT_SOME(link::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.
int status;
EXPECT_NE(-1, waitpid((pid_t) -1, &status, 0));
ASSERT_TRUE(WIFSIGNALED(status));
EXPECT_EQ(SIGKILL, WTERMSIG(status));
}
TEST_F(RoutingVethTest, ROOT_LinkWait)
{
AWAIT_READY(link::removed(TEST_VETH_LINK));
ASSERT_SOME(link::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::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::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::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_ARPFilterCreate)
{
ASSERT_SOME(link::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(arp::create(
TEST_VETH_LINK,
ingress::HANDLE,
None(),
action::Redirect(TEST_PEER_LINK)));
EXPECT_SOME_TRUE(arp::exists(TEST_VETH_LINK, ingress::HANDLE));
}
TEST_F(RoutingVethTest, ROOT_ARPFilterCreateDuplicated)
{
ASSERT_SOME(link::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(arp::create(
TEST_VETH_LINK,
ingress::HANDLE,
None(),
action::Mirror(links)));
EXPECT_SOME_TRUE(arp::exists(TEST_VETH_LINK, ingress::HANDLE));
EXPECT_SOME_FALSE(arp::create(
TEST_VETH_LINK,
ingress::HANDLE,
None(),
action::Redirect(TEST_PEER_LINK)));
}
TEST_F(RoutingVethTest, ROOT_ARPFilterRemove)
{
ASSERT_SOME(link::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(arp::create(
TEST_VETH_LINK,
ingress::HANDLE,
None(),
action::Mirror(links)));
EXPECT_SOME_TRUE(arp::exists(TEST_VETH_LINK, ingress::HANDLE));
EXPECT_SOME_TRUE(arp::remove(TEST_VETH_LINK, ingress::HANDLE));
EXPECT_SOME_FALSE(arp::exists(TEST_VETH_LINK, ingress::HANDLE));
}
TEST_F(RoutingVethTest, ROOT_ARPFilterUpdate)
{
ASSERT_SOME(link::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(arp::update(
TEST_VETH_LINK,
ingress::HANDLE,
action::Mirror(links)));
EXPECT_SOME_TRUE(arp::create(
TEST_VETH_LINK,
ingress::HANDLE,
None(),
action::Redirect(TEST_PEER_LINK)));
EXPECT_SOME_TRUE(arp::exists(TEST_VETH_LINK, ingress::HANDLE));
EXPECT_SOME_TRUE(arp::update(
TEST_VETH_LINK,
ingress::HANDLE,
action::Mirror(links)));
EXPECT_SOME_TRUE(arp::exists(TEST_VETH_LINK, ingress::HANDLE));
}
TEST_F(RoutingVethTest, ROOT_ICMPFilterCreate)
{
ASSERT_SOME(link::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.get().size());
EXPECT_SOME_EQ(ip, classifiers.get().front().destinationIP());
}
TEST_F(RoutingVethTest, ROOT_ICMPFilterCreateDuplicated)
{
ASSERT_SOME(link::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::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.get().size());
EXPECT_SOME_EQ(ip1, classifiers.get().front().destinationIP());
EXPECT_SOME_EQ(ip2, classifiers.get().back().destinationIP());
}
TEST_F(RoutingVethTest, ROOT_ICMPFilterRemove)
{
ASSERT_SOME(link::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::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::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.get().size());
EXPECT_SOME_EQ(mac.get(), classifiers.get().front().destinationMAC());
EXPECT_SOME_EQ(ip, classifiers.get().front().destinationIP());
EXPECT_SOME_EQ(
sourcePorts.get(),
classifiers.get().front().sourcePorts());
EXPECT_SOME_EQ(
destinationPorts.get(),
classifiers.get().front().destinationPorts());
}
TEST_F(RoutingVethTest, ROOT_IPFilterCreate2)
{
ASSERT_SOME(link::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.get().size());
EXPECT_NONE(classifiers.get().front().destinationMAC());
EXPECT_SOME_EQ(ip, classifiers.get().front().destinationIP());
EXPECT_NONE(classifiers.get().front().sourcePorts());
EXPECT_NONE(classifiers.get().front().destinationPorts());
}
TEST_F(RoutingVethTest, ROOT_IPFilterCreateDuplicated)
{
ASSERT_SOME(link::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::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.get().size());
EXPECT_SOME_EQ(mac.get(), classifiers.get().front().destinationMAC());
EXPECT_SOME_EQ(ip, classifiers.get().front().destinationIP());
EXPECT_SOME_EQ(
sourcePorts1.get(),
classifiers.get().front().sourcePorts());
EXPECT_SOME_EQ(
destinationPorts1.get(),
classifiers.get().front().destinationPorts());
EXPECT_SOME_EQ(mac.get(), classifiers.get().back().destinationMAC());
EXPECT_SOME_EQ(ip, classifiers.get().back().destinationIP());
EXPECT_SOME_EQ(
sourcePorts2.get(),
classifiers.get().back().sourcePorts());
EXPECT_SOME_EQ(
destinationPorts2.get(),
classifiers.get().back().destinationPorts());
}
TEST_F(RoutingVethTest, ROOT_IPFilterRemove)
{
ASSERT_SOME(link::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_EQ(0u, classifiers.get().size());
}
// Test the workaround introduced for MESOS-1617.
TEST_F(RoutingVethTest, ROOT_HandleGeneration)
{
ASSERT_SOME(link::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));
}