Bruce M. Simpson wrote:
Ben,
I've only briefly glimpsed at this patch, but I have a few comments
based on your description of the patch.
I'll leave it to Pavlin to comment on the MFEA specific scope of the
patch.
Ben Greear wrote:
Here's a first attempt at using one rx socket per device, and binding
to that particular
device. This keeps us from receiving multicast traffic not destined
for us when we are running
multiple instances of xorp on the same system.
This code appears to work, but it does not properly clean up sockets
when devices
are un-configured. I'll be working on that next.
This code will be less efficient than the old way if the OS doesn't
support
SO_BINDTODEVICE, so I'll also add some code to mimic the old behaviour
in that case (ie, windows).
There's also some other cruft in there to deal with races around
removing interfaces
and removing the OSPF multicast groups. These changes have nothing
in particular
to do with per-interface rx sockets.
Suggestions for improvements are welcome.
Right now, using a socket per interface is actually REQUIRED by
protocols which rely on IP layer broadcasts, i.e. OLSR (which is in
production deployment in places), BCAST (which was only ever
experimental) and the old RIPv1 which didn't use IP layer multicast
(which is more widespread than you'd hope for).
Pavlin and I have had some discussion about this. He quite rightly
states that using link-scoped multicasts is "the right thing" to do,
unfortunately the way that deployment of these protocols has played
out operationally, they are using all-ones and network broadcasts.
The xorp_olsr code, which has not yet been committed publicly, opens a
single socket per interface via XRL in a very similar way as xorp_rip
does to handle RIPv1.
It does this as it's the only consistent way of receiving IP
broadcasts on multiple interfaces in an OS portable way.
The lack of SO_BINDTODEVICE on a host platform is actually not that
big a deal.
To be sure, it's a Linux specific hack to deal with the ambiguity we
are presented with by the legacy BSD socket behaviour, that is,
broadcasts are NOT delivered to sockets which are bound in the laddr
tuple by bind().
If anything, I speculate that the overall cost of each additional
socket on the host platform is negligible, compared to the cost of
doing dispatch/fan-out in userland for a large number of such sockets.
I don't have hard data, but that is my gut feeling based on exposure.
In a "more deeply embedded" situation, the possibility exists that you
implement the IP layer in the FEA process anyway, so tight control
over the resource use of the XRL socket APIs exists at the cost of
having to code your own IP.
I still feel SO_BINDTODEVICE isn't the right way forward for solving
the problems it was introduced to solve, it's a case of immediatist
pragmatism, as it introduces a number of layering violations.
I just want to make sure that I can bind a socket to an interface, and
only have packets *from* that interface
show up on the socket. This means that the app will not receive crap on
interfaces that it is not (logically)
listening on. The current CVS tree of Xorp receives on all interfaces,
and then filters in the fea user-space logic.
When using 30 Xorp instances, this is about 900 wasted process wakes per
second for bogus packets
(assuming a conservative one multicast pkt tx per xorp per second).
It scales N^2 as well, so gets much worse as the numbers of Xorp
instances increase.
One problem with binding to local IPs is that if the IP addr of the
interface changes, then
you'd have to rebind the socket. With BINDTODEVICE that shouldn't be a
problem.
Anyway, I've done some more work to make this handle interfaces
leaving. I guess it could
still fail to register a new socket if nothing tries to bind a multicast
addr to it. With OSPF
that isn't a problem, but maybe other routing protocols don't use
multicast and would need
some explicit logic to allow fea to detect addition of new interfaces.
The new patch is attached.
Thanks,
Ben
--
Ben Greear <[EMAIL PROTECTED]>
Candela Technologies Inc http://www.candelatech.com
? data_plane/control_socket/click_socket.cc.flc
? data_plane/io/io_ip_socket.cc.ben
? data_plane/io/io_ip_socket.cc.flc
? data_plane/io/io_tcpudp_socket.cc.flc
Index: ifconfig_transaction.cc
===================================================================
RCS file: /cvs/xorp/fea/ifconfig_transaction.cc,v
retrieving revision 1.4
diff -u -r1.4 ifconfig_transaction.cc
--- ifconfig_transaction.cc 4 Jan 2008 03:15:46 -0000 1.4
+++ ifconfig_transaction.cc 2 Mar 2008 19:26:17 -0000
@@ -21,6 +21,7 @@
#include "libxorp/debug.h"
#include "ifconfig_transaction.hh"
+#include "xrl_fea_target.hh"
void
IfConfigTransactionManager::pre_commit(uint32_t tid)
@@ -38,3 +39,10 @@
flush(_tid_exec);
}
}
+
+bool RemoveInterface::dispatch() {
+ if (iftree().remove_interface(ifname()) != XORP_OK)
+ return (false);
+ fea_targ->notifyInterfaceDeleted(ifname());
+ return (true);
+}
Index: ifconfig_transaction.hh
===================================================================
RCS file: /cvs/xorp/fea/ifconfig_transaction.hh,v
retrieving revision 1.16
diff -u -r1.16 ifconfig_transaction.hh
--- ifconfig_transaction.hh 4 Jan 2008 03:15:46 -0000 1.16
+++ ifconfig_transaction.hh 2 Mar 2008 19:26:18 -0000
@@ -23,6 +23,7 @@
#include "ifconfig.hh"
#include "iftree.hh"
+class XrlFeaTarget;
class IfConfigTransactionManager : public TransactionManager {
public:
@@ -94,16 +95,16 @@
* Class for removing an interface.
*/
class RemoveInterface : public IfConfigTransactionOperation {
+protected:
+ XrlFeaTarget* fea_targ;
public:
- RemoveInterface(IfTree& iftree, const string& ifname)
- : IfConfigTransactionOperation(iftree, ifname) {}
-
- bool dispatch() {
- if (iftree().remove_interface(ifname()) != XORP_OK)
- return (false);
- return (true);
+ RemoveInterface(XrlFeaTarget* fea_target, IfTree& iftree, const string& ifname)
+ : IfConfigTransactionOperation(iftree, ifname) {
+ fea_targ = fea_target;
}
+ bool dispatch();
+
string str() const {
return string("RemoveInterface: ") + ifname();
}
Index: io_ip.hh
===================================================================
RCS file: /cvs/xorp/fea/io_ip.hh,v
retrieving revision 1.3
diff -u -r1.3 io_ip.hh
--- io_ip.hh 4 Jan 2008 03:15:47 -0000 1.3
+++ io_ip.hh 2 Mar 2008 19:26:18 -0000
@@ -255,10 +255,13 @@
/**
* Get the file descriptor for receiving protocol messages.
*
- * @return a reference to the file descriptor for receiving protocol
- * messages.
+ * @return a pointer to the file descriptor for receiving protocol
+ * messages, or NULL if it cannot be found.
*/
- virtual XorpFd& protocol_fd_in() = 0;
+ virtual XorpFd* mcast_protocol_fd_in() = 0;
+
+ /** Interface is going away..clean up the sockets for the associated vif(s) */
+ virtual void notifyInterfaceDeleted(const string& ifname) = 0;
protected:
/**
Index: io_ip_manager.cc
===================================================================
RCS file: /cvs/xorp/fea/io_ip_manager.cc,v
retrieving revision 1.12
diff -u -r1.12 io_ip_manager.cc
--- io_ip_manager.cc 4 Jan 2008 03:15:47 -0000 1.12
+++ io_ip_manager.cc 2 Mar 2008 19:26:18 -0000
@@ -457,6 +457,55 @@
return (ret_value);
}
+
+int
+IoIpComm::leave_all_multicast_groups(const string& if_name,
+ const string& vif_name,
+ string& error_msg)
+{
+ //XLOG_ERROR("IoIpComm::leave_all_multicast_groups, if: %s vif: %s\n",
+ //if_name.c_str(), vif_name.c_str());
+ start:
+ {
+ JoinedGroupsTable::iterator joined_iter;
+ for (joined_iter = _joined_groups_table.begin();
+ joined_iter != _joined_groups_table.end(); joined_iter++) {
+ //XLOG_ERROR("Found group, if: %s vif: %s\n",
+ // joined_iter->second.if_name().c_str(),
+ // joined_iter->second.vif_name().c_str());
+ if ((joined_iter->second.if_name() == if_name) &&
+ ((vif_name.size() == 0) || (joined_iter->second.vif_name() == vif_name))) {
+
+ string tmp_vifn(joined_iter->second.vif_name());
+
+ //XLOG_ERROR("Matched, looking for receivers.\n");
+ set<string>::iterator ri = joined_iter->second.get_receivers().begin();
+ while (ri != joined_iter->second.get_receivers().end()) {
+ //XLOG_ERROR("Found receiver: %s\n", ri->c_str());
+ leave_multicast_group(if_name, tmp_vifn, joined_iter->second.group_address(),
+ *ri, error_msg);
+ // Maybe there are more...back out to top and search again. This should keep our iterators
+ // from being corrupted by the leave_multicast_group call.
+ goto start;
+ }//for all receivers
+ }//if this joined group matches our interface and vif (if specified)
+ }//for all joined groups
+ }//scoping brace
+ // We delete all we can find...whatever we found must have been OK.
+ return XORP_OK;
+}
+
+void IoIpComm::notifyInterfaceDeleted(const string& ifname) {
+ IoIpPlugins::iterator plugin_iter;
+ for (plugin_iter = _io_ip_plugins.begin();
+ plugin_iter != _io_ip_plugins.end();
+ ++plugin_iter) {
+ IoIp* io_ip = plugin_iter->second;
+ io_ip->notifyInterfaceDeleted(ifname);
+ }
+}
+
+
int
IoIpComm::leave_multicast_group(const string& if_name,
const string& vif_name,
@@ -643,7 +692,7 @@
}
XorpFd
-IoIpComm::first_valid_protocol_fd_in()
+IoIpComm::first_valid_mcast_protocol_fd_in()
{
XorpFd xorp_fd;
@@ -651,7 +700,7 @@
IoIpPlugins::iterator iter;
for (iter = _io_ip_plugins.begin(); iter != _io_ip_plugins.end(); ++iter) {
IoIp* io_ip = iter->second;
- xorp_fd = io_ip->protocol_fd_in();
+ xorp_fd = *(io_ip->mcast_protocol_fd_in());
if (xorp_fd.is_valid())
return (xorp_fd);
}
@@ -1005,6 +1054,27 @@
return (XORP_ERROR);
}
+
+int IoIpManager::leave_all_multicast_groups(const string& if_name,
+ const string& vif_name,
+ string& error_msg) {
+ CommTable::iterator cti;
+ for (cti = _comm_table4.begin(); cti != _comm_table4.end(); cti++) {
+ IoIpComm* c = cti->second;
+ c->leave_all_multicast_groups(if_name, vif_name, error_msg);
+ }
+ return XORP_OK;
+}
+
+void IoIpManager::notifyInterfaceDeleted(const string& if_name) {
+ CommTable::iterator cti;
+ for (cti = _comm_table4.begin(); cti != _comm_table4.end(); cti++) {
+ IoIpComm* c = cti->second;
+ c->notifyInterfaceDeleted(if_name);
+ }
+}
+
+
int
IoIpManager::leave_multicast_group(const string& receiver_name,
const string& if_name,
@@ -1053,7 +1123,7 @@
int family,
uint8_t ip_protocol,
IoIpManager::UpcallReceiverCb receiver_cb,
- XorpFd& receiver_fd,
+ XorpFd& mcast_receiver_fd,
string& error_msg)
{
SystemMulticastUpcallFilter* filter;
@@ -1093,7 +1163,7 @@
if (filter->ip_protocol() == ip_protocol) {
// Already have this filter
filter->set_receiver_cb(receiver_cb);
- receiver_fd = io_ip_comm->first_valid_protocol_fd_in();
+ mcast_receiver_fd = io_ip_comm->first_valid_mcast_protocol_fd_in();
return (XORP_OK);
}
}
@@ -1110,7 +1180,7 @@
// Add the filter to those associated with empty receiver_name
filters.insert(FilterBag::value_type(receiver_name, filter));
- receiver_fd = io_ip_comm->first_valid_protocol_fd_in();
+ mcast_receiver_fd = io_ip_comm->first_valid_mcast_protocol_fd_in();
return (XORP_OK);
}
Index: io_ip_manager.hh
===================================================================
RCS file: /cvs/xorp/fea/io_ip_manager.hh,v
retrieving revision 1.13
diff -u -r1.13 io_ip_manager.hh
--- io_ip_manager.hh 4 Jan 2008 03:15:47 -0000 1.13
+++ io_ip_manager.hh 2 Mar 2008 19:26:19 -0000
@@ -196,6 +196,8 @@
*/
bool empty() const { return _receivers.empty(); }
+ set<string>& get_receivers() { return _receivers; }
+
private:
string _if_name;
string _vif_name;
@@ -398,6 +400,22 @@
string& error_msg);
/**
+ * Leave all IP multicast groups on this interface.
+ *
+ * @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 error_msg the error message (if error).
+ * @return XORP_OK on success, otherwise XORP_ERROR.
+ */
+ int leave_all_multicast_groups(const string& if_name,
+ const string& vif_name,
+ string& error_msg);
+
+ void notifyInterfaceDeleted(const string& ifname);
+
+
+ /**
* Get the IP protocol.
*
* @return the IP protocol.
@@ -410,7 +428,7 @@
* @return the first valid file descriptor for receiving protocol
* messages.
*/
- XorpFd first_valid_protocol_fd_in();
+ XorpFd first_valid_mcast_protocol_fd_in();
private:
IoIpComm(const IoIpComm&); // Not implemented.
@@ -609,6 +627,13 @@
const IPvX& group_address,
string& error_msg);
+ /** Leave all multicast groups on this vif */
+ int leave_all_multicast_groups(const string& if_name,
+ const string& vif_name,
+ string& error_msg);
+
+ void notifyInterfaceDeleted(const string& ifname);
+
/**
* Register to receive multicast forwarding related upcalls from the
* system.
@@ -628,7 +653,7 @@
int register_system_multicast_upcall_receiver(int family,
uint8_t ip_protocol,
IoIpManager::UpcallReceiverCb receiver_cb,
- XorpFd& receiver_fd,
+ XorpFd& mcast_receiver_fd,
string& error_msg);
/**
Index: io_link_manager.cc
===================================================================
RCS file: /cvs/xorp/fea/io_link_manager.cc,v
retrieving revision 1.8
diff -u -r1.8 io_link_manager.cc
--- io_link_manager.cc 4 Jan 2008 03:15:47 -0000 1.8
+++ io_link_manager.cc 2 Mar 2008 19:26:19 -0000
@@ -893,6 +893,7 @@
return (XORP_ERROR);
}
+
int
IoLinkManager::register_data_plane_manager(FeaDataPlaneManager* fea_data_plane_manager,
bool is_exclusive)
Index: io_link_manager.hh
===================================================================
RCS file: /cvs/xorp/fea/io_link_manager.hh,v
retrieving revision 1.8
diff -u -r1.8 io_link_manager.hh
--- io_link_manager.hh 4 Jan 2008 03:15:47 -0000 1.8
+++ io_link_manager.hh 2 Mar 2008 19:26:20 -0000
@@ -202,6 +202,8 @@
*/
bool empty() const { return _receivers.empty(); }
+ set<string>& get_receivers() { return _receivers; }
+
private:
Mac _group_address;
set<string> _receivers;
Index: xrl_fea_target.cc
===================================================================
RCS file: /cvs/xorp/fea/xrl_fea_target.cc,v
retrieving revision 1.37
diff -u -r1.37 xrl_fea_target.cc
--- xrl_fea_target.cc 4 Jan 2008 03:15:51 -0000 1.37
+++ xrl_fea_target.cc 2 Mar 2008 19:26:23 -0000
@@ -1429,6 +1429,10 @@
return XrlCmdError::OKAY();
}
+void XrlFeaTarget::notifyInterfaceDeleted(const string& ifname) {
+ _io_ip_manager.notifyInterfaceDeleted(ifname);
+}
+
XrlCmdError
XrlFeaTarget::ifmgr_0_1_delete_interface(
// Input values,
@@ -1438,9 +1442,18 @@
IfTree& iftree = ifconfig().local_config();
string error_msg;
+ XLOG_INFO("Deleting interface, ifname: %s\n", ifname.c_str());
+
+ // Hack: Remove multicast addrs first. --Ben
+ string empty;
+ _io_ip_manager.leave_all_multicast_groups(ifname, empty, error_msg);
+ if (error_msg.size()) {
+ XLOG_ERROR(error_msg.c_str());
+ }
+
if (ifconfig().add_transaction_operation(
tid,
- new RemoveInterface(iftree, ifname),
+ new RemoveInterface(this, iftree, ifname),
error_msg)
!= XORP_OK) {
return XrlCmdError::COMMAND_FAILED(error_msg);
@@ -1708,6 +1721,15 @@
IfTree& iftree = ifconfig().local_config();
string error_msg;
+
+ XLOG_ERROR("Deleting vif, ifname: %s vif: %s\n", ifname.c_str(), vifname.c_str());
+
+ // Hack: Remove multicast addrs first. --Ben
+ _io_ip_manager.leave_all_multicast_groups(ifname, vifname, error_msg);
+ if (error_msg.size()) {
+ XLOG_ERROR(error_msg.c_str());
+ }
+
if (ifconfig().add_transaction_operation(
tid,
new RemoveInterfaceVif(iftree, ifname, vifname),
Index: xrl_fea_target.hh
===================================================================
RCS file: /cvs/xorp/fea/xrl_fea_target.hh,v
retrieving revision 1.25
diff -u -r1.25 xrl_fea_target.hh
--- xrl_fea_target.hh 4 Jan 2008 03:15:52 -0000 1.25
+++ xrl_fea_target.hh 2 Mar 2008 19:26:24 -0000
@@ -425,6 +425,10 @@
const uint32_t& tid,
const string& ifname);
+ // Callback for RemoveInterface class, so we can clean up the io_ip_manager
+ // class properly.
+ void notifyInterfaceDeleted(const string& ifname);
+
/**
* Implicitly configure all interfaces within the FEA by using information
* from the underlying system.
Index: data_plane/control_socket/netlink_socket_utilities.cc
===================================================================
RCS file: /cvs/xorp/fea/data_plane/control_socket/netlink_socket_utilities.cc,v
retrieving revision 1.12
diff -u -r1.12 netlink_socket_utilities.cc
--- data_plane/control_socket/netlink_socket_utilities.cc 8 Jan 2008 23:30:09 -0000 1.12
+++ data_plane/control_socket/netlink_socket_utilities.cc 2 Mar 2008 19:26:24 -0000
@@ -332,9 +332,10 @@
const IfTreeVif* vifp = iftree.find_vif(if_index);
if (vifp == NULL) {
if (! is_deleted) {
- XLOG_FATAL("Could not find interface and vif for index %d",
+ XLOG_ERROR("Could not find interface and vif for index %d",
if_index);
}
+ return XORP_ERROR;
}
if_name = vifp->ifname();
vif_name = vifp->vifname();
Index: data_plane/fibconfig/fibconfig_entry_set_netlink_socket.cc
===================================================================
RCS file: /cvs/xorp/fea/data_plane/fibconfig/fibconfig_entry_set_netlink_socket.cc,v
retrieving revision 1.17
diff -u -r1.17 fibconfig_entry_set_netlink_socket.cc
--- data_plane/fibconfig/fibconfig_entry_set_netlink_socket.cc 4 Jan 2008 03:15:59 -0000 1.17
+++ data_plane/fibconfig/fibconfig_entry_set_netlink_socket.cc 2 Mar 2008 19:26:25 -0000
@@ -275,9 +275,9 @@
if (if_index != NULL)
break;
- XLOG_FATAL("Could not find interface index for interface %s vif %s",
+ XLOG_ERROR("Could not find interface index for interface %s vif %s",
fte.ifname().c_str(), fte.vifname().c_str());
- break;
+ return XORP_ERROR;
} while (false);
//
Index: data_plane/ifconfig/ifconfig_parse_netlink_socket.cc
===================================================================
RCS file: /cvs/xorp/fea/data_plane/ifconfig/ifconfig_parse_netlink_socket.cc,v
retrieving revision 1.17
diff -u -r1.17 ifconfig_parse_netlink_socket.cc
--- data_plane/ifconfig/ifconfig_parse_netlink_socket.cc 21 Feb 2008 02:02:33 -0000 1.17
+++ data_plane/ifconfig/ifconfig_parse_netlink_socket.cc 2 Mar 2008 19:26:25 -0000
@@ -603,7 +603,8 @@
//
return;
}
- XLOG_FATAL("Could not find vif with index %u in IfTree", if_index);
+ XLOG_ERROR("Could not find vif with index %u in IfTree", if_index);
+ return;
}
debug_msg("Address event on interface %s vif %s with interface index %u\n",
vifp->ifname().c_str(), vifp->vifname().c_str(),
Index: data_plane/io/io_ip_dummy.hh
===================================================================
RCS file: /cvs/xorp/fea/data_plane/io/io_ip_dummy.hh,v
retrieving revision 1.3
diff -u -r1.3 io_ip_dummy.hh
--- data_plane/io/io_ip_dummy.hh 4 Jan 2008 03:16:14 -0000 1.3
+++ data_plane/io/io_ip_dummy.hh 2 Mar 2008 19:26:25 -0000
@@ -183,7 +183,14 @@
* @return a reference to the file descriptor for receiving protocol
* messages.
*/
- XorpFd& protocol_fd_in() { return (_dummy_protocol_fd_in); }
+ XorpFd* mcast_protocol_fd_in() {
+ return (&_dummy_protocol_fd_in);
+ }
+
+ /** Interface is going away..clean up the sockets for the associated vif(s) */
+ void notifyInterfaceDeleted(const string& ifname) {
+ UNUSED(ifname);
+ }
private:
// Private state
Index: data_plane/io/io_ip_socket.cc
===================================================================
RCS file: /cvs/xorp/fea/data_plane/io/io_ip_socket.cc,v
retrieving revision 1.17
diff -u -r1.17 io_ip_socket.cc
--- data_plane/io/io_ip_socket.cc 4 Jan 2008 03:16:14 -0000 1.17
+++ data_plane/io/io_ip_socket.cc 2 Mar 2008 19:26:27 -0000
@@ -515,26 +515,37 @@
string& error_msg)
{
const IfTreeVif* vifp;
+ XorpFd* _proto_socket_in = NULL;
// Find the vif
vifp = iftree().find_vif(if_name, vif_name);
if (vifp == NULL) {
- error_msg = c_format("Joining multicast group %s failed: "
+ error_msg += c_format("Joining multicast group %s failed: "
"interface %s vif %s not found",
cstring(group),
if_name.c_str(),
vif_name.c_str());
- return (XORP_ERROR);
+ goto out_err;
+ }
+
+ _proto_socket_in = findOrCreateInputSocket(if_name, vif_name, error_msg);
+
+ if (! _proto_socket_in) {
+ string em = c_format("ERROR: Could not find or create input socket, if_name: %s vif_name: %s error_msg: %s",
+ if_name.c_str(), vif_name.c_str(), error_msg.c_str());
+ XLOG_WARNING("%s", em.c_str());
+ error_msg += em;
+ goto out_err;
}
#if 0 // TODO: enable or disable the enabled() check?
if (! vifp->enabled()) {
- error_msg = c_format("Cannot join group %s on interface %s vif %s: "
+ error_msg += c_format("Cannot join group %s on interface %s vif %s: "
"interface/vif is DOWN",
cstring(group),
if_name.c_str(),
vif_name.c_str());
- return (XORP_ERROR);
+ goto out_err;
}
#endif // 0/1
@@ -547,12 +558,12 @@
// Find the first address
IfTreeVif::IPv4Map::const_iterator ai = vifp->ipv4addrs().begin();
if (ai == vifp->ipv4addrs().end()) {
- error_msg = c_format("Cannot join group %s on interface %s vif %s: "
+ error_msg += c_format("Cannot join group %s on interface %s vif %s: "
"interface/vif has no address",
cstring(group),
if_name.c_str(),
vif_name.c_str());
- return (XORP_ERROR);
+ goto out_err;
}
const IfTreeAddr4& fa = ai->second;
@@ -560,14 +571,19 @@
group.copy_out(mreq.imr_multiaddr);
mreq.imr_interface.s_addr = in_addr.s_addr;
- if (setsockopt(_proto_socket_in, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+ if (setsockopt(*_proto_socket_in, IPPROTO_IP, IP_ADD_MEMBERSHIP,
XORP_SOCKOPT_CAST(&mreq), sizeof(mreq)) < 0) {
- error_msg = c_format("Cannot join group %s on interface %s vif %s: %s",
+ error_msg += c_format("Cannot join group %s on interface %s vif %s: %s",
cstring(group),
if_name.c_str(),
vif_name.c_str(),
strerror(errno));
- return (XORP_ERROR);
+ goto out_err;
+ }
+ else {
+ XLOG_INFO("Joined IPv4 group: %s on interface %s vif %s socket: %i",
+ cstring(group), if_name.c_str(), vif_name.c_str(),
+ (int)(*_proto_socket_in));
}
}
break;
@@ -576,22 +592,27 @@
case AF_INET6:
{
#ifndef HAVE_IPV6_MULTICAST
- error_msg = c_format("join_multicast_group() failed: "
+ error_msg += c_format("join_multicast_group() failed: "
"IPv6 multicast not supported");
- return (XORP_ERROR);
+ goto out_err;
#else
struct ipv6_mreq mreq6;
group.copy_out(mreq6.ipv6mr_multiaddr);
mreq6.ipv6mr_interface = vifp->pif_index();
- if (setsockopt(_proto_socket_in, IPPROTO_IPV6, IPV6_JOIN_GROUP,
+ if (setsockopt(*_proto_socket_in, IPPROTO_IPV6, IPV6_JOIN_GROUP,
XORP_SOCKOPT_CAST(&mreq6), sizeof(mreq6)) < 0) {
- error_msg = c_format("Cannot join group %s on interface %s vif %s: %s",
+ error_msg += c_format("Cannot join group %s on interface %s vif %s: %s",
cstring(group),
if_name.c_str(),
vif_name.c_str(),
strerror(errno));
- return (XORP_ERROR);
+ goto out_err;
+ }
+ else {
+ XLOG_INFO("Joined IPv6 group: %s on interface %s vif %s socket: %i",
+ cstring(group), if_name.c_str(), vif_name.c_str(),
+ (int)(*_proto_socket_in));
}
#endif // HAVE_IPV6_MULTICAST
}
@@ -600,13 +621,66 @@
default:
XLOG_UNREACHABLE();
- error_msg = c_format("Invalid address family %d", family());
- return (XORP_ERROR);
+ error_msg += c_format("Invalid address family %d", family());
+ goto out_err;
}
return (XORP_OK);
+
+ out_err:
+ if (error_msg.size()) {
+ XLOG_ERROR("ERROR in join_multicast_group: %s", error_msg.c_str());
+ }
+ return XORP_ERROR;
}
+
+XorpFd* IoIpSocket::mcast_protocol_fd_in() {
+ if (! _mcast_proto_socket_in.is_valid()) {
+ // Try to open the socket.
+ _mcast_proto_socket_in = socket(family(), SOCK_RAW, ip_protocol());
+ if (!_mcast_proto_socket_in.is_valid()) {
+ char *errstr;
+
+#ifdef HAVE_STRERROR
+ errstr = strerror(errno);
+#else
+ errstr = "unknown error";
+#endif
+ XLOG_WARNING("Cannot open multicast IP protocol %u raw socket: %s",
+ ip_protocol(), errstr);
+ }
+ else {
+ string err_msg;
+ initializeInputSocket(&_mcast_proto_socket_in, err_msg);
+ if (err_msg.size()) {
+ XLOG_WARNING("%s", err_msg.c_str());
+ }
+ }
+ }
+ return &_mcast_proto_socket_in;
+}
+
+
+XorpFd* IoIpSocket::findExistingInputSocket(const string& if_name, const string& vif_name) {
+#ifdef SO_BINDTODEVICE
+ string k(if_name);
+ k += " ";
+ k += vif_name;
+ map<string, XorpFd*>::iterator i = _proto_sockets_in.find(k);
+#else
+ map<string, XorpFd*>::iterator i = _proto_sockets_in.begin();
+#endif
+ if (i == _proto_sockets_in.end()) {
+ return NULL;
+ }
+ else {
+ return i->second;
+ }
+
+}
+
+
int
IoIpSocket::leave_multicast_group(const string& if_name,
const string& vif_name,
@@ -618,18 +692,28 @@
// Find the vif
vifp = iftree().find_vif(if_name, vif_name);
if (vifp == NULL) {
- error_msg = c_format("Leaving multicast group %s failed: "
- "interface %s vif %s not found",
+ error_msg += c_format("Leaving multicast group %s failed: "
+ "interface %s vif %s not found\n",
cstring(group),
if_name.c_str(),
vif_name.c_str());
return (XORP_ERROR);
}
+
+ XorpFd* _proto_socket_in = findExistingInputSocket(if_name, vif_name);
+ if (!_proto_socket_in) {
+ error_msg += c_format("Leaving multicast group %s failed: "
+ "interface %s vif %s does not have a socket assigned.\n",
+ cstring(group),
+ if_name.c_str(),
+ vif_name.c_str());
+ return (XORP_ERROR);
+ }
#if 0 // TODO: enable or disable the enabled() check?
if (! vifp->enabled()) {
- error_msg = c_format("Cannot leave group %s on interface %s vif %s: "
- "interface/vif is DOWN",
+ error_msg += c_format("Cannot leave group %s on interface %s vif %s: "
+ "interface/vif is DOWN\n",
cstring(group),
if_name.c_str(),
vif_name.c_str());
@@ -646,8 +730,8 @@
// Find the first address
IfTreeVif::IPv4Map::const_iterator ai = vifp->ipv4addrs().begin();
if (ai == vifp->ipv4addrs().end()) {
- error_msg = c_format("Cannot leave group %s on interface %s vif %s: "
- "interface/vif has no address",
+ error_msg += c_format("Cannot leave group %s on interface %s vif %s: "
+ "interface/vif has no address\n",
cstring(group),
if_name.c_str(),
vif_name.c_str());
@@ -658,15 +742,20 @@
fa.addr().copy_out(in_addr);
group.copy_out(mreq.imr_multiaddr);
mreq.imr_interface.s_addr = in_addr.s_addr;
- if (setsockopt(_proto_socket_in, IPPROTO_IP, IP_DROP_MEMBERSHIP,
+ if (setsockopt(*_proto_socket_in, IPPROTO_IP, IP_DROP_MEMBERSHIP,
XORP_SOCKOPT_CAST(&mreq), sizeof(mreq)) < 0) {
- error_msg = c_format("Cannot leave group %s on interface %s vif %s: %s",
+ error_msg += c_format("Cannot leave group %s on interface %s vif %s socket: %i: %s\n",
cstring(group),
if_name.c_str(),
- vif_name.c_str(),
+ vif_name.c_str(), (int)(*_proto_socket_in),
strerror(errno));
return (XORP_ERROR);
}
+ else {
+ XLOG_INFO("Left group: %s on interface %s vif %s socket: %i",
+ cstring(group), if_name.c_str(), vif_name.c_str(),
+ (int)(*_proto_socket_in));
+ }
}
break;
@@ -674,20 +763,20 @@
case AF_INET6:
{
#ifndef HAVE_IPV6_MULTICAST
- error_msg = c_format("leave_multicast_group() failed: "
- "IPv6 multicast not supported");
+ error_msg += c_format("leave_multicast_group() failed: "
+ "IPv6 multicast not supported\n");
return (XORP_ERROR);
#else
struct ipv6_mreq mreq6;
group.copy_out(mreq6.ipv6mr_multiaddr);
mreq6.ipv6mr_interface = vifp->pif_index();
- if (setsockopt(_proto_socket_in, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
+ if (setsockopt(*_proto_socket_in, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
XORP_SOCKOPT_CAST(&mreq6), sizeof(mreq6)) < 0) {
- error_msg = c_format("Cannot leave group %s on interface %s vif %s: %s",
+ error_msg += c_format("Cannot leave V6 group %s on interface %s vif %s socket: %i: %s\n",
cstring(group),
if_name.c_str(),
- vif_name.c_str(),
+ vif_name.c_str(), (int)(*_proto_socket_in),
strerror(errno));
return (XORP_ERROR);
}
@@ -698,25 +787,27 @@
default:
XLOG_UNREACHABLE();
- error_msg = c_format("Invalid address family %d", family());
+ error_msg += c_format("Invalid address family %d\n", family());
return (XORP_ERROR);
}
return (XORP_OK);
}
-int
-IoIpSocket::open_proto_sockets(string& error_msg)
-{
- string dummy_error_msg;
- if (_proto_socket_in.is_valid() && _proto_socket_out.is_valid())
- return (XORP_OK);
-
- // If necessary, open the protocol sockets
- if (! _proto_socket_in.is_valid()) {
- _proto_socket_in = socket(family(), SOCK_RAW, ip_protocol());
- if (!_proto_socket_in.is_valid()) {
+XorpFd* IoIpSocket::findOrCreateInputSocket(const string& if_name, const string& vif_name,
+ string& error_msg) {
+ XorpFd* rv = findExistingInputSocket(if_name, vif_name);
+
+ string key(if_name);
+ key += " ";
+ key += vif_name;
+
+ if (!rv) {
+ // Create a new one
+ rv = new XorpFd();
+ *rv = socket(family(), SOCK_RAW, ip_protocol());
+ if (!rv->is_valid()) {
char *errstr;
#ifdef HAVE_STRERROR
@@ -724,28 +815,47 @@
#else
errstr = "unknown error";
#endif
- error_msg = c_format("Cannot open IP protocol %u raw socket: %s",
- ip_protocol(), errstr);
- return (XORP_ERROR);
+ error_msg += c_format("Cannot open IP protocol %u raw socket: %s",
+ ip_protocol(), errstr);
+ delete rv;
+ return NULL;
+ }
+ else {
+ _proto_sockets_in[key] = rv;
}
- }
- if (! _proto_socket_out.is_valid()) {
- _proto_socket_out = socket(family(), SOCK_RAW, ip_protocol());
- if (!_proto_socket_out.is_valid()) {
- char *errstr;
+ int rslt = initializeInputSocket(rv, error_msg);
+ if (rslt != XORP_OK) {
+ _proto_sockets_in.erase(key);
+ cleanupXorpFd(rv);
+ return NULL;
+ }
+ // Bind to a particular interface.
+#ifdef SO_BINDTODEVICE
+ if (setsockopt(*rv, SOL_SOCKET, SO_BINDTODEVICE,
+ vif_name.c_str(), vif_name.size() + 1)) {
+ error_msg += c_format("ERROR: IoIpSocket::open_proto_socket, setsockopt (BINDTODEVICE): failed: %s",
#ifdef HAVE_STRERROR
- errstr = strerror(errno);
+ strerror(errno)
#else
- errstr = "unknown error";
-#endif
- error_msg = c_format("Cannot open IP protocol %u raw socket: %s",
- ip_protocol(), errstr);
- return (XORP_ERROR);
+ "unknown error"
+#endif
+ );
+ }
+ else {
+ XLOG_INFO("Successfully bound socket: %i to interface: %s input sockets size: %i\n",
+ (int)(*rv), vif_name.c_str(), _proto_sockets_in.size());
}
+#endif
}
+ return rv;
+}
+
+
+int IoIpSocket::initializeInputSocket(XorpFd* rv, string& error_msg) {
+
#ifdef HOST_OS_WINDOWS
switch (family()) {
case AF_INET:
@@ -758,7 +868,7 @@
int result;
DWORD nbytes;
- result = WSAIoctl(_proto_socket_in,
+ result = WSAIoctl(*rv,
SIO_GET_EXTENSION_FUNCTION_POINTER,
const_cast<GUID *>(&guidWSARecvMsg),
sizeof(guidWSARecvMsg),
@@ -777,7 +887,7 @@
int result;
DWORD nbytes;
- result = WSAIoctl(_proto_socket_in,
+ result = WSAIoctl(*rv,
SIO_GET_EXTENSION_FUNCTION_POINTER,
const_cast<GUID *>(&guidWSASendMsg),
sizeof(guidWSASendMsg),
@@ -794,8 +904,8 @@
#endif // HAVE_IPV6
default:
XLOG_UNREACHABLE();
- error_msg = c_format("Invalid address family %d", family());
- return (XORP_ERROR);
+ error_msg += c_format("Invalid address family %d", family());
+ return XORP_ERROR;
}
#endif // HOST_OS_WINDOWS
@@ -804,43 +914,21 @@
//
// Lots of input buffering
- if (comm_sock_set_rcvbuf(_proto_socket_in, SO_RCV_BUF_SIZE_MAX,
+ if (comm_sock_set_rcvbuf(*rv, SO_RCV_BUF_SIZE_MAX,
SO_RCV_BUF_SIZE_MIN)
< SO_RCV_BUF_SIZE_MIN) {
- error_msg = c_format("Cannot set the receiver buffer size: %s",
- comm_get_last_error_str());
- close_proto_sockets(dummy_error_msg);
- return (XORP_ERROR);
- }
- // Lots of output buffering
- if (comm_sock_set_rcvbuf(_proto_socket_out, SO_SND_BUF_SIZE_MAX,
- SO_SND_BUF_SIZE_MIN)
- < SO_SND_BUF_SIZE_MIN) {
- error_msg = c_format("Cannot set the sender buffer size: %s",
- comm_get_last_error_str());
- close_proto_sockets(dummy_error_msg);
- return (XORP_ERROR);
- }
- // Include IP header when sending (XXX: doesn't do anything for IPv6)
- if (enable_ip_hdr_include(true, error_msg) != XORP_OK) {
- close_proto_sockets(dummy_error_msg);
- return (XORP_ERROR);
+ error_msg += c_format("Cannot set the receiver buffer size: %s",
+ comm_get_last_error_str());
+ // doesn't seem fatal....continue on.
+ //close_proto_sockets(error_msg);
+ //return (XORP_ERROR);
}
+
// Show interest in receiving information from IP header
- if (enable_recv_pktinfo(true, error_msg) != XORP_OK) {
- close_proto_sockets(dummy_error_msg);
- return (XORP_ERROR);
- }
- // Restrict multicast TTL
- if (set_multicast_ttl(MINTTL, error_msg) != XORP_OK) {
- close_proto_sockets(dummy_error_msg);
- return (XORP_ERROR);
- }
- // Disable mcast loopback
- if (enable_multicast_loopback(false, error_msg) != XORP_OK) {
- close_proto_sockets(dummy_error_msg);
- return (XORP_ERROR);
+ if (enable_recv_pktinfo(rv, true, error_msg) != XORP_OK) {
+ return XORP_ERROR;
}
+
// Protocol-specific setup
switch (family()) {
case AF_INET:
@@ -870,12 +958,11 @@
}
#endif // 0
#endif // HAVE_IPV6_MULTICAST_ROUTING
- if (setsockopt(_proto_socket_in, ip_protocol(), ICMP6_FILTER,
+ if (setsockopt(*rv, ip_protocol(), ICMP6_FILTER,
XORP_SOCKOPT_CAST(&filter), sizeof(filter)) < 0) {
- close_proto_sockets(dummy_error_msg);
- error_msg = c_format("setsockopt(ICMP6_FILTER) failed: %s",
- strerror(errno));
- return (XORP_ERROR);
+ error_msg += c_format("setsockopt(ICMP6_FILTER) failed: %s",
+ strerror(errno));
+ return XORP_ERROR;
}
}
}
@@ -883,8 +970,8 @@
#endif // HAVE_IPV6
default:
XLOG_UNREACHABLE();
- error_msg = c_format("Invalid address family %d", family());
- return (XORP_ERROR);
+ error_msg += c_format("Invalid address family %d", family());
+ return XORP_ERROR;
}
#ifdef HOST_OS_WINDOWS
@@ -898,20 +985,77 @@
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
- if (SOCKET_ERROR == bind(_proto_socket_in, (sockaddr *)&sin,
+ if (SOCKET_ERROR == bind(*rv, (sockaddr *)&sin,
sizeof(sockaddr_in))) {
XLOG_WARNING("bind() failed: %s\n", win_strerror(GetLastError()));
}
#endif // HOST_OS_WINDOWS
// Assign a method to read from this socket
- if (eventloop().add_ioevent_cb(_proto_socket_in, IOT_READ,
+ if (eventloop().add_ioevent_cb(*rv, IOT_READ,
callback(this,
&IoIpSocket::proto_socket_read))
== false) {
+ error_msg += c_format("Cannot add protocol socket: %i to the set of "
+ "sockets to read from in the event loop", (int)(*rv));
+ return XORP_ERROR;
+ }
+
+ return XORP_OK;
+}//initializeInputSocket
+
+
+int
+IoIpSocket::open_proto_sockets(string& error_msg)
+{
+ string dummy_error_msg;
+
+ // We will open input sockets as interfaces are registered (due to listening for mcast addrs)
+ if (_proto_socket_out.is_valid())
+ return (XORP_OK);
+
+ if (! _proto_socket_out.is_valid()) {
+ _proto_socket_out = socket(family(), SOCK_RAW, ip_protocol());
+ if (!_proto_socket_out.is_valid()) {
+ char *errstr;
+
+#ifdef HAVE_STRERROR
+ errstr = strerror(errno);
+#else
+ errstr = "unknown error";
+#endif
+ error_msg = c_format("Cannot open IP protocol %u raw socket: %s",
+ ip_protocol(), errstr);
+ return (XORP_ERROR);
+ }
+ }
+
+ //
+ // Set various socket options
+ //
+
+ // Lots of output buffering
+ if (comm_sock_set_rcvbuf(_proto_socket_out, SO_SND_BUF_SIZE_MAX,
+ SO_SND_BUF_SIZE_MIN)
+ < SO_SND_BUF_SIZE_MIN) {
+ error_msg = c_format("Cannot set the sender buffer size: %s",
+ comm_get_last_error_str());
+ close_proto_sockets(dummy_error_msg);
+ return (XORP_ERROR);
+ }
+ // Include IP header when sending (XXX: doesn't do anything for IPv6)
+ if (enable_ip_hdr_include(true, error_msg) != XORP_OK) {
+ close_proto_sockets(dummy_error_msg);
+ return (XORP_ERROR);
+ }
+ // Restrict multicast TTL
+ if (set_multicast_ttl(MINTTL, error_msg) != XORP_OK) {
+ close_proto_sockets(dummy_error_msg);
+ return (XORP_ERROR);
+ }
+ // Disable mcast loopback
+ if (enable_multicast_loopback(false, error_msg) != XORP_OK) {
close_proto_sockets(dummy_error_msg);
- error_msg = c_format("Cannot add a protocol socket to the set of "
- "sockets to read from in the event loop");
return (XORP_ERROR);
}
@@ -931,12 +1075,30 @@
_proto_socket_out.clear();
}
+ if (_mcast_proto_socket_in.is_valid()) {
+ comm_close(_mcast_proto_socket_in);
+ _mcast_proto_socket_in.clear();
+ }
+
+ map<string, XorpFd*>::iterator i;
+ for (i = _proto_sockets_in.begin(); i != _proto_sockets_in.end(); i++) {
+
+ XorpFd* fd = i->second;
+
+ cleanupXorpFd(fd);
+ }
+ _proto_sockets_in.clear();
+
+ return (XORP_OK);
+}
+
+int IoIpSocket::cleanupXorpFd(XorpFd* fd) {
//
// Close the incoming protocol socket
//
- if (_proto_socket_in.is_valid()) {
+ if (fd->is_valid()) {
// Remove it just in case, even though it may not be select()-ed
- eventloop().remove_ioevent_cb(_proto_socket_in);
+ eventloop().remove_ioevent_cb(*fd);
#ifdef HOST_OS_WINDOWS
switch (family()) {
@@ -955,14 +1117,15 @@
return (XORP_ERROR);
}
#endif // HOST_OS_WINDOWS
-
- comm_close(_proto_socket_in);
- _proto_socket_in.clear();
+
+ comm_close(*fd);
+ fd->clear();
}
-
- return (XORP_OK);
+ delete fd;
+ return XORP_OK;
}
+
int
IoIpSocket::enable_ip_hdr_include(bool is_enabled, string& error_msg)
{
@@ -1002,7 +1165,7 @@
}
int
-IoIpSocket::enable_recv_pktinfo(bool is_enabled, string& error_msg)
+IoIpSocket::enable_recv_pktinfo(XorpFd* input_fd, bool is_enabled, string& error_msg)
{
switch (family()) {
case AF_INET:
@@ -1015,7 +1178,7 @@
//
#ifdef IP_RECVIF
// XXX: BSD
- if (setsockopt(_proto_socket_in, IPPROTO_IP, IP_RECVIF,
+ if (setsockopt(*input_fd, IPPROTO_IP, IP_RECVIF,
XORP_SOCKOPT_CAST(&bool_flag), sizeof(bool_flag)) < 0) {
XLOG_ERROR("setsockopt(IP_RECVIF, %u) failed: %s",
bool_flag, strerror(errno));
@@ -1025,7 +1188,7 @@
#ifdef IP_PKTINFO
// XXX: Linux
- if (setsockopt(_proto_socket_in, IPPROTO_IP, IP_PKTINFO,
+ if (setsockopt(*input_fd, IPPROTO_IP, IP_PKTINFO,
XORP_SOCKOPT_CAST(&bool_flag), sizeof(bool_flag)) < 0) {
XLOG_ERROR("setsockopt(IP_PKTINFO, %u) failed: %s",
bool_flag, strerror(errno));
@@ -1048,7 +1211,7 @@
//
#ifdef IPV6_RECVPKTINFO
// The new option (applies to receiving only)
- if (setsockopt(_proto_socket_in, IPPROTO_IPV6, IPV6_RECVPKTINFO,
+ if (setsockopt(*input_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
XORP_SOCKOPT_CAST(&bool_flag), sizeof(bool_flag)) < 0) {
error_msg = c_format("setsockopt(IPV6_RECVPKTINFO, %u) failed: %s",
bool_flag, strerror(errno));
@@ -1056,7 +1219,7 @@
}
#else
// The old option (see RFC-2292)
- if (setsockopt(_proto_socket_in, IPPROTO_IPV6, IPV6_PKTINFO,
+ if (setsockopt(*input_fd, IPPROTO_IPV6, IPV6_PKTINFO,
XORP_SOCKOPT_CAST(&bool_flag), sizeof(bool_flag)) < 0) {
error_msg = c_format("setsockopt(IPV6_PKTINFO, %u) failed: %s",
bool_flag, strerror(errno));
@@ -1068,14 +1231,14 @@
// Hop-limit field
//
#ifdef IPV6_RECVHOPLIMIT
- if (setsockopt(_proto_socket_in, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
+ if (setsockopt(*input_fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
XORP_SOCKOPT_CAST(&bool_flag), sizeof(bool_flag)) < 0) {
error_msg = c_format("setsockopt(IPV6_RECVHOPLIMIT, %u) failed: %s",
bool_flag, strerror(errno));
return (XORP_ERROR);
}
#else
- if (setsockopt(_proto_socket_in, IPPROTO_IPV6, IPV6_HOPLIMIT,
+ if (setsockopt(*input_fd, IPPROTO_IPV6, IPV6_HOPLIMIT,
XORP_SOCKOPT_CAST(&bool_flag), sizeof(bool_flag)) < 0) {
error_msg = c_format("setsockopt(IPV6_HOPLIMIT, %u) failed: %s",
bool_flag, strerror(errno));
@@ -1087,7 +1250,7 @@
// Traffic class value
//
#ifdef IPV6_RECVTCLASS
- if (setsockopt(_proto_socket_in, IPPROTO_IPV6, IPV6_RECVTCLASS,
+ if (setsockopt(*input_fd, IPPROTO_IPV6, IPV6_RECVTCLASS,
XORP_SOCKOPT_CAST(&bool_flag), sizeof(bool_flag)) < 0) {
error_msg = c_format("setsockopt(IPV6_RECVTCLASS, %u) failed: %s",
bool_flag, strerror(errno));
@@ -1099,14 +1262,14 @@
// Hop-by-hop options
//
#ifdef IPV6_RECVHOPOPTS
- if (setsockopt(_proto_socket_in, IPPROTO_IPV6, IPV6_RECVHOPOPTS,
+ if (setsockopt(*input_fd, IPPROTO_IPV6, IPV6_RECVHOPOPTS,
XORP_SOCKOPT_CAST(&bool_flag), sizeof(bool_flag)) < 0) {
error_msg = c_format("setsockopt(IPV6_RECVHOPOPTS, %u) failed: %s",
bool_flag, strerror(errno));
return (XORP_ERROR);
}
#else
- if (setsockopt(_proto_socket_in, IPPROTO_IPV6, IPV6_HOPOPTS,
+ if (setsockopt(*input_fd, IPPROTO_IPV6, IPV6_HOPOPTS,
XORP_SOCKOPT_CAST(&bool_flag), sizeof(bool_flag)) < 0) {
error_msg = c_format("setsockopt(IPV6_HOPOPTS, %u) failed: %s",
bool_flag, strerror(errno));
@@ -1118,14 +1281,14 @@
// Routing header options
//
#ifdef IPV6_RECVRTHDR
- if (setsockopt(_proto_socket_in, IPPROTO_IPV6, IPV6_RECVRTHDR,
+ if (setsockopt(*input_fd, IPPROTO_IPV6, IPV6_RECVRTHDR,
XORP_SOCKOPT_CAST(&bool_flag), sizeof(bool_flag)) < 0) {
error_msg = c_format("setsockopt(IPV6_RECVRTHDR, %u) failed: %s",
bool_flag, strerror(errno));
return (XORP_ERROR);
}
#else
- if (setsockopt(_proto_socket_in, IPPROTO_IPV6, IPV6_RTHDR,
+ if (setsockopt(*input_fd, IPPROTO_IPV6, IPV6_RTHDR,
XORP_SOCKOPT_CAST(&bool_flag), sizeof(bool_flag)) < 0) {
error_msg = c_format("setsockopt(IPV6_RTHDR, %u) failed: %s",
bool_flag, strerror(errno));
@@ -1137,14 +1300,14 @@
// Destination options
//
#ifdef IPV6_RECVDSTOPTS
- if (setsockopt(_proto_socket_in, IPPROTO_IPV6, IPV6_RECVDSTOPTS,
+ if (setsockopt(*input_fd, IPPROTO_IPV6, IPV6_RECVDSTOPTS,
XORP_SOCKOPT_CAST(&bool_flag), sizeof(bool_flag)) < 0) {
error_msg = c_format("setsockopt(IPV6_RECVDSTOPTS, %u) failed: %s",
bool_flag, strerror(errno));
return (XORP_ERROR);
}
#else
- if (setsockopt(_proto_socket_in, IPPROTO_IPV6, IPV6_DSTOPTS,
+ if (setsockopt(*input_fd, IPPROTO_IPV6, IPV6_DSTOPTS,
XORP_SOCKOPT_CAST(&bool_flag), sizeof(bool_flag)) < 0) {
error_msg = c_format("setsockopt(IPV6_DSTOPTS, %u) failed: %s",
bool_flag, strerror(errno));
@@ -1164,6 +1327,35 @@
return (XORP_OK);
}
+
+void IoIpSocket::notifyInterfaceDeleted(const string& ifname) {
+// Only clean up here if we are using BINDTODEVICE (ie, multiple input sockets)
+#ifdef SO_BINDTODEVICE
+ const IfTreeInterface* ifp = iftree().find_interface(ifname);
+ if (ifp) {
+ for (IfTreeInterface::VifMap::const_iterator i = ifp->vifs().begin(); i != ifp->vifs().end(); i++) {
+ string ifn = i->second.ifname();
+ string vn = i->second.vifname();
+ XorpFd* fd = findExistingInputSocket(ifn, vn);
+ if (fd) {
+ string key(ifn);
+ key += " ";
+ key += vn;
+ int _fd = (int)(*fd);
+
+ _proto_sockets_in.erase(key);
+ cleanupXorpFd(fd);
+
+ XLOG_INFO("Closed socket: %i on interface: %s:%s because its interface is being deleted, input sockets count: %i\n",
+ _fd, ifn.c_str(), vn.c_str(), _proto_sockets_in.size());
+
+ }
+ }
+ }
+#endif
+}
+
+
void
IoIpSocket::proto_socket_read(XorpFd fd, IoEventType type)
{
@@ -1210,12 +1402,12 @@
}
// Read from the socket
- nbytes = recvmsg(_proto_socket_in, &_rcvmh, 0);
+ nbytes = recvmsg(fd, &_rcvmh, 0);
if (nbytes < 0) {
if (errno == EINTR)
return; // OK: restart receiving
XLOG_ERROR("recvmsg() on socket %s failed: %s",
- _proto_socket_in.str().c_str(), strerror(errno));
+ fd.str().c_str(), strerror(errno));
return; // Error
}
@@ -1227,12 +1419,12 @@
struct sockaddr_storage from;
socklen_t from_len = sizeof(from);
- nbytes = recvfrom(_proto_socket_in, XORP_BUF_CAST(_rcvbuf),
+ nbytes = recvfrom(fd, XORP_BUF_CAST(_rcvbuf),
IO_BUF_SIZE, 0,
reinterpret_cast<struct sockaddr *>(&from),
&from_len);
debug_msg("Read fd %s, %d bytes\n",
- _proto_socket_in.str().c_str(), XORP_INT_CAST(nbytes));
+ fd.str().c_str(), XORP_INT_CAST(nbytes));
if (nbytes < 0) {
// XLOG_ERROR("recvfrom() failed: %s", strerror(errno));
return; // Error
@@ -1258,10 +1450,10 @@
XLOG_ERROR("lpWSARecvMsg is NULL");
return; // Error
}
- error = lpWSARecvMsg(_proto_socket_in, &mh, &nrecvd, NULL, NULL);
+ error = lpWSARecvMsg(fd, &mh, &nrecvd, NULL, NULL);
nbytes = (ssize_t)nrecvd;
debug_msg("Read fd %s, %d bytes\n",
- _proto_socket_in.str().c_str(), XORP_INT_CAST(nbytes));
+ fd.str().c_str(), XORP_INT_CAST(nbytes));
if (nbytes < 0) {
// XLOG_ERROR("lpWSARecvMsg() failed: %s", strerror(errno));
return; // Error
@@ -1751,7 +1943,7 @@
XLOG_WARNING("proto_socket_read() failed: "
"RX packet from %s to %s pif_index %u: no vif found",
cstring(src_address), cstring(dst_address), pif_index);
- return; // Error
+ return;// Error
}
if (! (ifp->enabled() || vifp->enabled())) {
// This vif is down. Silently ignore this packet.
Index: data_plane/io/io_ip_socket.hh
===================================================================
RCS file: /cvs/xorp/fea/data_plane/io/io_ip_socket.hh,v
retrieving revision 1.10
diff -u -r1.10 io_ip_socket.hh
--- data_plane/io/io_ip_socket.hh 4 Jan 2008 03:16:14 -0000 1.10
+++ data_plane/io/io_ip_socket.hh 2 Mar 2008 19:26:27 -0000
@@ -180,12 +180,18 @@
string& error_msg);
/**
- * Get the file descriptor for receiving protocol messages.
+ * Get the file descriptor for receiving protocol messages on the specified vif.
*
* @return a reference to the file descriptor for receiving protocol
* messages.
*/
- XorpFd& protocol_fd_in() { return (_proto_socket_in); }
+ XorpFd* findExistingInputSocket(const string& if_name, const string& vif_name);
+
+ /** Get the input file descriptor to be used for multicast routing. This
+ * should not be bound to any specific interface. Returns NULL if cannot
+ * find or create one.
+ */
+ XorpFd* mcast_protocol_fd_in();
private:
/**
@@ -199,6 +205,16 @@
*/
int open_proto_sockets(string& error_msg);
+
+ /** Returns XORP_ERROR on error. */
+ int initializeInputSocket(XorpFd* rv, string& error_msg);
+
+ /** Find or create an input socket for the specified VIF. Returns NULL
+ * if the socket cannot be found or created.
+ */
+ XorpFd* findOrCreateInputSocket(const string& if_name, const string& vif_name,
+ string& error_msg);
+
/**
* Close the protocol sockets.
*
@@ -207,6 +223,15 @@
*/
int close_proto_sockets(string& error_msg);
+ /** Helper method to close a single socket. Does not remove from
+ * socket map structure. Deletes memory associated with 'fd'.
+ */
+ int cleanupXorpFd(XorpFd* fd);
+
+
+ /** Interface is going away..clean up the sockets for the associated vif(s) */
+ void notifyInterfaceDeleted(const string& ifname);
+
/**
* Enable/disable the "Header Included" option (for IPv4) on the outgoing
* protocol socket.
@@ -239,7 +264,7 @@
* @param error_msg the error message (if error).
* @return XORP_OK on success, otherwise XORP_ERROR.
*/
- int enable_recv_pktinfo(bool is_enabled, string& error_msg);
+ int enable_recv_pktinfo(XorpFd* input_fd, bool is_enabled, string& error_msg);
/**
* Read data from a protocol socket, and then call the appropriate protocol
@@ -269,7 +294,10 @@
string& error_msg);
// Private state
- XorpFd _proto_socket_in; // The socket to receive protocol message
+ //XorpFd _proto_socket_in; // The socket to receive protocol message
+ // The key is "if_name vif_name"
+ map<string, XorpFd*> _proto_sockets_in;
+ XorpFd _mcast_proto_socket_in;
XorpFd _proto_socket_out; // The socket to end protocol message
bool _is_ip_hdr_included; // True if IP header is included on send
uint16_t _ip_id; // IPv4 Header ID
_______________________________________________
Xorp-hackers mailing list
[email protected]
http://mailman.ICSI.Berkeley.EDU/mailman/listinfo/xorp-hackers