// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*- // Copyright (c) 2001-2009 XORP, Inc. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, Version 2, June // 1991 as published by the Free Software Foundation. Redistribution // and/or modification of this program under the terms of any other // version of the GNU General Public License is not permitted. // // This program is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For more details, // see the GNU General Public License, Version 2, a copy of which can be // found in the XORP LICENSE.gpl file. // // XORP Inc, 2953 Bunker Hill Lane, Suite 204, Santa Clara, CA 95054, USA; // http://xorp.net // $XORP: xorp/fea/io_ip_manager.hh,v 1.16 2009/01/05 18:30:49 jtc Exp $ #ifndef __FEA_IO_IP_MANAGER_HH__ #define __FEA_IO_IP_MANAGER_HH__ #include <list> #include <vector> #include <set> #include <map> #include "libxorp/callback.hh" #include "libxorp/ipvx.hh" #include "libxorp/xorpfd.hh" #include "fea_io.hh" #include "io_ip.hh" class FeaDataPlaneManager; class FeaNode; class IoIpManager; /** * Structure used to store commonly passed IPv4 and IPv6 header information. */ struct IPvXHeaderInfo { string if_name; string vif_name; IPvX src_address; IPvX dst_address; uint8_t ip_protocol; int32_t ip_ttl; int32_t ip_tos; bool ip_router_alert; bool ip_internet_control; vector<uint8_t> ext_headers_type; vector<vector<uint8_t> > ext_headers_payload; }; /** * A class that handles raw IP I/O communication for a specific protocol. * * It also allows arbitrary filters to receive the raw IP data for that * protocol. */ class IoIpComm : public IoIpReceiver { public: /** * Filter class. */ class InputFilter { public: InputFilter(IoIpManager& io_ip_manager, const string& receiver_name, uint8_t ip_protocol) : _io_ip_manager(io_ip_manager), _receiver_name(receiver_name), _ip_protocol(ip_protocol) {} virtual ~InputFilter() {} /** * Get a reference to the I/O IP manager. * * @return a reference to the I/O IP manager. */ IoIpManager& io_ip_manager() { return (_io_ip_manager); } /** * Get a const reference to the I/O IP manager. * * @return a const reference to the I/O IP manager. */ const IoIpManager& io_ip_manager() const { return (_io_ip_manager); } /** * Get the receiver name. * * @return the receiver name. */ const string& receiver_name() const { return (_receiver_name); } /** * Get the IP protocol. * * @return the IP protocol. */ uint8_t ip_protocol() const { return (_ip_protocol); } /** * Method invoked when data arrives on associated IoIpComm instance. */ virtual void recv(const struct IPvXHeaderInfo& header, const vector<uint8_t>& payload) = 0; /** * Method invoked when a multicast forwarding related upcall is * received from the system. */ virtual void recv_system_multicast_upcall(const vector<uint8_t>& payload) = 0; /** * Method invoked by the destructor of the associated IoIpComm * instance. This method provides the InputFilter with the * opportunity to delete itself or update its state. * The input filter does not need to call IoIpComm::remove_filter() * since filter removal is automatically conducted. */ virtual void bye() = 0; private: IoIpManager& _io_ip_manager; string _receiver_name; uint8_t _ip_protocol; }; /** * Joined multicast group class. */ class JoinedMulticastGroup { public: JoinedMulticastGroup(const string& if_name, const string& vif_name, const IPvX& group_address) : _if_name(if_name), _vif_name(vif_name), _group_address(group_address) {} virtual ~JoinedMulticastGroup() {} const string& if_name() const { return _if_name; } const string& vif_name() const { return _vif_name; } const IPvX& group_address() const { return _group_address; } /** * Less-Than Operator * * @param other the right-hand operand to compare against. * @return true if the left-hand operand is numerically smaller * than the right-hand operand. */ bool operator<(const JoinedMulticastGroup& other) const { if (_if_name != other._if_name) return (_if_name < other._if_name); if (_vif_name != other._vif_name) return (_vif_name < other._vif_name); return (_group_address < other._group_address); } /** * Equality Operator * * @param other the right-hand operand to compare against. * @return true if the left-hand operand is numerically same as the * right-hand operand. */ bool operator==(const JoinedMulticastGroup& other) const { return ((_if_name == other._if_name) && (_vif_name == other._vif_name) && (_group_address == other._group_address)); } /** * Add a receiver. * * @param receiver_name the name of the receiver to add. */ void add_receiver(const string& receiver_name) { _receivers.insert(receiver_name); } /** * Delete a receiver. * * @param receiver_name the name of the receiver to delete. */ void delete_receiver(const string& receiver_name) { _receivers.erase(receiver_name); } /** * @return true if there are no receivers associated with this group. */ bool empty() const { return _receivers.empty(); } private: string _if_name; string _vif_name; IPvX _group_address; set<string> _receivers; }; public: /** * Constructor for IoIpComm. * * @param io_ip_manager the corresponding I/O IP manager * (@ref IoIpManager). * @param iftree the interface tree to use. * @param family the address family (AF_INET or AF_INET6 for IPv4 and IPv6 * respectively). * @param ip_protocol the IP protocol number (IPPROTO_*). */ IoIpComm(IoIpManager& io_ip_manager, const IfTree& iftree, int family, uint8_t ip_protocol); /** * Virtual destructor. */ virtual ~IoIpComm(); /** * Allocate the I/O IP plugins (one per data plane manager). */ void allocate_io_ip_plugins(); /** * Deallocate the I/O IP plugins (one per data plane manager). */ void deallocate_io_ip_plugins(); /** * Allocate an I/O IP plugin for a given data plane manager. * * @param fea_data_plane_manager the data plane manager. */ void allocate_io_ip_plugin(FeaDataPlaneManager* fea_data_plane_manager); /** * Deallocate the I/O IP plugin for a given data plane manager. * * @param fea_data_plane_manager the data plane manager. */ void deallocate_io_ip_plugin(FeaDataPlaneManager* fea_data_plane_manager); /** * Start all I/O IP plugins. */ void start_io_ip_plugins(); /** * Stop all I/O IP plugins. */ void stop_io_ip_plugins(); /** * Add a filter to list of input filters. * * The IoIpComm class assumes that the callee will be responsible for * managing the memory associated with the filter and will call * remove_filter() if the filter is deleted or goes out of scope. * * @param filter the filter to add. * @return XORP_OK on success, otherwise XORP_ERROR. */ int add_filter(InputFilter* filter); /** * Remove filter from list of input filters. * * @param filter the filter to remove. * @return XORP_OK on success, otherwise XORP_ERROR. */ int remove_filter(InputFilter* filter); /** * @return true if there are no filters associated with this instance. */ bool no_input_filters() const { return _input_filters.empty(); } /** * Send a raw IP packet. * * @param if_name the interface to send the packet on. It is essential for * multicast. In the unicast case this field may be empty. * @param vif_name the vif to send the packet on. It is essential for * multicast. In the unicast case this field may be empty. * @param src_address the IP source address. * @param dst_address the IP destination address. * @param ip_ttl the IP TTL (hop-limit). If it has a negative value, * the TTL will be set internally before transmission. * @param ip_tos the Type Of Service (IP traffic class for IPv6). * If it has a negative value, the TOS will be * set internally before transmission. * @param ip_router_alert if true, then add the IP Router Alert option to * the IP packet. * @param ip_internet_control if true, then this is IP control traffic. * @param ext_headers_type a vector of integers with the types of the * optional IPv6 extention headers. * @param ext_headers_payload a vector of payload data, one for each * optional IPv6 extention header. The number of entries must match * ext_headers_type. * @param payload the payload, everything after the IP header and options. * @param error_msg the error message (if error). * @return XORP_OK on success, otherwise XORP_ERROR. */ int send_packet(const string& if_name, const string& vif_name, const IPvX& src_address, const IPvX& dst_address, int32_t ip_ttl, int32_t ip_tos, bool ip_router_alert, bool ip_internet_control, const vector<uint8_t>& ext_headers_type, const vector<vector<uint8_t> >& ext_headers_payload, const vector<uint8_t>& payload, string& error_msg); /** * Received a raw IP packet. * * @param if_name the interface name the packet arrived on. * @param vif_name the vif name the packet arrived on. * @param src_address the IP source address. * @param dst_address the IP destination address. * @param ip_ttl the IP TTL (hop-limit). If it has a negative value, * then the received value is unknown. * @param ip_tos The type of service (Diffserv/ECN bits for IPv4). If it * has a negative value, then the received value is unknown. * @param ip_router_alert if true, the IP Router Alert option was * included in the IP packet. * @param ip_internet_control if true, then this is IP control traffic. * @param ext_headers_type a vector of integers with the types of the * optional IPv6 extention headers. * @param ext_headers_payload a vector of payload data, one for each * optional IPv6 extention header. The number of entries must match * ext_headers_type. * @param packet the payload, everything after the IP header and * options. */ virtual void recv_packet(const string& if_name, const string& vif_name, const IPvX& src_address, const IPvX& dst_address, int32_t ip_ttl, int32_t ip_tos, bool ip_router_alert, bool ip_internet_control, const vector<uint8_t>& ext_headers_type, const vector<vector<uint8_t> >& ext_headers_payload, const vector<uint8_t>& payload); /** * Received a multicast forwarding related upcall from the system. * * Examples of such upcalls are: "nocache", "wrongiif", "wholepkt", * "bw_upcall". * * @param payload the payload data for the upcall. */ virtual void recv_system_multicast_upcall(const vector<uint8_t>& payload); /** * Join an IP multicast group. * * @param if_name the interface through which packets should be accepted. * @param vif_name the vif through which packets should be accepted. * @param group_address the multicast group address to join. * @param receiver_name the name of the receiver. * @param error_msg the error message (if error). * @return XORP_OK on success, otherwise XORP_ERROR. */ int join_multicast_group(const string& if_name, const string& vif_name, const IPvX& group_address, const string& receiver_name, string& error_msg); /** * Leave an IP multicast group. * * @param if_name the interface through which packets should not be * accepted. * @param vif_name the vif through which packets should not be accepted. * @param group_address the multicast group address to leave. * @param receiver_name the name of the receiver. * @param error_msg the error message (if error). * @return XORP_OK on success, otherwise XORP_ERROR. */ int leave_multicast_group(const string& if_name, const string& vif_name, const IPvX& group_address, const string& receiver_name, string& error_msg); /** * Get the IP protocol. * * @return the IP protocol. */ uint8_t ip_protocol() const { return (_ip_protocol); } /** * Get the first valid file descriptor for receiving protocol messages. * * @return the first valid file descriptor for receiving protocol * messages. */ XorpFd first_valid_protocol_fd_in(); private: IoIpComm(const IoIpComm&); // Not implemented. IoIpComm& operator=(const IoIpComm&); // Not implemented. IoIpManager& _io_ip_manager; const IfTree& _iftree; const int _family; const uint8_t _ip_protocol; typedef list<pair<FeaDataPlaneManager*, IoIp*> >IoIpPlugins; IoIpPlugins _io_ip_plugins; list<InputFilter*> _input_filters; typedef map<JoinedMulticastGroup, JoinedMulticastGroup> JoinedGroupsTable; JoinedGroupsTable _joined_groups_table; }; /** * @short Class that implements the API for sending IP packet to a * receiver. */ class IoIpManagerReceiver { public: /** * Virtual destructor. */ virtual ~IoIpManagerReceiver() {} /** * Data received event. * * @param receiver_name the name of the receiver to send the * IP packet to. * @param header the IP header information. * @param payload the payload, everything after the IP header * and options. */ virtual void recv_event(const string& receiver_name, const struct IPvXHeaderInfo& header, const vector<uint8_t>& payload) = 0; }; /** * @short A class that manages raw IP I/O. * * The IoIpManager has two containers: a container for IP protocol handlers * (@ref IoIpComm) indexed by the protocol associated with the handler, and * a container for the filters associated with each receiver_name. When * a receiver registers for interest in a particular type of raw * packet a handler (@ref IoIpComm) is created if necessary, then the * relevent filter is created and associated with the IoIpComm. */ class IoIpManager : public IoIpManagerReceiver, public InstanceWatcher { public: typedef XorpCallback2<int, const uint8_t*, size_t>::RefPtr UpcallReceiverCb; /** * Constructor for IoIpManager. */ IoIpManager(FeaNode& fea_node, const IfTree& iftree); /** * Virtual destructor. */ virtual ~IoIpManager(); /** * Send a raw IP packet. * * @param if_name the interface to send the packet on. It is essential for * multicast. In the unicast case this field may be empty. * @param vif_name the vif to send the packet on. It is essential for * multicast. In the unicast case this field may be empty. * @param src_address the IP source address. * @param dst_address the IP destination address. * @param ip_protocol the IP protocol number. It must be between 1 and * 255. * @param ip_ttl the IP TTL (hop-limit). If it has a negative value, the * TTL will be set internally before transmission. * @param ip_tos the Type Of Service (IP traffic class for IPv6). If it * has a negative value, the TOS will be set internally before * transmission. * @param ip_router_alert if true, then add the IP Router Alert option to * the IP packet. * @param ip_internet_control if true, then this is IP control traffic. * @param ext_headers_type a vector of integers with the types of the * optional IPv6 extention headers. * @param ext_headers_payload a vector of payload data, one for each * optional IPv6 extention header. The number of entries must match * ext_headers_type. * @param payload the payload, everything after the IP header and options. * @param error_msg the error message (if error). * @return XORP_OK on success, otherwise XORP_ERROR. */ int send(const string& if_name, const string& vif_name, const IPvX& src_address, const IPvX& dst_address, uint8_t ip_protocol, int32_t ip_ttl, int32_t ip_tos, bool ip_router_alert, bool ip_internet_control, const vector<uint8_t>& ext_headers_type, const vector<vector<uint8_t> >& ext_headers_payload, const vector<uint8_t>& payload, string& error_msg); /** * Register to receive IP packets. * * @param family the address family (AF_INET or AF_INET6 for * IPv4 and IPv6 respectively). * @param receiver_name the name of the receiver. * @param if_name the interface through which packets should be accepted. * @param vif_name the vif through which packets should be accepted. * @param ip_protocol the IP protocol number that the receiver is * interested in. It must be between 0 and 255. A protocol number of 0 is * used to specify all protocols. * @param enable_multicast_loopback if true then enable delivering of * multicast datagrams back to this host (assuming the host is a member of * the same multicast group. * @param error_msg the error message (if error). * @return XORP_OK on success, otherwise XORP_ERROR. */ int register_receiver(int family, const string& receiver_name, const string& if_name, const string& vif_name, uint8_t ip_protocol, bool enable_multicast_loopback, string& error_msg); /** * Unregister to receive IP packets. * * @param family the address family (AF_INET or AF_INET6 for * IPv4 and IPv6 respectively). * @param receiver_name the name of the receiver. * @param if_name the interface through which packets should not be * accepted. * @param vif_name the vif through which packets should not be accepted. * @param ip_protocol the IP Protocol number that the receiver is not * interested in anymore. It must be between 0 and 255. A protocol number * of 0 is used to specify all protocols. * @param error_msg the error message (if error). * @return XORP_OK on success, otherwise XORP_ERROR. */ int unregister_receiver(int family, const string& receiver_name, const string& if_name, const string& vif_name, uint8_t ip_protocol, string& error_msg); /** * Join an IP multicast group. * * @param receiver_name the name of the receiver. * @param if_name the interface through which packets should be accepted. * @param vif_name the vif through which packets should be accepted. * @param ip_protocol the IP protocol number that the receiver is * interested in. It must be between 0 and 255. A protocol number of 0 is * used to specify all protocols. * @param group_address the multicast group address to join. * @param error_msg the error message (if error). * @return XORP_OK on success, otherwise XORP_ERROR. */ int join_multicast_group(const string& receiver_name, const string& if_name, const string& vif_name, uint8_t ip_protocol, const IPvX& group_address, string& error_msg); /** * Leave an IP multicast group. * * @param receiver_name the name of the receiver. * @param if_name the interface through which packets should not be * accepted. * @param vif_name the vif through which packets should not be accepted. * @param ip_protocol the IP protocol number that the receiver is not * interested in anymore. It must be between 0 and 255. A protocol number * of 0 is used to specify all protocols. * @param group_address the multicast group address to leave. * @param error_msg the error message (if error). * @return XORP_OK on success, otherwise XORP_ERROR. */ int leave_multicast_group(const string& receiver_name, const string& if_name, const string& vif_name, uint8_t ip_protocol, const IPvX& group_address, string& error_msg); /** * Register to receive multicast forwarding related upcalls from the * system. * * @param family the address family (AF_INET or AF_INET6 for * IPv4 and IPv6 respectively). * @param ip_protocol the IP protocol number that the receiver is * interested in. It must be between 0 and 255. A protocol number of 0 is * used to specify all protocols. * @param receiver_cb the receiver callback to be invoked when an * upcall is received. * @param receiver_fd the return-by-reference file descriptor for * the socket that receives the upcalls. * @param error_msg the error message (if error). * @return XORP_OK on success, otherwise XORP_ERROR. */ int register_system_multicast_upcall_receiver(int family, uint8_t ip_protocol, IoIpManager::UpcallReceiverCb receiver_cb, XorpFd& receiver_fd, string& error_msg); /** * Unregister to receive multicast forwarding related upcalls from the * system. * * @param family the address family (AF_INET or AF_INET6 for * IPv4 and IPv6 respectively). * @param ip_protocol the IP Protocol number that the receiver is not * interested in anymore. It must be between 0 and 255. A protocol number * of 0 is used to specify all protocols. * @param error_msg the error message (if error). * @return XORP_OK on success, otherwise XORP_ERROR. */ int unregister_system_multicast_upcall_receiver(int family, uint8_t ip_protocol, string& error_msg); /** * Data received event. * * @param receiver_name the name of the receiver to send the IP packet to. * @param header the IP header information. * @param payload the payload, everything after the IP header and options. */ void recv_event(const string& receiver_name, const struct IPvXHeaderInfo& header, const vector<uint8_t>& payload); /** * Inform the watcher that a component instance is alive. * * @param instance_name the name of the instance that is alive. */ void instance_birth(const string& instance_name); /** * Inform the watcher that a component instance is dead. * * @param instance_name the name of the instance that is dead. */ void instance_death(const string& instance_name); /** * Set the instance that is responsible for sending IP packets * to a receiver. */ void set_io_ip_manager_receiver(IoIpManagerReceiver* v) { _io_ip_manager_receiver = v; } /** * Get a reference to the interface tree. * * @return a reference to the interface tree (@ref IfTree). */ const IfTree& iftree() const { return _iftree; } /** * Register @ref FeaDataPlaneManager data plane manager. * * @param fea_data_plane_manager the data plane manager to register. * @param is_exclusive if true, the manager is registered as the * exclusive manager, otherwise is added to the list of managers. * @return XORP_OK on success, otherwise XORP_ERROR. */ int register_data_plane_manager(FeaDataPlaneManager* fea_data_plane_manager, bool is_exclusive); /** * Unregister @ref FeaDataPlaneManager data plane manager. * * @param fea_data_plane_manager the data plane manager to unregister. * @return XORP_OK on success, otherwise XORP_ERROR. */ int unregister_data_plane_manager(FeaDataPlaneManager* fea_data_plane_manager); /** * Get the list of registered data plane managers. * * @return the list of registered data plane managers. */ list<FeaDataPlaneManager*>& fea_data_plane_managers() { return _fea_data_plane_managers; } private: typedef map<uint8_t, IoIpComm*> CommTable; typedef multimap<string, IoIpComm::InputFilter*> FilterBag; /** * Get the CommTable for an address family. * * @param family the address family. * @return a reference to the CommTable for the address family. */ CommTable& comm_table_by_family(int family); /** * Get the FilterBag for an address family. * * @param family the address family. * @return a reference to the FilterBag for the address family. */ FilterBag& filters_by_family(int family); /** * Erase filters for a given receiver name. * * @param family the address family. * @param receiver_name the name of the receiver. */ void erase_filters_by_receiver_name(int family, const string& receiver_name); /** * Test whether there is a filter for a given receiver name. * * @param receiver_name the name of the receiver. * @return true if there is a filter for the given receiver name, * otherwise false. */ bool has_filter_by_receiver_name(const string& receiver_name) const; /** * Erase filters for a given CommTable and FilterBag. * * @param comm_table the associated CommTable. * @param filters the associated FilterBag. * @param begin the begin iterator to the FilterBag for the set of * filters to erase. * @param end the end iterator to the FilterBag for the set of filters * to erase. */ void erase_filters(CommTable& comm_table, FilterBag& filters, const FilterBag::iterator& begin, const FilterBag::iterator& end); FeaNode& _fea_node; EventLoop& _eventloop; const IfTree& _iftree; // Collection of IP communication handlers keyed by protocol. CommTable _comm_table4; CommTable _comm_table6; // Collection of input filters created by IoIpManager FilterBag _filters4; FilterBag _filters6; IoIpManagerReceiver* _io_ip_manager_receiver; list<FeaDataPlaneManager*> _fea_data_plane_managers; }; #endif // __FEA_IO_IP_MANAGER_HH__