📄 test_outputs.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_outputs.cc,v 1.34 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/ipv6.hh"#include "libxorp/ipnet.hh"#include "auth.hh"#include "output_table.hh"#include "output_updates.hh"#include "port.hh"#include "peer.hh"#include "packet_queue.hh"#include "route_db.hh"#include "system.hh"#include "update_queue.hh"#include "test_utils.hh"#ifdef HAVE_GETOPT_H#include <getopt.h>#endif/////////////////////////////////////////////////////////////////////////////////// This test comprises of a RIP system with 2 ports injecting routes. One of// the ports has an associated Output class instance that generates packets// containing the routes. We test both the update packets and the unsolicted// response packets.//// +--- System ----+// TestPort OtherPort// Routes ------> TestPeer OtherPeer <------ Routes// |// V// response packets (inspected)//// We look at the routes in the response packets and compare them against// what we'd expect to see against differing horizon policies.///////////////////////////////////////////////////////////////////////////////////// Generic Constants//static const char *program_name = "test_output_update";static const char *program_description = "Test RIP Port processing";static const char *program_version_id = "0.1";static const char *program_date = "August, 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";// ----------------------------------------------------------------------------// Type specific helperstemplate <typename A>struct DefaultPeer { static A get();};template <typename A>struct OtherPeer { static A get();};template <>IPv4 DefaultPeer<IPv4>::get() { return IPv4("10.0.0.1"); }template <>IPv4 OtherPeer<IPv4>::get() { return IPv4("192.168.0.1"); }template <>IPv6 DefaultPeer<IPv6>::get() { return IPv6("10::1"); }template <>IPv6 OtherPeer<IPv6>::get() { return IPv6("1920:1680::1"); }// ----------------------------------------------------------------------------// 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"); } ~SpoofPort() { // verbose_log("Destructing SpoofPort instance\n"); while (this->_peers.empty() == false) { delete this->_peers.front(); this->_peers.pop_front(); } }};// ----------------------------------------------------------------------------// BlockedPortIO//// This is a port IO class that reports it's always pending so packets// build up in the packet queue and never leave...template <typename A>class BlockedPortIO : public PortIOBase<A>{public: typedef A Addr; typedef PortIOUserBase<A> PortIOUser;public: BlockedPortIO(PortIOUserBase<A>& user) : PortIOBase<A>(user, "if0", "vif0", A(DefaultPeer<A>::get())) { } /** * Called by RIP Port instance. */ bool send(const Addr&, uint16_t, const vector<uint8_t>&) { XLOG_FATAL("Called send inappropriately"); return true; } bool pending() const { return true; }private:};// ----------------------------------------------------------------------------// 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())); this->_ports.push_back(new SpoofPort<A>(*this, OtherPeer<A>::get())); } ~SpoofPortManager() { while (!this->_ports.empty()) { delete this->_ports.front(); this->_ports.pop_front(); } } Port<A>* test_port() { return this->_ports.front(); } const Port<A>* test_port() const { return this->_ports.front(); } Port<A>* other_port() { return this->_ports.back(); } const Port<A>* other_port() const { return this->_ports.back(); } Peer<A>* test_peer() { return test_port()->peers().front(); } const Peer<A>* test_peer() const { return test_port()->peers().front(); } Peer<A>* other_peer() { return other_port()->peers().front(); } const Peer<A>* other_peer() const { return other_port()->peers().front(); }};// ----------------------------------------------------------------------------// Response Reader - Really needed for IPv6, but IPv4 is trivialtemplate <typename A>struct ResponseReader { ResponseReader(const RipPacket<A>* rp) : _rp(rp), _pe(0) { RipPacketHeader rph(_rp->header_ptr()); if (rph.command() != RipPacketHeader::RESPONSE) { verbose_log("Bad packet!\n"); _pe = ~0U; } } bool get(IPNet<A>& n, A& nh, uint32_t& cost, uint32_t& tag); uint32_t packet_entry() const { return _pe; }protected: const RipPacket<A>* _rp; uint32_t _pe; // Current packet entry A _nh6; // IPv6 only next hop};template <>boolResponseReader<IPv4>::get(IPNet<IPv4>& n, IPv4& nh, uint32_t& cost, uint32_t& tag){ const uint8_t* pre_ptr = _rp->route_entry_ptr(_pe); if (pre_ptr == NULL) return false; const PacketRouteEntry<IPv4> pre(pre_ptr); n = pre.net(); nh = pre.nexthop(); cost = pre.metric(); tag = pre.tag(); _pe++; return true;}template <>boolResponseReader<IPv6>::get(IPNet<IPv6>& n, IPv6& nh, uint32_t& cost, uint32_t& tag){ for (;;) { const uint8_t* pre_ptr = _rp->route_entry_ptr(_pe); if (pre_ptr == NULL) return false; const PacketRouteEntry<IPv6> pre(pre_ptr); if (pre.is_nexthop()) { _nh6 = pre.nexthop(); _pe++; continue; } nh = _nh6; n = pre.net(); cost = pre.metric(); tag = pre.tag(); _pe++; return true; }}//-----------------------------------------------------------------------------// Horizon checkerstemplate <typename A>class HorizonValidatorBase{public: HorizonValidatorBase(const set<IPNet<A> >& tpn, const set<IPNet<A> >& opn) : _total_routes_seen(0), _test_peer_routes_seen(0), _tpn(tpn), _opn(opn) {} virtual ~HorizonValidatorBase() {} /* Check an individual response packet is valid */ virtual bool valid_response(const RipPacket<A>* p) = 0; /* Final check responses valid */ virtual bool valid_in_sum() const = 0; uint32_t total_routes_seen() const { return _total_routes_seen; } uint32_t test_peer_routes_seen() const { return _test_peer_routes_seen; }protected: uint32_t _total_routes_seen; uint32_t _test_peer_routes_seen; const set<IPNet<A> >& _tpn; const set<IPNet<A> >& _opn;};template <typename A>class NoHorizonValidator : public HorizonValidatorBase<A> {public: NoHorizonValidator(const set<IPNet<A> >& tpn, const set<IPNet<A> >& opn) : HorizonValidatorBase<A>(tpn, opn) {} bool valid_response(const RipPacket<A>* p) { IPNet<A> n; A nh; uint32_t cost; uint32_t tag; ResponseReader<A> rr(p); while (rr.get(n, nh, cost, tag) == true) { this->_total_routes_seen++; if (this->_tpn.find(n) != this->_tpn.end()) { this->_test_peer_routes_seen++; } else if (this->_opn.find(n) != this->_opn.end()) { // No-op } else { // Not a test peer net and not an other peer net // ==> it's bogus verbose_log("Failed Processing entry %u / %u %s cost %u\n", XORP_UINT_CAST(rr.packet_entry()), XORP_UINT_CAST(p->max_entries()), n.str().c_str(), XORP_UINT_CAST(cost)); return false; } } return true; } bool valid_in_sum() const { if (this->test_peer_routes_seen() != this->_tpn.size()) { verbose_log("Test routes seen (%u) does not match expected (%u)\n", XORP_UINT_CAST(this->test_peer_routes_seen()), XORP_UINT_CAST(this->_tpn.size())); return false; } verbose_log("total routes seen %u, test peer routes seen = %u\n", XORP_UINT_CAST(this->total_routes_seen()), XORP_UINT_CAST(this->test_peer_routes_seen())); return this->test_peer_routes_seen() * 2 == this->total_routes_seen(); }};template <typename A>class SplitHorizonValidator : public HorizonValidatorBase<A> {public: SplitHorizonValidator(const set<IPNet<A> >& tpn, const set<IPNet<A> >& opn)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -