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

Reply via email to