An updated patch is attached. This patch also includes
logic to clean up multicast bindings on interface removal
and code to set the rx buffer for the tx-only socket very
small.
The multicast changes fix a race in interface removal
(iface is removed before OSPF notices and removes the
multicast binds, and since the iface is gone, fea can no
longer run the unbind logic.) This is probably less
critical when running one socket per iface, since the
entire socket will already be cleaned up.
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.cc
===================================================================
RCS file: /cvs/xorp/fea/ifconfig.cc,v
retrieving revision 1.82
diff -u -r1.82 ifconfig.cc
--- ifconfig.cc 9 Mar 2008 00:21:16 -0000 1.82
+++ ifconfig.cc 12 Mar 2008 00:16:42 -0000
@@ -737,6 +737,9 @@
return ret_value;
}
+// TODO: This can be costly when you have lots of interfaces, so try to
+// optimize things so this is called rarely. Currently it is called
+// several times on startup of fea.
const IfTree&
IfConfig::pull_config()
{
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 12 Mar 2008 00:16:42 -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.17
diff -u -r1.17 ifconfig_transaction.hh
--- ifconfig_transaction.hh 9 Mar 2008 00:21:16 -0000 1.17
+++ ifconfig_transaction.hh 12 Mar 2008 00:16:43 -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 12 Mar 2008 00:16:43 -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 12 Mar 2008 00:16:45 -0000
@@ -324,6 +324,10 @@
ret_value = XORP_ERROR;
if (! error_msg.empty())
error_msg += " ";
+ error_msg += c_format("Error while sending to vif: %s:%s src: %s dest: %s: ",
+ if_name.c_str(), vif_name.c_str(),
+ src_address.str().c_str(),
+ dst_address.str().c_str());
error_msg += error_msg2;
}
}
@@ -457,6 +461,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 +696,7 @@
}
XorpFd
-IoIpComm::first_valid_protocol_fd_in()
+IoIpComm::first_valid_mcast_protocol_fd_in()
{
XorpFd xorp_fd;
@@ -651,7 +704,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 +1058,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 +1127,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 +1167,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 +1184,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 12 Mar 2008 00:16:46 -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.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 12 Mar 2008 00:16:48 -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.38
diff -u -r1.38 xrl_fea_target.cc
--- xrl_fea_target.cc 9 Mar 2008 00:21:16 -0000 1.38
+++ xrl_fea_target.cc 12 Mar 2008 00:16:52 -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),
@@ -2827,6 +2849,7 @@
ext_headers_payload_vector,
payload, error_msg)
!= XORP_OK) {
+ assert(error_msg.size()); // don't allow empty error messages.
return XrlCmdError::COMMAND_FAILED(error_msg);
}
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 12 Mar 2008 00:16:54 -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.14
diff -u -r1.14 netlink_socket_utilities.cc
--- data_plane/control_socket/netlink_socket_utilities.cc 9 Mar 2008 00:21:17 -0000 1.14
+++ data_plane/control_socket/netlink_socket_utilities.cc 12 Mar 2008 00:16:55 -0000
@@ -364,11 +364,12 @@
// enough evidence and the issue is understood.
//
IPvXNet dst_subnet(dst_addr, dst_mask_len);
- XLOG_FATAL("Decoding for route %s next hop %s failed: "
+ XLOG_ERROR("ERROR: Decoding for route %s next hop %s failed: "
"could not find interface and vif for index %d",
dst_subnet.str().c_str(),
nexthop_addr.str().c_str(),
if_index);
+ return XORP_ERROR;
}
}
}
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 12 Mar 2008 00:16:56 -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 12 Mar 2008 00:16:58 -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 12 Mar 2008 00:16:58 -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.19
diff -u -r1.19 io_ip_socket.cc
--- data_plane/io/io_ip_socket.cc 9 Mar 2008 07:04:06 -0000 1.19
+++ data_plane/io/io_ip_socket.cc 12 Mar 2008 00:17:01 -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,74 @@
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() {
+#ifdef USE_SOCKET_PER_IFACE
+ 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;
+#else
+ string nll;
+ // Just grabs first and only socket when USE_SOCKET_PER_IFACE is not defined.
+ return findExistingInputSocket(nll, nll);
+#endif
+}
+
+
+XorpFd* IoIpSocket::findExistingInputSocket(const string& if_name, const string& vif_name) {
+#ifdef USE_SOCKET_PER_IFACE
+ string k(if_name);
+ k += " ";
+ k += vif_name;
+ map<string, XorpFd*>::iterator i = _proto_sockets_in.find(k);
+#else
+ UNUSED(if_name);
+ UNUSED(vif_name);
+ 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 +700,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 +738,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 +750,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 +771,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 +795,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 +823,49 @@
#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 USE_SOCKET_PER_IFACE
+#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
+#endif
}
+ return rv;
+}
+
+
+int IoIpSocket::initializeInputSocket(XorpFd* rv, string& error_msg) {
+
#ifdef HOST_OS_WINDOWS
switch (family()) {
case AF_INET:
@@ -758,7 +878,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 +897,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 +914,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 +924,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_sndbuf(_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 +968,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 +980,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 +995,82 @@
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_sndbuf(_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);
+ }
+
+ // Very small input buffering, as we never read this, but don't fail if
+ // we can't...it just wastes a bit of memory.
+ comm_sock_set_rcvbuf(_proto_socket_out, 2000, 2000);
+
+ // 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 +1090,32 @@
_proto_socket_out.clear();
}
+#ifdef USE_SOCKET_PER_IFACE
+ if (_mcast_proto_socket_in.is_valid()) {
+ comm_close(_mcast_proto_socket_in);
+ _mcast_proto_socket_in.clear();
+ }
+#endif
+
+ 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 +1134,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 +1182,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 +1195,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 +1205,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 +1228,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 +1236,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 +1248,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 +1267,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 +1279,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 +1298,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 +1317,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 +1344,37 @@
return (XORP_OK);
}
+
+void IoIpSocket::notifyInterfaceDeleted(const string& ifname) {
+// Only clean up here if we are using multiple input sockets.
+#ifdef USE_SOCKET_PER_IFACE
+ 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());
+
+ }
+ }
+ }
+#else
+ UNUSED(ifname);
+#endif
+}
+
+
void
IoIpSocket::proto_socket_read(XorpFd fd, IoEventType type)
{
@@ -1210,12 +1421,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 +1438,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 +1469,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
@@ -1748,10 +1959,23 @@
if ((ifp == NULL) || (vifp == NULL)) {
// No vif found. Ignore this packet.
+#ifdef USE_SOCKET_PER_IFACE
+ // Don't expect this to happen, so log all errors.
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
+#else
+ // On a multi-port system, one can rx pkts for devices not in use by this system,
+ // so don't print the error messages so often.
+ static int bad_vifs = 0;
+ if ((bad_vifs++ % 1000) == 0) {
+ XLOG_WARNING("proto_socket_read(), total bad_vifs: %i: "
+ "RX packets from %s to %s pif_index %u: no vif found",
+ bad_vifs, cstring(src_address), cstring(dst_address),
+ pif_index);
+ }
+#endif
+ return;// Error
}
if (! (ifp->enabled() || vifp->enabled())) {
// This vif is down. Silently ignore this packet.
@@ -1956,6 +2180,7 @@
if (enable_ip_hdr_include(do_ip_hdr_include, error_msg)
!= XORP_OK) {
XLOG_ERROR("%s", error_msg.c_str());
+ assert(error_msg.size());
return (XORP_ERROR);
}
}
@@ -2097,6 +2322,7 @@
ip4.set_ip_id(_ip_id);
if (ip4.fragment(ifp->mtu(), fragments, false, error_msg)
!= XORP_OK) {
+ assert(error_msg.size());
return (XORP_ERROR);
}
XLOG_ASSERT(! fragments.empty());
@@ -2450,6 +2676,8 @@
// TODO: check the interface status.
// E.g., vif_state_check(family());
//
+ error_msg = c_format("sendmsg failed, error: %s socket: %i",
+ strerror(errno), (int)(_proto_socket_out));
} else {
error_msg = c_format("sendmsg(proto %d size %u from %s to %s "
"on interface %s vif %s) failed: %s",
@@ -2538,6 +2766,9 @@
#endif // SO_BINDTODEVICE
}
+ if (ret_value != XORP_OK) {
+ assert(error_msg.size());
+ }
return (ret_value);
}
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 12 Mar 2008 00:17:02 -0000
@@ -33,6 +33,13 @@
#include "fea/io_ip.hh"
+// Shall we use one socket per interface for receiving? Defaulting
+// to enabled for Linux (its the only thing that supports SO_BINDTODEVICE it seems.)
+#ifdef SO_BINDTODEVICE
+#define USE_SOCKET_PER_IFACE
+#endif
+
+
/**
* @short A base class for I/O IP raw socket communication.
*
@@ -180,12 +187,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 +212,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 +230,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 +271,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 +301,12 @@
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;
+#ifdef USE_SOCKET_PER_IFACE
+ XorpFd _mcast_proto_socket_in;
+#endif
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