Source: ../../fea/netlink_socket.hh
|
|
|
|
// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*-
// Copyright (c) 2001-2007 International Computer Science Institute
//
// 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.
// $XORP: xorp/fea/netlink_socket.hh,v 1.22 2007/02/16 22:45:47 pavlin Exp $
#ifndef __FEA_NETLINK_SOCKET_HH__
#define __FEA_NETLINK_SOCKET_HH__
#include <list>
#include "libxorp/eventloop.hh"
#include "libxorp/exceptions.hh"
class NetlinkSocketObserver;
struct NetlinkSocketPlumber;
/**
* NetlinkSocket class opens a netlink socket and forwards data arriving
* on the socket to NetlinkSocketObservers. The NetlinkSocket hooks itself
* into the EventLoop and activity usually happens asynchronously.
*/
class NetlinkSocket {
public:
NetlinkSocket(EventLoop& eventloop);
~NetlinkSocket();
/**
* Start the netlink socket operation.
*
* @param error_msg the error message (if error).
* @return XORP_OK on success, otherwise XORP_ERROR.
*/
int start(string& error_msg);
/**
* Stop the netlink socket operation.
*
* @param error_msg the error message (if error).
* @return XORP_OK on success, otherwise XORP_ERROR.
*/
int stop(string& error_msg);
/**
* Test if the netlink socket is open.
*
* This method is needed because NetlinkSocket may fail to open
* netlink socket during startup.
*
* @return true if the netlink socket is open, otherwise false.
*/
inline bool is_open() const { return _fd >= 0; }
/**
* Write data to netlink socket.
*
* This method also updates the sequence number associated with
* this netlink socket.
*
* @return the number of bytes which were written, or -1 if error.
*/
ssize_t write(const void* data, size_t nbytes);
/**
* Sendto data on netlink socket.
*
* This method also updates the sequence number associated with
* this netlink socket.
*
* @return the number of bytes which were written, or -1 if error.
*/
ssize_t sendto(const void* data, size_t nbytes, int flags,
const struct sockaddr* to, socklen_t tolen);
/**
* Get the sequence number for next message written into the kernel.
*
* The sequence number is derived from the instance number of this netlink
* socket and a 16-bit counter.
*
* @return the sequence number for the next message written into the
* kernel.
*/
inline uint32_t seqno() const { return (_instance_no << 16 | _seqno); }
/**
* Get cached netlink socket identifier value.
*
* @return the cached netlink socket identifier value.
*/
inline uint32_t nl_pid() const { return _nl_pid; }
/**
* Force socket to read data.
*
* This usually is performed after writing a request that the
* kernel will answer (e.g., after writing a route lookup).
* Use sparingly, with caution, and at your own risk.
*
* @param error_msg the error message (if error).
* @return XORP_OK on success, otherwise XORP_ERROR.
*/
int force_read(string& error_msg);
/**
* Force socket to recvfrom data.
*
* This usually is performed after writing a sendto() request that the
* kernel will answer (e.g., after writing a route lookup).
* Use sparingly, with caution, and at your own risk.
*
* @param flags the flags argument to the underlying recvfrom(2)
* system call.
* @param from if not NULL, on return it will be filled in with the source
* address of the received message.
* @param fromlen it should be initialized to the size of the buffer
* associated with @ref from. On return it will be modified to indicate the
* actual size of the address stored there.
* @param error_msg the error message (if error).
* @return XORP_OK on success, otherwise XORP_ERROR.
*/
int force_recvfrom(int flags, struct sockaddr* from, socklen_t* fromlen,
string& error_msg);
/**
* Force socket to recvmsg data.
*
* This usually is performed after writing a sendmsg() request that the
* kernel will answer (e.g., after writing a route lookup).
* Use sparingly, with caution, and at your own risk.
*
* @param flags the flags argument to the underlying recvmsg(2)
* system call.
* @param only_kernel_messages if true, accept only messages originated
* by the kernel.
* @param error_msg the error message (if error).
* @return XORP_OK on success, otherwise XORP_ERROR.
*/
int force_recvmsg(int flags, bool only_kernel_messages, string& error_msg);
/**
* Set the netlink multicast groups to listen for on the netlink socket.
*
* Note that this method must be called before method start() is called.
* If this method is not called, then the netlink socket will listen
* to the default set of netlink multicast groups (the empty set).
*
* @param v the set of netlink multicast groups to listen for on the
* netlink socket.
*/
void set_nl_groups(uint32_t v) { _nl_groups = v; }
/**
* Set a flag to expect to read a multipart message that is terminated
* with NLMSG_DONE.
*
* This flag is required to fix a bug with the Linux kernel:
* if we try to read the whole forwarding table, the kernel
* doesn't set the NLM_F_MULTI flag in each part of the multi-part
* message. The problem is similar when we read all addresses on
* an interface.
*
* @param v if true, set the flag to expect to read a multi-part message
* that is terminated with NLMSG_DONE.
*/
void set_multipart_message_read(bool v) { _is_multipart_message_read = v; }
private:
typedef list<NetlinkSocketObserver*> ObserverList;
/**
* Read data available for NetlinkSocket and invoke
* NetlinkSocketObserver::nlsock_data() on all observers of netlink
* socket.
*/
void io_event(XorpFd fd, IoEventType sm);
NetlinkSocket& operator=(const NetlinkSocket&); // Not implemented
NetlinkSocket(const NetlinkSocket&); // Not implemented
static const size_t NLSOCK_BYTES = 8*1024; // Initial guess at msg size
EventLoop& _eventloop;
int _fd;
ObserverList _ol;
uint16_t _seqno; // Seqno of next write()
uint16_t _instance_no; // Instance number of this netlink socket
static uint16_t _instance_cnt;
uint32_t _nl_pid;
uint32_t _nl_groups; // The netlink multicast groups to listen for
bool _is_multipart_message_read; // If true, expect to read a multipart message
friend class NetlinkSocketPlumber; // class that hooks observers in and out
};
class NetlinkSocketObserver {
public:
NetlinkSocketObserver(NetlinkSocket& ns);
virtual ~NetlinkSocketObserver();
/**
* Receive data from the netlink socket.
*
* Note that this method is called asynchronously when the netlink socket
* has data to receive, therefore it should never be called directly by
* anything else except the netlink socket facility itself.
*
* @param buffer the buffer with the received data.
*/
virtual void nlsock_data(const vector<uint8_t>& buffer) = 0;
/**
* Get NetlinkSocket associated with Observer.
*/
NetlinkSocket& netlink_socket();
private:
NetlinkSocket& _ns;
};
class NetlinkSocketReader : public NetlinkSocketObserver {
public:
NetlinkSocketReader(NetlinkSocket& ns);
virtual ~NetlinkSocketReader();
/**
* Force the reader to receive data from the specified netlink socket.
*
* @param ns the netlink socket to receive the data from.
* @param seqno the sequence number of the data to receive.
* @param error_msg the error message (if error).
* @return XORP_OK on success, otherwise XORP_ERROR.
*/
int receive_data(NetlinkSocket& ns, uint32_t seqno, string& error_msg);
/**
* Get the buffer with the data that was received.
*
* @return a reference to the buffer with the data that was received.
*/
const vector<uint8_t>& buffer() const { return (_cache_data); }
/**
* Receive data from the netlink socket.
*
* Note that this method is called asynchronously when the netlink socket
* has data to receive, therefore it should never be called directly by
* anything else except the netlink socket facility itself.
*
* @param buffer the buffer with the received data.
*/
virtual void nlsock_data(const vector<uint8_t>& buffer);
private:
NetlinkSocket& _ns;
bool _cache_valid; // Cache data arrived.
uint32_t _cache_seqno; // Seqno of netlink socket data to
// cache so reading via netlink
// socket can appear synchronous.
vector<uint8_t> _cache_data; // Cached netlink socket data.
};
#endif // __FEA_NETLINK_SOCKET_HH__
Generated by: pavlin on possum.icir.org on Wed Mar 21 11:23:22 2007, using kdoc $.