📄 port.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/port.cc,v 1.73 2008/07/23 05:11:35 pavlin Exp $"#include "rip_module.h"#include "libxorp/xorp.h"#include "libxorp/debug.h"#include "libxorp/xlog.h"#include "libxorp/random.h"#include "libxorp/eventloop.hh"#include "libxorp/ipv4.hh"#include "libxorp/ipv6.hh"#include "constants.hh"#include "packets.hh"#include "auth.hh"#include "peer.hh"#include "port.hh"#include "port_manager.hh"#include "packet_assembly.hh"#include "packet_queue.hh"#include "system.hh"#include "output_table.hh"#include "output_updates.hh"// ----------------------------------------------------------------------------// Utilitiesinline static uint32_trange_random(uint32_t lo, uint32_t hi){ if (hi < lo) swap(hi, lo); return lo + ( xorp_random() % (hi - lo) );}// ----------------------------------------------------------------------------// Address Family specific Port methods#ifdef INSTANTIATE_IPV4PortAFSpecState<IPv4>::PortAFSpecState(){ set_auth_handler(new NullAuthHandler());}PortAFSpecState<IPv4>::~PortAFSpecState(){ delete auth_handler();}AuthHandlerBase*PortAFSpecState<IPv4>::set_auth_handler(AuthHandlerBase* new_handler){ AuthHandlerBase* old_handler = _ah; _ah = new_handler; return old_handler;}const AuthHandlerBase*PortAFSpecState<IPv4>::auth_handler() const{ return _ah;}AuthHandlerBase*PortAFSpecState<IPv4>::auth_handler(){ return _ah;}#endif // INSTANTIATE_IPV4// ----------------------------------------------------------------------------// Generic Port<A> Implementationtemplate <typename A>Port<A>::Port(PortManagerBase<A>& pm) : _pm(pm), _en(false), _cost(1), _horizon(SPLIT_POISON_REVERSE), _advertise(false), _adv_def_rt(true), _acc_def_rt(true), _passive(false), _acc_non_rip_reqs(true), _ur_out(0), _tu_out(0), _su_out(0){ _packet_queue = new PacketQueue<A>();}template <typename A>Port<A>::~Port(){ stop_output_processing(); delete _ur_out; delete _su_out; delete _tu_out; while (_peers.empty() == false) { delete _peers.front(); _peers.pop_front(); } delete _packet_queue;}template <typename A>Peer<A>*Port<A>::create_peer(const Addr& addr){ if (peer(addr) == 0) { Peer<A>* peer = new Peer<A>(*this, addr); _peers.push_back(peer); EventLoop& e = _pm.eventloop(); TimeVal now; e.current_time(now); peer->set_last_active(now); start_peer_gc_timer(); return peer; } return 0;}template <typename A>Peer<A>*Port<A>::peer(const Addr& addr){ typename PeerList::iterator i = find_if(_peers.begin(), _peers.end(), peer_has_address<A>(addr)); return (i == _peers.end()) ? 0 : *i;}template <typename A>const Peer<A>*Port<A>::peer(const Addr& addr) const{ typename PeerList::const_iterator i = find_if(_peers.begin(), _peers.end(), peer_has_address<A>(addr)); return (i == _peers.end()) ? 0 : *i;}template <typename A>voidPort<A>::unsolicited_response_timeout(){ debug_msg("Unsolicited response timeout %p\n", this); // // Fast forward triggered updater because we're about to dump entire // table. // if (_tu_out->running()) { _tu_out->ffwd(); } // // Check if unsolicited response process already exists and kill // it if so. // if (_ur_out->running()) { XLOG_WARNING("Starting unsolicited response process while an " "existing one is already running.\n"); _ur_out->stop(); } // Start output process. _ur_out->start(); // // Reschedule this callback in next interval // TimeVal interval = TimeVal(constants().update_interval(), 0); double factor = constants().update_jitter() / 100.0; _ur_timer.reschedule_after(random_uniform(interval, factor));}template <typename A>voidPort<A>::triggered_update_timeout(){ debug_msg("Triggered update timeout %p\n", this); { RouteDB<A>& rdb = _pm.system().route_db(); UNUSED(rdb); debug_msg("- Route DB routes = %u\n", XORP_UINT_CAST(rdb.route_count())); } // Table dump is running, we should not be doing triggered updates. if (_ur_out->running()) goto reschedule; // // Push triggered updater along. It wont be running if we've just // instantiated it, or if it was running and ran out of updates to // announce. // if (_tu_out->running() == false) { _tu_out->start(); } reschedule: TimeVal delay = TimeVal(constants().triggered_update_delay(), 0); double factor = constants().triggered_update_jitter() / 100.0; _tu_timer.reschedule_after(random_uniform(delay, factor));}template <typename A>voidPort<A>::start_output_processing(){ EventLoop& e = _pm.eventloop(); RouteDB<A>& rdb = _pm.system().route_db(); // Create triggered update output process _tu_out = new OutputUpdates<A>(e, *this, *_packet_queue, rdb); // Schedule triggered update process TimeVal interval = TimeVal(constants().update_interval(), 0); double factor = constants().update_jitter() / 100.0; _ur_timer = e.new_oneoff_after(random_uniform(interval, factor), callback(this, &Port<A>::unsolicited_response_timeout)); // Create unsolicited response (table dump) output process _ur_out = new OutputTable<A>(e, *this, *_packet_queue, rdb); // Schedule unsolicited output process TimeVal delay = TimeVal(constants().triggered_update_delay(), 0); factor = constants().triggered_update_jitter() / 100.0; _tu_timer = e.new_oneoff_after(random_uniform(delay, factor), callback(this, &Port<A>::triggered_update_timeout));}template <typename A>voidPort<A>::stop_output_processing(){ delete _ur_out; _ur_out = 0; delete _tu_out; _tu_out = 0; _ur_timer.unschedule(); _tu_timer.unschedule();}template <typename A>voidPort<A>::start_request_table_timer(){ EventLoop& e = _pm.eventloop(); if (constants().table_request_period_secs() == 0) { // Don't start the timer, but cancel it instead _rt_timer.unschedule(); return; } _rt_timer = e.new_periodic_ms( constants().table_request_period_secs() * 1000, callback(this, &Port<A>::request_table_timeout));}template <typename A>voidPort<A>::reschedule_request_table_timer(){ if (! _rt_timer.scheduled()) return; start_request_table_timer();}template <typename A>voidPort<A>::stop_request_table_timer(){ _rt_timer.unschedule();}template <typename A>boolPort<A>::request_table(){ RipPacket<A>* pkt = new RipPacket<A>(RIP_AF_CONSTANTS<A>::IP_GROUP(), RIP_AF_CONSTANTS<A>::IP_PORT); list<RipPacket<A>*> auth_packets; RequestTablePacketAssembler<A> rtpa(*this); if (rtpa.prepare(pkt, auth_packets) == true) { typename list<RipPacket<A>*>::iterator iter; for (iter = auth_packets.begin(); iter != auth_packets.end(); ++iter) { RipPacket<A>* auth_pkt = *iter; _packet_queue->enqueue_packet(auth_pkt); counters().incr_table_requests_sent(); } } else { XLOG_ERROR("Failed to assemble table request.\n"); } delete pkt; push_packets(); debug_msg("Sending Request.\n"); return true;}template <typename A>boolPort<A>::request_table_timeout(){ if (_peers.empty() == false) return false; return (request_table());}template <typename A>voidPort<A>::start_peer_gc_timer(){ XLOG_ASSERT(_peers.empty() == false); // Set peer garbage collection timeout to 180 seconds since for RIP // MIB we need to keep track of quiescent peers for this long. EventLoop& e = _pm.eventloop(); _gc_timer = e.new_periodic_ms(180 * 1000, callback(this, &Port<A>::peer_gc_timeout));}template <typename A>boolPort<A>::peer_gc_timeout(){ typename PeerList::iterator i = _peers.begin(); while (i != _peers.end()) { Peer<A>* pp = *i; if (pp->route_count() == 0) { delete pp; _peers.erase(i++); } else { ++i; } } if (_peers.empty()) { start_request_table_timer(); return false; } return true;}template <typename A>voidPort<A>::record_packet(Peer<A>* p){ counters().incr_packets_recv(); if (p) { EventLoop& e = _pm.eventloop(); TimeVal now; e.current_time(now); p->counters().incr_packets_recv(); p->set_last_active(now); }}template <typename A>voidPort<A>::record_response_packet(Peer<A>* p){ counters().incr_update_packets_recv(); if (p) { p->counters().incr_update_packets_recv(); }}template <typename A>voidPort<A>::record_request_packet(Peer<A>* p){ counters().incr_table_requests_recv(); if (p) { p->counters().incr_table_requests_recv(); }}template <typename A>voidPort<A>::record_bad_packet(const string& why, const Addr& host, uint16_t port, Peer<A>* p){ XLOG_INFO("RIP port %s/%s/%s received bad packet from %s:%u - %s\n", this->_pio->ifname().c_str(), this->_pio->vifname().c_str(), this->_pio->address().str().c_str(), host.str().c_str(), port, why.c_str()); counters().incr_bad_packets(); if (p) { p->counters().incr_bad_packets(); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -