📄 test_request.cc
字号:
// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*-// Copyright (c) 2001-2008 XORP, Inc.//// Permission is hereby granted, free of charge, to any person obtaining a// copy of this software and associated documentation files (the "Software")// to deal in the Software without restriction, subject to the conditions// listed in the XORP LICENSE file. These conditions include: you must// preserve this copyright notice, and you cannot mention the copyright// holders in advertising related to the Software without their permission.// The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This// notice is a summary of the XORP LICENSE file; the license in that file is// legally binding.#ident "$XORP: xorp/rip/test_request.cc,v 1.30 2008/07/23 05:11:37 pavlin Exp $"#include <set>#include "rip_module.h"#include "libxorp/xlog.h"#include "libxorp/c_format.hh"#include "libxorp/eventloop.hh"#include "libxorp/ipv4.hh"#include "libxorp/ipv4net.hh"#include "auth.hh"#include "port.hh"#include "peer.hh"#include "route_db.hh"#include "system.hh"#include "test_utils.hh"#ifdef HAVE_GETOPT_H#include <getopt.h>#endif/////////////////////////////////////////////////////////////////////////////////// Constants//static const char *program_name = "test_request";static const char *program_description = "Test RIP handling route requests";static const char *program_version_id = "0.1";static const char *program_date = "July, 2003";static const char *program_copyright = "See file LICENSE";static const char *program_return_value = "0 on success, 1 if test error, 2 if internal error";// ----------------------------------------------------------------------------// Spoof Port that supports just a single Peer//template <typename A>class SpoofPort : public Port<A> {public: SpoofPort(PortManagerBase<A>& pm, A addr) : Port<A>(pm) { this->_peers.push_back(new Peer<A>(*this, addr)); verbose_log("Constructing SpoofPort instance\n"); this->set_enabled(true); } ~SpoofPort() { verbose_log("Destructing SpoofPort instance\n"); while (this->_peers.empty() == false) { delete this->_peers.front(); this->_peers.pop_front(); } }};// ----------------------------------------------------------------------------// Type specific helperstemplate <typename A>struct DefaultPeer { static A get();};template <>IPv4 DefaultPeer<IPv4>::get() { return IPv4("10.0.0.1"); }template <>IPv6 DefaultPeer<IPv6>::get() { return IPv6("10::1"); }// ----------------------------------------------------------------------------// Spoof Port Manager instance support a single Spoof Port which in turn// contains a single Peer.//template <typename A>class SpoofPortManager : public PortManagerBase<A> {public: SpoofPortManager(System<A>& s, const IfMgrIfTree& iftree) : PortManagerBase<A>(s, iftree) { this->_ports.push_back(new SpoofPort<A>(*this, DefaultPeer<A>::get())); } ~SpoofPortManager() { while (!this->_ports.empty()) { delete this->_ports.front(); this->_ports.pop_front(); } } Port<A>* the_port() { XLOG_ASSERT(this->_ports.size() == 1); return this->_ports.front(); } Peer<A>* the_peer() { XLOG_ASSERT(this->_ports.size() == 1); XLOG_ASSERT(this->_ports.front()->peers().size() == 1); return this->_ports.front()->peers().front(); }};// ----------------------------------------------------------------------------// Test PortIO classtemplate <typename A>class SpoofPortIO : public PortIOBase<A>{public: typedef A Addr; typedef PortIOUserBase<A> PortIOUser;public: SpoofPortIO(PortIOUserBase<A>& user) : PortIOBase<A>(user, "if0", "vif0", IPv4("10.0.0.1")) { last_rip_send_flush(); } /** * Called by RIP Port instance. */ bool send(const Addr& addr, uint16_t port, const vector<uint8_t>& rip_packet) { _lo_addr = addr; _lo_port = port; _lo_data = rip_packet; _pending = true; return true; } bool pending() const { return _lo_port != 0; } const Addr& last_rip_send_addr() const { return _lo_addr; } uint16_t last_rip_send_port() const { return _lo_port; } const vector<uint8_t>& last_rip_send_data() const { return _lo_data; } void last_rip_send_flush() { _lo_addr = A::ZERO(); _lo_port = 0; _lo_data.resize(0); _pending = false; }private: vector<uint8_t> _lo_data; Addr _lo_addr; uint16_t _lo_port; bool _pending;};static const IPv4 REQUESTING_HOST = IPv4("10.0.100.1");static const uint16_t REQUESTING_PORT = 1092;static const uint8_t ROUTE_COST = 5;static const IfMgrIfTree ift_dummy = IfMgrIfTree();class RequestPacketTester {public: static const uint32_t INJECTED_ROUTES = 10; static const uint32_t REQUESTED_ROUTES = 25;public: RequestPacketTester() : _e(), _rip_system(_e), _pm(_rip_system, ift_dummy) { _portio = new SpoofPortIO<IPv4>(*_pm.the_port()); _pm.the_port()->set_io_handler(_portio, false); _portio->set_enabled(true); } ~RequestPacketTester() { _portio->set_enabled(false); delete _portio; RouteDB<IPv4>& rdb = _rip_system.route_db(); rdb.flush_routes(); } bool init_nets() { string ifname, vifname; // XXX: not set, because not needed RouteDB<IPv4>& rdb = _rip_system.route_db(); make_nets(_testnets, REQUESTED_ROUTES); set<IPv4Net>::const_iterator n = _testnets.begin(); for (uint32_t i = 0; i < INJECTED_ROUTES; i++) { if (rdb.update_route(*n, IPv4::ZERO(), ifname, vifname, ROUTE_COST, 0, _pm.the_peer(), PolicyTags(), false) == false) { verbose_log("Failed to add route for %s\n", n->str().c_str()); return false; } n++; } return true; } bool send_rip_route_queries() { vector<uint8_t> buf; buf.resize(RipPacketHeader::SIZE + REQUESTED_ROUTES * PacketRouteEntry<IPv4>::size()); RipPacketHeaderWriter rph(&buf[0]); rph.initialize(RipPacketHeader::REQUEST, 2); set<IPv4Net>::const_iterator n = _testnets.begin(); for (uint32_t i = 0; i < REQUESTED_ROUTES; i++) { XLOG_ASSERT(n != _testnets.end()); uint32_t offset = RipPacketHeader::SIZE + i * PacketRouteEntry<IPv4>::size(); PacketRouteEntryWriter<IPv4> pre(&(buf[offset])); pre.initialize(0, *n, IPv4::ZERO(), 0); n++; } XLOG_ASSERT(_pm.the_port() != 0); _pm.the_port()->port_io_receive(REQUESTING_HOST, REQUESTING_PORT, &(buf[0]), buf.size()); return true; } bool check_response() { if (_portio->pending() == false) { verbose_log("No response packet sent by rip\n"); return false; } if (_portio->last_rip_send_addr() != REQUESTING_HOST) { verbose_log("Response was not sent to originator\n"); return false; } if (_portio->last_rip_send_port() != REQUESTING_PORT) { verbose_log("Response was not sent to originators port\n"); return false; } const vector<uint8_t> buf = _portio->last_rip_send_data(); // Validate RIP packet header const RipPacketHeader rph(&buf[0]); if (rph.valid_command() == false) { verbose_log("Invalid command\n"); return false; } if (rph.valid_version(RipPacketHeader::IPv4_VERSION) == false) { verbose_log("Invalid version\n"); return false; } if (rph.valid_padding() == false) { verbose_log("Invalid padding\n"); return false; } if (rph.command() != RipPacketHeader::RESPONSE) { verbose_log("Not a response packet\n"); return false; } // Validate entries const uint8_t* pre_ptr = &buf[0] + RipPacketHeader::size(); uint32_t n_entries = buf.size() / PacketRouteEntry<IPv4>::size() - 1; if (n_entries > _testnets.size()) { verbose_log("Got more routes than requested (%u > %u).\n", XORP_UINT_CAST(n_entries), XORP_UINT_CAST(_testnets.size())); return false; } set<IPv4Net>::const_iterator ni = _testnets.begin(); for (uint32_t i = 0; i < n_entries; i++, pre_ptr += PacketRouteEntry<IPv4>::size()) { const PacketRouteEntry<IPv4> pre(pre_ptr); verbose_log("%s %s %u %u\n", pre.net().str().c_str(), pre.nexthop().str().c_str(), XORP_UINT_CAST(pre.metric()), pre.tag()); if (pre.addr_family() != PacketRouteEntry<IPv4>::ADDR_FAMILY) { verbose_log("Invalid address family in route entry %u\n", XORP_UINT_CAST(i)); return false; } if (*ni != pre.net()) { verbose_log("Mismatched net in route entry %u\n", XORP_UINT_CAST(i)); return false; } if (i < INJECTED_ROUTES) { if (pre.metric() != ROUTE_COST) { verbose_log("Metric changed.\n"); return false; } } else { if (pre.metric() != RIP_INFINITY) { verbose_log("Non-existant route with finite metric??\n"); } } ni++; } return true; } int run_test() { if (init_nets() == false) { return -1; } bool start_test = false; XorpTimer d = _e.set_flag_after_ms(1 * 1000, &start_test); while (start_test == false) { _e.run(); } if (send_rip_route_queries() == false) { return -1; } if (check_response() == false) { return -1; } return 0; }protected: EventLoop _e; System<IPv4> _rip_system; SpoofPortManager<IPv4> _pm; SpoofPortIO<IPv4>* _portio; set<IPv4Net> _testnets;};/** * Print program info to output stream. * * @param stream the output stream the print the program info to. */static voidprint_program_info(FILE *stream){ fprintf(stream, "Name: %s\n", program_name); fprintf(stream, "Description: %s\n", program_description); fprintf(stream, "Version: %s\n", program_version_id); fprintf(stream, "Date: %s\n", program_date); fprintf(stream, "Copyright: %s\n", program_copyright); fprintf(stream, "Return: %s\n", program_return_value);}/* * Print program usage information to the stderr. * * @param progname the name of the program. */static voidusage(const char* progname){ print_program_info(stderr); fprintf(stderr, "usage: %s [-v] [-h]\n", progname); fprintf(stderr, " -h : usage (this message)\n"); fprintf(stderr, " -v : verbose output\n");}intmain(int argc, char* const argv[]){ // // Initialize and start xlog // xlog_init(argv[0], NULL); xlog_set_verbose(XLOG_VERBOSE_LOW); // Least verbose messages // XXX: verbosity of the error messages temporary increased xlog_level_set_verbose(XLOG_LEVEL_ERROR, XLOG_VERBOSE_HIGH); xlog_add_default_output(); xlog_start(); int ch; while ((ch = getopt(argc, argv, "hv")) != -1) { switch (ch) { case 'v': set_verbose(true); break; case 'h': case '?': default: usage(argv[0]); xlog_stop(); xlog_exit(); if (ch == 'h') return (0); else return (1); } } argc -= optind; argv += optind; int rval = 0; XorpUnexpectedHandler x(xorp_unexpected_handler); try { RequestPacketTester rpt; rval = rpt.run_test(); } catch (...) { // Internal error xorp_print_standard_exceptions(); rval = 2; } // // Gracefully stop and exit xlog // xlog_stop(); xlog_exit(); return rval;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -