📄 xrl_port_manager.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/xrl_port_manager.cc,v 1.31 2008/07/23 05:11:37 pavlin Exp $"// #define DEBUG_LOGGING#include "libxorp/eventloop.hh"#include "libxorp/ipv4.hh"#include "libxorp/ipv6.hh"#include "libxorp/debug.h"#include "libxipc/xrl_router.hh"#include "libfeaclient/ifmgr_atoms.hh"#include "port.hh"#include "xrl_port_manager.hh"#include "xrl_port_io.hh"// ----------------------------------------------------------------------------// Utility methods/** * Query whether an address exists on given interface and vif path and all * items on path are enabled. */template <typename A>static booladdress_exists(const IfMgrIfTree& iftree, const string& ifname, const string& vifname, const A& addr){ debug_msg("Looking for %s/%s/%s\n", ifname.c_str(), vifname.c_str(), addr.str().c_str()); const IfMgrIfAtom* ia = iftree.find_interface(ifname); if (ia == NULL) return false; const IfMgrVifAtom* va = ia->find_vif(vifname); if (va == NULL) return false; const typename IfMgrIP<A>::Atom* aa = va->find_addr(addr); if (aa == NULL) return false; return true;}/** * Query whether an address exists on given interface and vif path and all * items on path are enabled. */template <typename A>static booladdress_enabled(const IfMgrIfTree& iftree, const string& ifname, const string& vifname, const A& addr){ debug_msg("Looking for %s/%s/%s\n", ifname.c_str(), vifname.c_str(), addr.str().c_str()); const IfMgrIfAtom* ia = iftree.find_interface(ifname); if (ia == 0 || ia->enabled() == false || ia->no_carrier()) { debug_msg("if %s exists ? %d ?\n", ifname.c_str(), (ia ? 1 : 0)); return false; } const IfMgrVifAtom* va = ia->find_vif(vifname); if (va == 0 || va->enabled() == false) { debug_msg("vif %s exists ? %d?\n", vifname.c_str(), (va ? 1: 0)); return false; } const typename IfMgrIP<A>::Atom* aa = va->find_addr(addr); if (aa == 0 || aa->enabled() == false) { debug_msg("addr %s exists ? %d?\n", addr.str().c_str(), (aa ? 1: 0)); return false; } debug_msg("Found\n"); return true;}/** * Unary function object to test whether a particular address is * associated with a RIP port. */template <typename A>struct port_has_address { port_has_address(const A& addr) : _addr(addr) {} bool operator() (const Port<A>* p) { const PortIOBase<A>* io = p->io_handler(); return io && io->address() == _addr; }private: A _addr;};/** * Unary function object to test whether a particular port's io * system is in a given state. */template <typename A>struct port_has_io_in_state { port_has_io_in_state(ServiceStatus st) : _st(st) {} bool operator() (const Port<A>* p) const { const PortIOBase<A>* io = p->io_handler(); const XrlPortIO<A>* xio = dynamic_cast<const XrlPortIO<A>*>(io); if (xio == 0) return false; return xio->status() == _st; }protected: ServiceStatus _st;};/** * Unary function object to test whether a particular RIP port is appropriate * for packet arriving on socket. * * NB At a future date we might want to track socket id to XrlPortIO * mappings. This would be more efficient. */template <typename A>struct is_port_for { is_port_for(const string* sockid, const string* ifname, const string* vifname, const A* addr, IfMgrXrlMirror* im) : _psid(sockid), _ifname(ifname), _vifname(vifname), _pa(addr), _pim(im) {} bool operator() (Port<A>*& p);protected: bool link_addr_valid() const;private: const string* _psid; const string* _ifname; const string* _vifname; const A* _pa; IfMgrXrlMirror* _pim;};template <>inline boolis_port_for<IPv4>::link_addr_valid() const{ return true;}template <>inline boolis_port_for<IPv6>::link_addr_valid() const{ return _pa->is_linklocal_unicast();}template <typename A>boolis_port_for<A>::operator() (Port<A>*& p){ // // Perform address family specific check for source address being // link-local. For IPv4 the concept does not exist, for IPv6 // check if origin is link local. // if (link_addr_valid() == false) { return false; } PortIOBase<A>* io = p->io_handler(); XrlPortIO<A>* xio = dynamic_cast<XrlPortIO<A>*>(io); if (xio == 0) return false; // If another socket, ignore if (xio->socket_id() != *_psid) return false; // If our packet, ignore if (xio->address() == *_pa) return false; // Check the incoming interface and vif name (if known) if ((! _ifname->empty()) && (! _vifname->empty())) { if (xio->ifname() != *_ifname) return false; if (xio->vifname() != *_vifname) return false; } // // Packet has arrived on multicast socket and is not one of ours. // // Check source address to find originating neighbour on local nets // or p2p link. // const typename IfMgrIP<A>::Atom* ifa; ifa = _pim->iftree().find_addr(xio->ifname(), xio->vifname(), xio->address()); if (ifa == 0) { return false; } if (ifa->has_endpoint()) { return ifa->endpoint_addr() == *_pa; } IPNet<A> n(ifa->addr(), ifa->prefix_len()); return n.contains(*_pa);}// ----------------------------------------------------------------------------// XrlPortManagertemplate <typename A>intXrlPortManager<A>::startup(){ set_status(SERVICE_STARTING); // Transition to SERVICE_RUNNING occurs when tree_complete() is called, ie // we have interface/vif/address state available. return (XORP_OK);}template <typename A>intXrlPortManager<A>::shutdown(){ set_status(SERVICE_SHUTTING_DOWN); typename PortManagerBase<A>::PortList& pl = this->ports(); typename PortManagerBase<A>::PortList::iterator i = pl.begin(); // XXX Walk ports and shut them down. Only when they are all // shutdown should we consider ourselves shutdown. debug_msg("XXX XrlPortManager<A>::shutdown (%p)\n", this); debug_msg("XXX n_ports = %u n_dead_ports %u\n", XORP_UINT_CAST(this->ports().size()), XORP_UINT_CAST(_dead_ports.size())); while (i != pl.end()) { Port<A>* p = *i; XrlPortIO<A>* xio = dynamic_cast<XrlPortIO<A>*>(p->io_handler()); if (xio) { _dead_ports.insert(make_pair(xio, p)); xio->shutdown(); pl.erase(i++); debug_msg(" XXX killing port %p\n", p); } else { i++; debug_msg(" XXX skipping port %p\n", p); } } return (XORP_OK);}template <typename A>voidXrlPortManager<A>::tree_complete(){ debug_msg("XrlPortManager<IPv%u>::tree_complete notification\n", XORP_UINT_CAST(A::ip_version())); set_status(SERVICE_RUNNING);}template <typename A>voidXrlPortManager<A>::updates_made(){ debug_msg("XrlPortManager<IPv%u>::updates_made notification\n", XORP_UINT_CAST(A::ip_version())); // Scan ports and enable/disable underlying I/O handler // according to fea state typename PortManagerBase<A>::PortList::iterator pi; for (pi = this->ports().begin(); pi != this->ports().end(); ++pi) { Port<A>* p = *pi; XrlPortIO<A>* xio = dynamic_cast<XrlPortIO<A>*>(p->io_handler()); if (xio == 0) continue; bool fea_en = address_enabled(_ifm.iftree(), xio->ifname(), xio->vifname(), xio->address()); if (fea_en != xio->enabled()) { XLOG_INFO("Detected iftree change on %s %s %s setting transport enabled %s", xio->ifname().c_str(), xio->vifname().c_str(), xio->address().str().c_str(), bool_c_str(fea_en)); xio->set_enabled(fea_en); } }}template <typename A>boolXrlPortManager<A>::add_rip_address(const string& ifname, const string& vifname, const A& addr){ if (status() != SERVICE_RUNNING) { debug_msg("add_rip_address failed: not running.\n"); return false; } // Check whether address exists, fail if not. const IfMgrIfTree& iftree = _ifm.iftree(); if (address_exists(iftree, ifname, vifname, addr) == false) { debug_msg("add_rip_address failed: address does not exist.\n"); return false; } // Check if port already exists typename PortManagerBase<A>::PortList::const_iterator pi; pi = find_if(this->ports().begin(), this->ports().end(), port_has_address<A>(addr)); if (pi != this->ports().end()) return true; // Create port Port<A>* p = new Port<A>(*this); this->ports().push_back(p); // Create XrlPortIO object for port XrlPortIO<A>* io = new XrlPortIO<A>(_xr, *p, ifname, vifname, addr); // Bind io to port p->set_io_handler(io, false); // Add self to observers of io objects status io->set_observer(this); // Start port's I/O handler if no others are starting up already try_start_next_io_handler(); return true;}template <typename A>boolXrlPortManager<A>::remove_rip_address(const string& /* ifname */, const string& /* vifname */, const A& addr){ typename PortManagerBase<A>::PortList& pl = this->ports(); typename PortManagerBase<A>::PortList::iterator i; i = find_if(pl.begin(), pl.end(), port_has_address<A>(addr)); if (i != pl.end()) { Port<A>* p = *i; XrlPortIO<A>* xio = dynamic_cast<XrlPortIO<A>*>(p->io_handler()); if (xio) { _dead_ports.insert(make_pair(xio, p)); xio->shutdown(); } pl.erase(i); } return true;}template <typename A>boolXrlPortManager<A>::deliver_packet(const string& sockid, const string& ifname, const string& vifname, const A& src_addr, uint16_t src_port, const vector<uint8_t>& pdata){ typename PortManagerBase<A>::PortList& pl = this->ports(); typename PortManagerBase<A>::PortList::iterator i; Port<A>* p = NULL; debug_msg("Packet on %s from interface %s vif %s %s/%u %u bytes\n", sockid.c_str(), ifname.c_str(), vifname.c_str(), src_addr.str().c_str(), src_port, XORP_UINT_CAST(pdata.size())); i = find_if(pl.begin(), pl.end(), is_port_for<A>(&sockid, &ifname, &vifname, &src_addr, &_ifm)); if (i == this->ports().end()) { debug_msg("Discarding packet %s/%u %u bytes\n", src_addr.str().c_str(), src_port, XORP_UINT_CAST(pdata.size())); return false; } p = *i; XLOG_ASSERT(find_if(++i, pl.end(), is_port_for<A>(&sockid, &ifname, &vifname, &src_addr, &_ifm)) == pl.end()); p->port_io_receive(src_addr, src_port, &pdata[0], pdata.size()); return true;}template <typename A>Port<A>*XrlPortManager<A>::find_port(const string& ifname, const string& vifname, const A& addr){ typename PortManagerBase<A>::PortList::iterator pi; pi = find_if(this->ports().begin(), this->ports().end(), port_has_address<A>(addr)); if (pi == this->ports().end()) { return 0; } Port<A>* port = *pi; PortIOBase<A>* port_io = port->io_handler(); if (port_io->ifname() != ifname || port_io->vifname() != vifname) { return 0; } return port;}template <typename A>const Port<A>*XrlPortManager<A>::find_port(const string& ifname, const string& vifname, const A& addr) const{ typename PortManagerBase<A>::PortList::const_iterator pi; pi = find_if(this->ports().begin(), this->ports().end(), port_has_address<A>(addr)); if (pi == this->ports().end()) { return 0; } const Port<A>* port = *pi; const PortIOBase<A>* port_io = port->io_handler(); if (port_io->ifname() != ifname || port_io->vifname() != vifname) { return 0; } return port;}template <typename A>boolXrlPortManager<A>::underlying_rip_address_up(const string& ifname, const string& vifname, const A& addr) const{ return address_enabled(_ifm.iftree(), ifname, vifname, addr);}template <typename A>boolXrlPortManager<A>::underlying_rip_address_exists(const string& ifname, const string& vifname, const A& addr) const{ return _ifm.iftree().find_addr(ifname, vifname, addr) != 0;}template <typename A>voidXrlPortManager<A>::status_change(ServiceBase* service, ServiceStatus /* old_status */, ServiceStatus new_status){ debug_msg("XXX %p status -> %s\n", service, service_status_name(new_status)); try_start_next_io_handler(); if (new_status != SERVICE_SHUTDOWN) return; typename map<ServiceBase*, Port<A>*>::iterator i; i = _dead_ports.find(service); XLOG_ASSERT(i != _dead_ports.end()); // delete i->second; // _dead_ports.erase(i);}template <typename A>XrlPortManager<A>::~XrlPortManager(){ _ifm.detach_hint_observer(this); while (_dead_ports.empty() == false) { Port<A>* p = _dead_ports.begin()->second; PortIOBase<A>* io = p->io_handler(); delete io; delete p; _dead_ports.erase(_dead_ports.begin()); }}template <typename A>voidXrlPortManager<A>::try_start_next_io_handler(){ typename PortManagerBase<A>::PortList::const_iterator cpi; cpi = find_if(this->ports().begin(), this->ports().end(), port_has_io_in_state<A>(SERVICE_STARTING)); if (cpi != this->ports().end()) { return; } typename PortManagerBase<A>::PortList::iterator pi = this->ports().begin(); XrlPortIO<A>* xio = 0; while (xio == 0) { pi = find_if(pi, this->ports().end(), port_has_io_in_state<A>(SERVICE_READY)); if (pi == this->ports().end()) { return; } Port<A>* p = (*pi); xio = dynamic_cast<XrlPortIO<A>*>(p->io_handler()); pi++; } xio->startup();}#ifdef INSTANTIATE_IPV4template class XrlPortManager<IPv4>;#endif#ifdef INSTANTIATE_IPV6template class XrlPortManager<IPv6>;#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -