iface_mgr_unittest.cc 126 KB
Newer Older
1
// Copyright (C) 2011-2018 Internet Systems Consortium, Inc. ("ISC")
2
//
3 4 5
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 7 8

#include <config.h>

9 10 11
#include <asiolink/io_address.h>
#include <dhcp/dhcp4.h>
#include <dhcp/iface_mgr.h>
12
#include <dhcp/option.h>
13
#include <dhcp/pkt6.h>
14
#include <dhcp/pkt_filter.h>
15
#include <dhcp/tests/iface_mgr_test_config.h>
16
#include <dhcp/tests/pkt_filter6_test_utils.h>
17
#include <dhcp/tests/packet_queue_testutils.h>
18

19
#include <boost/bind.hpp>
20
#include <boost/foreach.hpp>
21
#include <boost/scoped_ptr.hpp>
22 23
#include <gtest/gtest.h>

24
#include <fcntl.h>
25 26 27 28 29 30
#include <fstream>
#include <iostream>
#include <sstream>

#include <arpa/inet.h>
#include <unistd.h>
31 32 33

using namespace std;
using namespace isc;
34
using namespace isc::asiolink;
35
using namespace isc::dhcp;
36
using namespace isc::dhcp::test;
37
using boost::scoped_ptr;
38

39
namespace {
40

41 42 43 44 45 46 47 48
// Name of loopback interface detection
const size_t BUF_SIZE = 32;
char LOOPBACK[BUF_SIZE] = "lo";

// Ports used during testing
const uint16_t PORT1 = 10547;   // V6 socket
const uint16_t PORT2 = 10548;   // V4 socket

49 50 51 52
// On some systems measured duration of receive6() and receive4() appears to be
// shorter than select() timeout.  This may be the case if different time
// resolutions are used by these functions.  For such cases we set the
// tolerance to 0.01s.
53 54
const uint32_t TIMEOUT_TOLERANCE = 10000;

55 56 57 58 59 60 61 62
/// This test verifies that the socket read buffer can be used to
/// receive the data and that the data can be read from it.
TEST(IfaceTest, readBuffer) {
    // Create fake interface object.
    Iface iface("em0", 0);
    // The size of read buffer should initially be 0 and the returned
    // pointer should be NULL.
    ASSERT_EQ(0, iface.getReadBufferSize());
63
    EXPECT_EQ(NULL, iface.getReadBuffer());
64 65 66 67 68 69

    // Let's resize the buffer.
    iface.resizeReadBuffer(256);
    // Check that the buffer has expected size.
    ASSERT_EQ(256, iface.getReadBufferSize());
    // The returned pointer should now be non-NULL.
70
    uint8_t* buf_ptr = iface.getReadBuffer();
71 72 73
    ASSERT_FALSE(buf_ptr == NULL);

    // Use the pointer to set some data.
74
    for (size_t i = 0; i < iface.getReadBufferSize(); ++i) {
75 76 77
        buf_ptr[i] = i;
    }

78
    // Get the pointer again and validate the data.
79
    buf_ptr = iface.getReadBuffer();
80
    ASSERT_EQ(256, iface.getReadBufferSize());
81
    for (size_t i = 0; i < iface.getReadBufferSize(); ++i) {
82 83
        // Use assert so as it fails on the first failure, no need
        // to continue further checks.
84
        ASSERT_EQ(i, buf_ptr[i]);
85 86 87
    }
}

88 89
// Check that counting the number of active addresses on the interface
// works as expected.
90
TEST(IfaceTest, countActive4) {
91
    Iface iface("eth0", 0);
92
    ASSERT_EQ(0, iface.countActive4());
93 94

    iface.addAddress(IOAddress("192.168.0.2"));
95
    ASSERT_EQ(1, iface.countActive4());
96 97

    iface.addAddress(IOAddress("2001:db8:1::1"));
98
    ASSERT_EQ(1, iface.countActive4());
99 100

    iface.addAddress(IOAddress("192.168.0.3"));
101
    ASSERT_EQ(2, iface.countActive4());
102 103

    ASSERT_NO_THROW(iface.setActive(IOAddress("192.168.0.2"), false));
104
    ASSERT_EQ(1, iface.countActive4());
105 106

    ASSERT_NO_THROW(iface.setActive(IOAddress("192.168.0.3"), false));
107
    ASSERT_EQ(0, iface.countActive4());
108 109
}

110 111 112 113 114 115 116 117 118 119 120 121 122
/// Mock object implementing PktFilter class.  It is used by
/// IfaceMgrTest::setPacketFilter to verify that IfaceMgr::setPacketFilter
/// sets this object as a handler for opening sockets. This dummy
/// class simply records that openSocket function was called by
/// the IfaceMgr as expected.
///
/// @todo This class currently doesn't verify that send/receive functions
/// were called. In order to test it, there is a need to supply dummy
/// function performing select() on certain sockets. The system select()
/// call will fail when dummy socket descriptor is provided and thus
/// TestPktFilter::receive will never be called. The appropriate extension
/// to IfaceMgr is planned along with implementation of other "Packet
/// Filters" such as these supporting Linux Packet Filtering and
Andrei Pavel's avatar
Andrei Pavel committed
123
/// Berkeley Packet Filtering.
124 125 126 127 128 129 130 131
class TestPktFilter : public PktFilter {
public:

    /// Constructor
    TestPktFilter()
        : open_socket_called_(false) {
    }

132 133 134 135
    virtual bool isDirectResponseSupported() const {
        return (false);
    }

136 137 138 139 140 141 142 143 144 145 146 147 148 149
    /// @brief Pretend to open a socket.
    ///
    /// This function doesn't open a real socket. It always returns the
    /// same fake socket descriptor. It also records the fact that it has
    /// been called in the public open_socket_called_ member.
    /// As in the case of opening a real socket, this function will check
    /// if there is another fake socket "bound" to the same address and port.
    /// If there is, it will throw an exception. This allows to simulate the
    /// conditions when one of the sockets can't be open because there is
    /// a socket already open and test how IfaceMgr will handle it.
    ///
    /// @param iface An interface on which the socket is to be opened.
    /// @param addr An address to which the socket is to be bound.
    /// @param port A port to which the socket is to be bound.
150
    virtual SocketInfo openSocket(Iface& iface,
151 152
                                  const isc::asiolink::IOAddress& addr,
                                  const uint16_t port,
153
                                  const bool join_multicast,
154
                                  const bool) {
155 156 157 158 159
        // Check if there is any other socket bound to the specified address
        // and port on this interface.
        const Iface::SocketCollection& sockets = iface.getSockets();
        for (Iface::SocketCollection::const_iterator socket = sockets.begin();
             socket != sockets.end(); ++socket) {
160 161 162
            if (((socket->addr_ == addr) ||
                 ((socket->addr_ == IOAddress("::")) && join_multicast)) &&
                socket->port_ == port) {
163 164 165
                isc_throw(SocketConfigError, "test socket bind error");
            }
        }
166
        open_socket_called_ = true;
167
        return (SocketInfo(addr, port, 255));
168 169 170
    }

    /// Does nothing
171
    virtual Pkt4Ptr receive(Iface&, const SocketInfo&) {
172 173 174 175
        return (Pkt4Ptr());
    }

    /// Does nothing
176
    virtual int send(const Iface&, uint16_t, const Pkt4Ptr&) {
177 178 179 180 181 182 183
        return (0);
    }

    /// Holds the information whether openSocket was called on this
    /// object after its creation.
    bool open_socket_called_;
};
184

185
class NakedIfaceMgr: public IfaceMgr {
186
    // "Naked" Interface Manager, exposes internal fields
187
public:
188 189

    /// @brief Constructor.
190
    NakedIfaceMgr() {
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
        loDetect();
    }

    /// @brief detects name of the loopback interface
    ///
    /// This method detects name of the loopback interface.
    static void loDetect() {
        // Poor man's interface detection.  It will go away as soon as proper
        // interface detection is implemented
        if (if_nametoindex("lo") > 0) {
            snprintf(LOOPBACK, BUF_SIZE - 1, "lo");
        } else if (if_nametoindex("lo0") > 0) {
            snprintf(LOOPBACK, BUF_SIZE - 1, "lo0");
        } else {
            cout << "Failed to detect loopback interface. Neither "
                 << "lo nor lo0 worked. I give up." << endl;
            FAIL();
        }
209
    }
210 211 212 213

    /// @brief Returns the collection of existing interfaces.
    IfaceCollection& getIfacesLst() { return (ifaces_); }

Andrei Pavel's avatar
Andrei Pavel committed
214
    /// @brief This function creates fictitious interfaces with fictitious
215 216 217 218 219 220 221 222 223 224 225
    /// addresses.
    ///
    /// These interfaces can be used in tests that don't actually try
    /// to open the sockets on these interfaces. Some tests use mock
    /// objects to mimic sockets being open. These interfaces are
    /// suitable for such tests.
    void createIfaces() {

        ifaces_.clear();

        // local loopback
226 227 228
        IfacePtr lo = createIface("lo", 0);
        lo->addAddress(IOAddress("127.0.0.1"));
        lo->addAddress(IOAddress("::1"));
229
        ifaces_.push_back(lo);
230
        // eth0
231 232 233 234
        IfacePtr eth0 = createIface("eth0", 1);
        eth0->addAddress(IOAddress("10.0.0.1"));
        eth0->addAddress(IOAddress("fe80::3a60:77ff:fed5:cdef"));
        eth0->addAddress(IOAddress("2001:db8:1::1"));
235
        ifaces_.push_back(eth0);
236
        // eth1
237 238 239
        IfacePtr eth1 = createIface("eth1", 2);
        eth1->addAddress(IOAddress("192.0.2.3"));
        eth1->addAddress(IOAddress("fe80::3a60:77ff:fed5:abcd"));
240
        ifaces_.push_back(eth1);
241 242 243 244 245 246 247 248 249 250
    }

    /// @brief Create an object representing interface.
    ///
    /// Apart from creating an interface, this function also sets the
    /// interface flags:
    /// - loopback flag if interface name is "lo"
    /// - up always true
    /// - running always true
    /// - inactive always to false
251
    /// - multicast always to true
252
    /// - broadcast always to false
253 254 255 256 257 258 259 260
    ///
    /// If one needs to modify the default flag settings, the setIfaceFlags
    /// function should be used.
    ///
    /// @param name A name of the interface to be created.
    /// @param ifindex An index of the interface to be created.
    ///
    /// @return An object representing interface.
261 262
    static IfacePtr createIface(const std::string& name, const int ifindex) {
        IfacePtr iface(new Iface(name, ifindex));
263
        if (name == "lo") {
264
            iface->flag_loopback_ = true;
265
            // Don't open sockets on loopback interface.
266 267
            iface->inactive4_ = true;
            iface->inactive6_ = true;
268
        } else {
269 270
            iface->inactive4_ = false;
            iface->inactive6_ = false;
271
        }
272
        iface->flag_multicast_ = true;
273 274 275 276 277
        // On BSD systems, the SO_BINDTODEVICE option is not supported.
        // Therefore the IfaceMgr will throw an exception on attempt to
        // open sockets on more than one broadcast-capable interface at
        // the same time. In order to prevent this error, we mark all
        // interfaces broadcast-incapable for unit testing.
278 279 280
        iface->flag_broadcast_ = false;
        iface->flag_up_ = true;
        iface->flag_running_ = true;
281 282 283
        return (iface);
    }

284
    /// @brief Checks if the specified interface has a socket bound to a
Josh Soref's avatar
Josh Soref committed
285
    /// specified address.
286 287 288 289 290 291
    ///
    /// @param iface_name A name of the interface.
    /// @param addr An address to be checked for binding.
    ///
    /// @return true if there is a socket bound to the specified address.
    bool isBound(const std::string& iface_name, const std::string& addr) {
292 293
        IfacePtr iface = getIface(iface_name);
        if (!iface) {
294 295 296 297 298 299 300 301
            ADD_FAILURE() << "the interface " << iface_name << " doesn't exist";
            return (false);
        }
        const Iface::SocketCollection& sockets = iface->getSockets();
        for (Iface::SocketCollection::const_iterator sock = sockets.begin();
             sock != sockets.end(); ++sock) {
            if (sock->addr_ == IOAddress(addr)) {
                return (true);
302

303 304
            } else if ((sock->addr_ == IOAddress("::")) &&
                       (IOAddress(addr).isV6LinkLocal())) {
305 306
                BOOST_FOREACH(Iface::Address a, iface->getAddresses()) {
                    if (a.get() == IOAddress(addr)) {
307 308 309
                        return (true);
                    }
                }
310 311 312 313 314 315
            }
        }
        return (false);
    }

    /// @brief Modify flags on the interface.
316 317 318 319 320 321 322 323
    ///
    /// @param name A name of the interface.
    /// @param loopback A new value of the loopback flag.
    /// @param up A new value of the up flag.
    /// @param running A new value of the running flag.
    /// @param inactive A new value of the inactive flag.
    void setIfaceFlags(const std::string& name, const bool loopback,
                       const bool up, const bool running,
324 325
                       const bool inactive4,
                       const bool inactive6) {
326 327
        for (IfaceMgr::IfaceCollection::iterator iface = ifaces_.begin();
             iface != ifaces_.end(); ++iface) {
328 329 330 331 332 333
            if ((*iface)->getName() == name) {
                (*iface)->flag_loopback_ = loopback;
                (*iface)->flag_up_ = up;
                (*iface)->flag_running_ = running;
                (*iface)->inactive4_ = inactive4;
                (*iface)->inactive6_ = inactive6;
334 335 336
            }
        }
    }
337

338 339
};

340 341 342 343 344 345 346
/// @brief A test fixture class for IfaceMgr.
///
/// @todo Sockets being opened by IfaceMgr tests should be managed by
/// the test fixture. In particular, the class should close sockets after
/// each test. Current approach where test cases are responsible for
/// closing sockets is resource leak prone, especially in case of the
/// test failure path.
347 348
class IfaceMgrTest : public ::testing::Test {
public:
349 350 351
    /// @brief Constructor.
    IfaceMgrTest()
        : errors_count_(0) {
352
    }
353

354 355
    ~IfaceMgrTest() {
    }
356

357 358 359 360 361 362 363 364 365 366
    /// @brief Tests the number of IPv6 sockets on interface
    ///
    /// This function checks the expected number of open IPv6 sockets on the
    /// specified interface. On non-Linux systems, sockets are bound to a
    /// link-local address and the number of unicast addresses specified.
    /// On Linux systems, there is one more socket bound to a ff02::1:2
    /// multicast address.
    ///
    /// @param iface An interface on which sockets are open.
    /// @param unicast_num A number of unicast addresses bound.
367 368 369
    /// @param link_local_num A number of link local addresses bound.
    void checkSocketsCount6(const Iface& iface, const int unicast_num,
                            const int link_local_num = 1) {
370 371 372 373 374 375 376 377
        // On local-loopback interface, there should be no sockets.
        if (iface.flag_loopback_) {
            ASSERT_TRUE(iface.getSockets().empty())
                << "expected empty socket set on loopback interface "
                << iface.getName();
            return;
        }
#if defined OS_LINUX
378 379 380 381 382
        // On Linux, for each link-local address there may be an
        // additional socket opened and bound to ff02::1:2. This socket
        // is only opened if the interface is multicast-capable.
        ASSERT_EQ(unicast_num + (iface.flag_multicast_ ? link_local_num : 0)
                  + link_local_num, iface.getSockets().size())
383 384 385 386
            << "invalid number of sockets on interface "
            << iface.getName();
#else
        // On non-Linux, there is no additional socket.
387
        ASSERT_EQ(unicast_num + link_local_num, iface.getSockets().size())
388 389 390 391 392 393
            << "invalid number of sockets on interface "
            << iface.getName();

#endif
    }

Andrei Pavel's avatar
Andrei Pavel committed
394
    // Get the number of IPv4 or IPv6 sockets on the loopback interface
395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411
    int getOpenSocketsCount(const Iface& iface, uint16_t family) const {
        // Get all sockets.
        Iface::SocketCollection sockets = iface.getSockets();

        // Loop through sockets and try to find the ones which match the
        // specified type.
        int sockets_count = 0;
        for (Iface::SocketCollection::const_iterator sock = sockets.begin();
             sock != sockets.end(); ++sock) {
            // Match found, increase the counter.
            if (sock->family_ == family) {
                ++sockets_count;
            }
        }
        return (sockets_count);
    }

412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432
    /// @brief returns socket bound to a specific address (or NULL)
    ///
    /// A helper function, used to pick a socketinfo that is bound to a given
    /// address.
    ///
    /// @param sockets sockets collection
    /// @param addr address the socket is bound to
    ///
    /// @return socket info structure (or NULL)
    const isc::dhcp::SocketInfo*
    getSocketByAddr(const isc::dhcp::Iface::SocketCollection& sockets,
                    const IOAddress& addr) {
        for (isc::dhcp::Iface::SocketCollection::const_iterator s =
                 sockets.begin(); s != sockets.end(); ++s) {
            if (s->addr_ == addr) {
                return (&(*s));
            }
        }
        return (NULL);
    }

433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449
    /// @brief Implements an IfaceMgr error handler.
    ///
    /// This function can be installed as an error handler for the
    /// IfaceMgr::openSockets4 function. The error handler is invoked
    /// when an attempt to open a particular socket fails for any reason.
    /// Typically, the error handler will log a warning. When the error
    /// handler returns, the openSockets4 function should continue opening
    /// sockets on other interfaces.
    ///
    /// @param errmsg An error string indicating the reason for failure.
    void ifaceMgrErrorHandler(const std::string&) {
        // Increase the counter of invocations to this function. By checking
        // this number, a test amy check if the expected number of errors
        // has occurred.
        ++errors_count_;
    }

450 451
    /// @brief Tests the ability to send and receive DHCPv6 packets
    ///
452
    /// This test calls @r IfaceMgr::configureDHCPPacketQueue, passing in the
453 454 455 456 457 458 459 460 461 462 463 464 465 466 467
    /// given queue configuration.  It then calls IfaceMgr::startDHCPReceiver
    /// and verifies whether or not the receive thread has been started as
    /// expected.  Next it creates a generic DHCPv6 packet and sends it over
    /// the loop back interface.  It invokes IfaceMgr::receive6 to receive the
    /// packet sent, and compares to the packets for equality.
    ///
    /// @param dhcp_queue_control dhcp-queue-control contents to use for the test
    /// @param exp_queue_enabled flag that indicates if packet queuing is expected
    /// to be enabled.
    void sendReceive6Test(data::ConstElementPtr dhcp_queue_control, bool exp_queue_enabled) {
        scoped_ptr<NakedIfaceMgr> ifacemgr(new NakedIfaceMgr());

        // Testing socket operation in a portable way is tricky
        // without interface detection implemented
        // let's assume that every supported OS have lo interface
468
        IOAddress lo_addr("::1");
469 470
        int socket1 = 0, socket2 = 0;
        EXPECT_NO_THROW(
471 472
            socket1 = ifacemgr->openSocket(LOOPBACK, lo_addr, 10547);
            socket2 = ifacemgr->openSocket(LOOPBACK, lo_addr, 10546);
473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539
        );

        EXPECT_GE(socket1, 0);
        EXPECT_GE(socket2, 0);

        // Configure packet queueing as desired.
        bool queue_enabled = false;
        ASSERT_NO_THROW(queue_enabled = ifacemgr->configureDHCPPacketQueue(AF_INET6, dhcp_queue_control));

        // Verify that we have a queue only if we expected one.
        ASSERT_EQ(exp_queue_enabled, queue_enabled);

        // Thread should only start when there is a packet queue.
        ASSERT_NO_THROW(ifacemgr->startDHCPReceiver(AF_INET6));
        ASSERT_TRUE(queue_enabled == ifacemgr->isReceiverRunning());

        // If the thread is already running, trying to start it again should fail.
        if (queue_enabled) {
            ASSERT_THROW(ifacemgr->startDHCPReceiver(AF_INET6), InvalidOperation);
            // Should still have one running.
            ASSERT_TRUE(ifacemgr->isReceiverRunning());
        }

        // Let's build our DHCPv6 packet.
        // prepare dummy payload
        uint8_t data[128];
        for (uint8_t i = 0; i < 128; i++) {
            data[i] = i;
        }

        Pkt6Ptr sendPkt = Pkt6Ptr(new Pkt6(data, 128));
        sendPkt->repack();
        sendPkt->setRemotePort(10547);
        sendPkt->setRemoteAddr(IOAddress("::1"));
        sendPkt->setIndex(1);
        sendPkt->setIface(LOOPBACK);

        // Send the packet.
        EXPECT_EQ(true, ifacemgr->send(sendPkt));

        // Now, let's try and receive it.
        Pkt6Ptr rcvPkt;
        rcvPkt = ifacemgr->receive6(10);
        ASSERT_TRUE(rcvPkt); // received our own packet

        // let's check that we received what was sent
        ASSERT_EQ(sendPkt->data_.size(), rcvPkt->data_.size());
        EXPECT_EQ(0, memcmp(&sendPkt->data_[0], &rcvPkt->data_[0],
                            rcvPkt->data_.size()));

        EXPECT_EQ(sendPkt->getRemoteAddr(), rcvPkt->getRemoteAddr());

        // since we opened 2 sockets on the same interface and none of them is multicast,
        // none is preferred over the other for sending data, so we really should not
        // assume the one or the other will always be chosen for sending data. Therefore
        // we should accept both values as source ports.
        EXPECT_TRUE((rcvPkt->getRemotePort() == 10546) || (rcvPkt->getRemotePort() == 10547));

        // Stop the thread.  This should be no harm/no foul if we're not
        // queueuing.  Either way, we should not have a thread afterwards.
        ASSERT_NO_THROW(ifacemgr->stopDHCPReceiver());
        ASSERT_FALSE(ifacemgr->isReceiverRunning());
    }


    /// @brief Tests the ability to send and receive DHCPv4 packets
    ///
540
    /// This test calls @r IfaceMgr::configureDHCPPacketQueue, passing in the
541 542 543 544 545 546 547 548 549 550 551 552 553 554 555
    /// given queue configuration.  It then calls IfaceMgr::startDHCPReceiver
    /// and verifies whether or not the receive thread has been started as
    /// expected.  Next it creates a DISCOVER packet and sends it over
    /// the loop back interface.  It invokes IfaceMgr::receive4 to receive the
    /// packet sent, and compares to the packets for equality.
    ///
    /// @param dhcp_queue_control dhcp-queue-control contents to use for the test
    /// @param exp_queue_enabled flag that indicates if packet queuing is expected
    /// to be enabled.
    void sendReceive4Test(data::ConstElementPtr dhcp_queue_control, bool exp_queue_enabled) {
        scoped_ptr<NakedIfaceMgr> ifacemgr(new NakedIfaceMgr());

        // Testing socket operation in a portable way is tricky
        // without interface detection implemented.
        // Let's assume that every supported OS has lo interface
556
        IOAddress lo_addr("127.0.0.1");
557 558
        int socket1 = 0;
        EXPECT_NO_THROW(
559
            socket1 = ifacemgr->openSocket(LOOPBACK, lo_addr, DHCP4_SERVER_PORT + 10000);
560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665
        );

        EXPECT_GE(socket1, 0);

        // Configure packet queueing as desired.
        bool queue_enabled = false;
        ASSERT_NO_THROW(queue_enabled = ifacemgr->configureDHCPPacketQueue(AF_INET, dhcp_queue_control));

        // Verify that we have a queue only if we expected one.
        ASSERT_EQ(exp_queue_enabled, queue_enabled);

        // Thread should only start when there is a packet queue.
        ASSERT_NO_THROW(ifacemgr->startDHCPReceiver(AF_INET));
        ASSERT_TRUE(queue_enabled == ifacemgr->isReceiverRunning());

        // If the thread is already running, trying to start it again should fail.
        if (queue_enabled) {
            ASSERT_THROW(ifacemgr->startDHCPReceiver(AF_INET), InvalidOperation);
            // Should still have one running.
            ASSERT_TRUE(ifacemgr->isReceiverRunning());
        }

        // Let's construct the packet to send.
        boost::shared_ptr<Pkt4> sendPkt(new Pkt4(DHCPDISCOVER, 1234) );
        sendPkt->setLocalAddr(IOAddress("127.0.0.1"));
        sendPkt->setLocalPort(DHCP4_SERVER_PORT + 10000 + 1);
        sendPkt->setRemotePort(DHCP4_SERVER_PORT + 10000);
        sendPkt->setRemoteAddr(IOAddress("127.0.0.1"));
        sendPkt->setIndex(1);
        sendPkt->setIface(string(LOOPBACK));
        sendPkt->setHops(6);
        sendPkt->setSecs(42);
        sendPkt->setCiaddr(IOAddress("192.0.2.1"));
        sendPkt->setSiaddr(IOAddress("192.0.2.2"));
        sendPkt->setYiaddr(IOAddress("192.0.2.3"));
        sendPkt->setGiaddr(IOAddress("192.0.2.4"));

        // Unpack() now checks if mandatory DHCP_MESSAGE_TYPE is present.
        // Workarounds (creating DHCP Message Type Option by hand) are no longer
        // needed as setDhcpType() is called in constructor.

        uint8_t sname[] = "That's just a string that will act as SNAME";
        sendPkt->setSname(sname, strlen((const char*)sname));
        uint8_t file[] = "/another/string/that/acts/as/a/file_name.txt";
        sendPkt->setFile(file, strlen((const char*)file));

        ASSERT_NO_THROW(
            sendPkt->pack();
        );

        // OK, Send the PACKET!
        EXPECT_NO_THROW(ifacemgr->send(sendPkt));

        // Now let's try and receive it.
        boost::shared_ptr<Pkt4> rcvPkt;
        ASSERT_NO_THROW(rcvPkt = ifacemgr->receive4(10));
        ASSERT_TRUE(rcvPkt); // received our own packet
        ASSERT_NO_THROW(
            rcvPkt->unpack();
        );

        // let's check that we received what was sent
        EXPECT_EQ(sendPkt->len(), rcvPkt->len());
        EXPECT_EQ("127.0.0.1", rcvPkt->getRemoteAddr().toText());
        EXPECT_EQ(sendPkt->getRemotePort(), rcvPkt->getLocalPort());
        EXPECT_EQ(sendPkt->getHops(), rcvPkt->getHops());
        EXPECT_EQ(sendPkt->getOp(),   rcvPkt->getOp());
        EXPECT_EQ(sendPkt->getSecs(), rcvPkt->getSecs());
        EXPECT_EQ(sendPkt->getFlags(), rcvPkt->getFlags());
        EXPECT_EQ(sendPkt->getCiaddr(), rcvPkt->getCiaddr());
        EXPECT_EQ(sendPkt->getSiaddr(), rcvPkt->getSiaddr());
        EXPECT_EQ(sendPkt->getYiaddr(), rcvPkt->getYiaddr());
        EXPECT_EQ(sendPkt->getGiaddr(), rcvPkt->getGiaddr());
        EXPECT_EQ(sendPkt->getTransid(), rcvPkt->getTransid());
        EXPECT_TRUE(sendPkt->getSname() == rcvPkt->getSname());
        EXPECT_TRUE(sendPkt->getFile() == rcvPkt->getFile());
        EXPECT_EQ(sendPkt->getHtype(), rcvPkt->getHtype());
        EXPECT_EQ(sendPkt->getHlen(), rcvPkt->getHlen());

        // since we opened 2 sockets on the same interface and none of them is multicast,
        // none is preferred over the other for sending data, so we really should not
        // assume the one or the other will always be chosen for sending data. We should
        // skip checking source port of sent address.

        // Close the socket. Further we will test if errors are reported
        // properly on attempt to use closed socket.
        close(socket1);

        // @todo Closing the socket does NOT cause a read error out of the
        // receiveDHCP<X>Packets() select.  Apparently this is because the
        // thread is already inside the select when the socket is closed,
        // and (at least under Centos 7.5), this does not interrupt the
        // select.  For now, we'll only test this for direct receive.
        if (!queue_enabled) {
            EXPECT_THROW(ifacemgr->receive4(10), SocketReadError);
        }

        // Verify write fails.
        EXPECT_THROW(ifacemgr->send(sendPkt), SocketWriteError);

        // Stop the thread.  This should be no harm/no foul if we're not
        // queueuing.  Either way, we should not have a thread afterwards.
        ASSERT_NO_THROW(ifacemgr->stopDHCPReceiver());
        ASSERT_FALSE(ifacemgr->isReceiverRunning());
    }

666 667 668
    /// Holds the invocation counter for ifaceMgrErrorHandler.
    int errors_count_;

669 670
};

671 672 673
// We need some known interface to work reliably. Loopback interface is named
// lo on Linux and lo0 on BSD boxes. We need to find out which is available.
// This is not a real test, but rather a workaround that will go away when
674
// interface detection is implemented on all OSes.
675
TEST_F(IfaceMgrTest, loDetect) {
676
    NakedIfaceMgr::loDetect();
677 678
}

679
// Uncomment this test to create packet writer. It will
680 681 682 683 684 685 686 687
// write incoming DHCPv6 packets as C arrays. That is useful
// for generating test sequences based on actual traffic
//
// TODO: this potentially should be moved to a separate tool
//

#if 0
TEST_F(IfaceMgrTest, dhcp6Sniffer) {
688
    // Testing socket operation in a portable way is tricky
689 690
    // without interface detection implemented

691
    static_cast<void>(remove("interfaces.txt"));
692 693 694 695 696

    ofstream interfaces("interfaces.txt", ios::ate);
    interfaces << "eth0 fe80::21e:8cff:fe9b:7349";
    interfaces.close();

697
    boost::scoped_ptr<NakedIfaceMgr> ifacemgr = new NakedIfaceMgr();
698

699
    Pkt6Ptr pkt;
700 701 702
    int cnt = 0;
    cout << "---8X-----------------------------------------" << endl;
    while (true) {
703
        pkt.reset(ifacemgr->receive());
704

705
        cout << "// this code is autogenerated. Do NOT edit." << endl;
706 707 708 709 710
        cout << "// Received " << pkt->data_len_ << " bytes packet:" << endl;
        cout << "Pkt6 *capture" << cnt++ << "() {" << endl;
        cout << "    Pkt6* pkt;" << endl;
        cout << "    pkt = new Pkt6(" << pkt->data_len_ << ");" << endl;
        cout << "    pkt->remote_port_ = " << pkt-> remote_port_ << ";" << endl;
711
        cout << "    pkt->remote_addr_ = IOAddress(\""
712
             << pkt->remote_addr_ << "\");" << endl;
713
        cout << "    pkt->local_port_ = " << pkt-> local_port_ << ";" << endl;
714
        cout << "    pkt->local_addr_ = IOAddress(\""
715
             << pkt->local_addr_ << "\");" << endl;
716 717
        cout << "    pkt->ifindex_ = " << pkt->ifindex_ << ";" << endl;
        cout << "    pkt->iface_ = \"" << pkt->iface_ << "\";" << endl;
718

719 720
        // TODO it is better to declare statically initialize the array
        // and then memcpy it to packet.
721
        for (int i=0; i< pkt->data_len_; i++) {
722 723
            cout << "    pkt->data_[" << i << "]="
                 << (int)(unsigned char)pkt->data_[i] << "; ";
724 725 726 727 728 729 730
            if (!(i%4))
                cout << endl;
        }
        cout << endl;
        cout << "    return (pkt);" << endl;
        cout << "}" << endl << endl;

731
        pkt.reset();
732 733
    }
    cout << "---8X-----------------------------------------" << endl;
734

735
    // Never happens. Infinite loop is infinite
736 737 738
}
#endif

739 740 741 742
// This test verifies that creation of the IfaceMgr instance doesn't
// cause an exception.
TEST_F(IfaceMgrTest, instance) {
    EXPECT_NO_THROW(IfaceMgr::instance());
743
}
744

745
TEST_F(IfaceMgrTest, ifaceClass) {
746
    // Basic tests for Iface inner class
747

748
    Iface iface("eth5", 7);
749
    EXPECT_STREQ("eth5/7", iface.getFullName().c_str());
750 751
}

752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777
// Test that the IPv4 address can be retrieved for the interface.
TEST_F(IfaceMgrTest, ifaceGetAddress) {
    Iface iface("eth0", 0);

    IOAddress addr("::1");
    // Initially, the Iface has no addresses assigned.
    EXPECT_FALSE(iface.getAddress4(addr));
    // Add some addresses with IPv4 address in the middle.
    iface.addAddress(IOAddress("fe80::3a60:77ff:fed5:cdef"));
    iface.addAddress(IOAddress("10.1.2.3"));
    iface.addAddress(IOAddress("2001:db8:1::2"));
    // The v4 address should be returned.
    EXPECT_TRUE(iface.getAddress4(addr));
    EXPECT_EQ("10.1.2.3", addr.toText());
    // Delete the IPv4 address and leave only two IPv6 addresses.
    ASSERT_NO_THROW(iface.delAddress(IOAddress("10.1.2.3")));
    // The IPv4 address should not be returned.
    EXPECT_FALSE(iface.getAddress4(addr));
    // Add a different IPv4 address at the end of the list.
    iface.addAddress(IOAddress("192.0.2.3"));
    // This new address should now be returned.
    EXPECT_TRUE(iface.getAddress4(addr));
    EXPECT_EQ("192.0.2.3", addr.toText());

}

778 779 780 781 782
// This test checks if it is possible to check that the specific address is
// assigned to the interface.
TEST_F(IfaceMgrTest, ifaceHasAddress) {
    IfaceMgrTestConfig config(true);

783 784
    IfacePtr iface = IfaceMgr::instance().getIface("eth0");
    ASSERT_TRUE(iface);
785
    EXPECT_TRUE(iface->hasAddress(IOAddress("10.0.0.1")));
786
    EXPECT_FALSE(iface->hasAddress(IOAddress("10.0.0.2")));
787 788 789 790 791
    EXPECT_TRUE(iface->hasAddress(IOAddress("fe80::3a60:77ff:fed5:cdef")));
    EXPECT_TRUE(iface->hasAddress(IOAddress("2001:db8:1::1")));
    EXPECT_FALSE(iface->hasAddress(IOAddress("2001:db8:1::2")));
}

792 793
// TODO: Implement getPlainMac() test as soon as interface detection
// is implemented.
794 795 796
TEST_F(IfaceMgrTest, getIface) {

    cout << "Interface checks. Please ignore socket binding errors." << endl;
797
    scoped_ptr<NakedIfaceMgr> ifacemgr(new NakedIfaceMgr());
798

799
    // Interface name, ifindex
800 801
    IfacePtr iface1(new Iface("lo1", 100));
    IfacePtr iface2(new Iface("eth9", 101));
802
    IfacePtr iface3(new Iface("en7", 102));
803
    IfacePtr iface4(new Iface("e1000g4", 103));
804
    cout << "This test assumes that there are less than 100 network interfaces"
805
         << " in the tested system and there are no lo1, eth9, en7, e1000g4"
806
         << " or wifi15 interfaces present." << endl;
807

808
    // Note: real interfaces may be detected as well
809 810 811 812 813
    ifacemgr->getIfacesLst().push_back(iface1);
    ifacemgr->getIfacesLst().push_back(iface2);
    ifacemgr->getIfacesLst().push_back(iface3);
    ifacemgr->getIfacesLst().push_back(iface4);

814 815
    cout << "There are " << ifacemgr->getIfacesLst().size()
         << " interfaces." << endl;
816
    for (IfaceMgr::IfaceCollection::iterator iface=ifacemgr->getIfacesLst().begin();
817 818
         iface != ifacemgr->getIfacesLst().end();
         ++iface) {
819
        cout << "  " << (*iface)->getFullName() << endl;
820 821 822
    }


823
    // Check that interface can be retrieved by ifindex
824 825
    IfacePtr tmp = ifacemgr->getIface(102);
    ASSERT_TRUE(tmp);
826

827
    EXPECT_EQ("en7", tmp->getName());
828
    EXPECT_EQ(102, tmp->getIndex());
829

830
    // Check that interface can be retrieved by name
831
    tmp = ifacemgr->getIface("lo1");
832
    ASSERT_TRUE(tmp);
833

834
    EXPECT_EQ("lo1", tmp->getName());
835
    EXPECT_EQ(100, tmp->getIndex());
836

837
    // Check that non-existing interfaces are not returned
838
    EXPECT_FALSE(ifacemgr->getIface("wifi15") );
839 840
}

841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859
TEST_F(IfaceMgrTest, clearIfaces) {
    NakedIfaceMgr ifacemgr;
    // Create a set of fake interfaces. At the same time, remove the actual
    // interfaces that have been detected by the IfaceMgr.
    ifacemgr.createIfaces();

    ASSERT_GT(ifacemgr.countIfaces(), 0);

    boost::shared_ptr<TestPktFilter> custom_packet_filter(new TestPktFilter());
    ASSERT_TRUE(custom_packet_filter);
    ASSERT_NO_THROW(ifacemgr.setPacketFilter(custom_packet_filter));

    ASSERT_NO_THROW(ifacemgr.openSockets4());

    ifacemgr.clearIfaces();

    EXPECT_EQ(0, ifacemgr.countIfaces());
}

860
// Verify that we have the expected default DHCPv4 packet queue.
861 862
TEST_F(IfaceMgrTest, packetQueue4) {
    NakedIfaceMgr ifacemgr;
863

864 865
    // Should not have a queue at start up.
    ASSERT_FALSE(ifacemgr.getPacketQueue4());
866

867
    // Verify that we can create a queue with default factory.
868
    data::ConstElementPtr config = makeQueueConfig(PacketQueueMgr4::DEFAULT_QUEUE_TYPE4, 2000);
869
    ASSERT_NO_THROW(ifacemgr.getPacketQueueMgr4()->createPacketQueue(config));
870
    CHECK_QUEUE_INFO(ifacemgr.getPacketQueue4(), "{ \"capacity\": 2000, \"queue-type\": \""
871
                     << PacketQueueMgr4::DEFAULT_QUEUE_TYPE4 << "\", \"size\": 0 }");
872 873
}

874
// Verify that we have the expected default DHCPv6 packet queue.
875 876 877
TEST_F(IfaceMgrTest, packetQueue6) {
    NakedIfaceMgr ifacemgr;

878 879
    // Should not have a queue at start up.
    ASSERT_FALSE(ifacemgr.getPacketQueue6());
880

881
    // Verify that we can create a queue with default factory.
882
    data::ConstElementPtr config = makeQueueConfig(PacketQueueMgr6::DEFAULT_QUEUE_TYPE6, 2000);
883
    ASSERT_NO_THROW(ifacemgr.getPacketQueueMgr6()->createPacketQueue(config));
884
    CHECK_QUEUE_INFO(ifacemgr.getPacketQueue6(), "{ \"capacity\": 2000, \"queue-type\": \""
885
                     << PacketQueueMgr6::DEFAULT_QUEUE_TYPE6 << "\", \"size\": 0 }");
886
}
887

888
TEST_F(IfaceMgrTest, receiveTimeout6) {
889
    using namespace boost::posix_time;
890 891 892 893
    std::cout << "Testing DHCPv6 packet reception timeouts."
              << " Test will block for a few seconds when waiting"
              << " for timeout to occur." << std::endl;

894
    scoped_ptr<NakedIfaceMgr> ifacemgr(new NakedIfaceMgr());
895
    // Open socket on the lo interface.
896
    IOAddress lo_addr("::1");
897 898
    int socket1 = 0;
    ASSERT_NO_THROW(
899
        socket1 = ifacemgr->openSocket(LOOPBACK, lo_addr, 10547)
900
    );
901 902
    // Socket is open if result is non-negative.
    ASSERT_GE(socket1, 0);
903 904
    // Start receiver.
    ASSERT_NO_THROW(ifacemgr->startDHCPReceiver(AF_INET6));
905 906

    // Remember when we call receive6().
907
    ptime start_time = microsec_clock::universal_time();
908
    // Call receive with timeout of 1s + 400000us = 1.4s.
909
    Pkt6Ptr pkt;
910
    ASSERT_NO_THROW(pkt = ifacemgr->receive6(1, 400000));
911
    // Remember when call to receive6() ended.
912
    ptime stop_time = microsec_clock::universal_time();
913 914 915 916
    // We did not send a packet to lo interface so we expect that
    // nothing has been received and timeout has been reached.
    ASSERT_FALSE(pkt);
    // Calculate duration of call to receive6().
917
    time_duration duration = stop_time - start_time;
918 919
    // We stop the clock when the call completes so it does not
    // precisely reflect the receive timeout. However the
Josh Soref's avatar
Josh Soref committed
920
    // uncertainty should be low enough to expect that measured
921
    // value is in the range <1.4s; 1.7s>.
922 923
    EXPECT_GE(duration.total_microseconds(),
              1400000 - TIMEOUT_TOLERANCE);
924
    EXPECT_LE(duration.total_microseconds(), 1700000);
925 926

    // Test timeout shorter than 1s.
927
    start_time = microsec_clock::universal_time();
928
    ASSERT_NO_THROW(pkt = ifacemgr->receive6(0, 500000));
929
    stop_time = microsec_clock::universal_time();
930
    ASSERT_FALSE(pkt);
931
    duration = stop_time - start_time;
932
    // Check if measured duration is within <0.5s; 0.8s>.
933 934
    EXPECT_GE(duration.total_microseconds(),
              500000 - TIMEOUT_TOLERANCE);
935
    EXPECT_LE(duration.total_microseconds(), 800000);
936 937 938 939

    // Test with invalid fractional timeout values.
    EXPECT_THROW(ifacemgr->receive6(0, 1000000), isc::BadValue);
    EXPECT_THROW(ifacemgr->receive6(1, 1000010), isc::BadValue);
940 941

    // Stop receiver.
942
    EXPECT_NO_THROW(ifacemgr->stopDHCPReceiver());
943 944 945
}

TEST_F(IfaceMgrTest, receiveTimeout4) {
946
    using namespace boost::posix_time;
947
    std::cout << "Testing DHCPv4 packet reception timeouts."
948 949 950
              << " Test will block for a few seconds when waiting"
              << " for timeout to occur." << std::endl;

951
    scoped_ptr<NakedIfaceMgr> ifacemgr(new NakedIfaceMgr());
952
    // Open socket on the lo interface.
953
    IOAddress lo_addr("127.0.0.1");
954 955
    int socket1 = 0;
    ASSERT_NO_THROW(
956
        socket1 = ifacemgr->openSocket(LOOPBACK, lo_addr, 10067)
957
    );
958 959
    // Socket is open if returned value is non-negative.
    ASSERT_GE(socket1, 0);
960

961 962
    // Start receiver.
    ASSERT_NO_THROW(ifacemgr->startDHCPReceiver(AF_INET));
963

964
    Pkt4Ptr pkt;
965
    // Remember when we call receive4().
966
    ptime start_time = microsec_clock::universal_time();
967 968
    // Call receive with timeout of 2s + 300000us = 2.3s.
    ASSERT_NO_THROW(pkt = ifacemgr->receive4(2, 300000));
969
    // Remember when call to receive4() ended.
970
    ptime stop_time = microsec_clock::universal_time();
971 972 973 974
    // We did not send a packet to lo interface so we expect that
    // nothing has been received and timeout has been reached.
    ASSERT_FALSE(pkt);
    // Calculate duration of call to receive4().
975
    time_duration duration = stop_time - start_time;
976 977
    // We stop the clock when the call completes so it does not
    // precisely reflect the receive timeout. However the
Josh Soref's avatar
Josh Soref committed
978
    // uncertainty should be low enough to expect that measured
979
    // value is in the range <2.3s; 2.6s>.
980 981
    EXPECT_GE(duration.total_microseconds(),
              2300000 - TIMEOUT_TOLERANCE);
982
    EXPECT_LE(duration.total_microseconds(), 2600000);
983 984

    // Test timeout shorter than 1s.
985
    start_time = microsec_clock::universal_time();
986
    ASSERT_NO_THROW(pkt = ifacemgr->receive4(0, 400000));
987
    stop_time = microsec_clock::universal_time();
988
    ASSERT_FALSE(pkt);
989
    duration = stop_time - start_time;
990
    // Check if measured duration is within <0.4s; 0.7s>.
991 992
    EXPECT_GE(duration.total_microseconds(),
              400000 - TIMEOUT_TOLERANCE);
993
    EXPECT_LE(duration.total_microseconds(), 700000);
994 995

    // Test with invalid fractional timeout values.
996 997
    EXPECT_THROW(ifacemgr->receive4(0, 1000000), isc::BadValue);
    EXPECT_THROW(ifacemgr->receive4(2, 1000005), isc::BadValue);