[patch] A more general way to hook into the rx path.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Greetings everyone,

The following change (against ppclinux 2.4.18pre2 --sorry that's what I'm
working on right now) removes the bridge driver's global hook and replaces 
it with a device-specific function.

With this change, any driver which defines net_device.recv_from_slave()
and calls netdev_set_master(slave, self) has the opportunity to process
the packets received by the slave device.

This method seemed more flexible than adding a global hook for my own
driver.  Please let me know what you think.  A simple "this looks good" or
"it has the following problems..." would be greatly appreciated.

diff -wbBurN linux-GPL.orig/drivers/net/bonding.c linux-GPL/drivers/net/bonding.c
--- linux-GPL.orig/drivers/net/bonding.c	Fri May  3 13:49:25 2002
+++ linux-GPL/drivers/net/bonding.c	Wed Jan 29 13:31:21 2003
@@ -504,7 +504,7 @@
 	}
 	memset(new_slave, 0, sizeof(slave_t));
 
-	err = netdev_set_master(slave_dev, master_dev);
+	err = netdev_set_master(slave_dev, master_dev, NULL);
 
 	if (err) {
 #ifdef BONDING_DEBUG
@@ -833,7 +833,7 @@
 
 			/* release the slave from its bond */
 			 
-			netdev_set_master(slave, NULL);
+			netdev_set_master(slave, NULL, NULL);
 
 			/* only restore its RUNNING flag if monitoring set it down */
 			if (slave->flags & IFF_UP) {
diff -wbBurN linux-GPL.orig/include/linux/if_bridge.h linux-GPL/include/linux/if_bridge.h
--- linux-GPL.orig/include/linux/if_bridge.h	Wed Jan 22 13:47:27 2003
+++ linux-GPL/include/linux/if_bridge.h	Thu Jan 30 16:16:03 2003
@@ -102,7 +102,6 @@
 struct net_bridge_port;
 
 extern int (*br_ioctl_hook)(unsigned long arg);
-extern void (*br_handle_frame_hook)(struct sk_buff *skb);
 
 #endif
 
diff -wbBurN linux-GPL.orig/include/linux/netdevice.h linux-GPL/include/linux/netdevice.h
--- linux-GPL.orig/include/linux/netdevice.h	Wed Jan 22 13:46:26 2003
+++ linux-GPL/include/linux/netdevice.h	Thu Jan 30 16:12:24 2003
@@ -303,6 +303,7 @@
 	struct net_device	*master; /* Pointer to master device of a group,
 					  * which this device is member of.
 					  */
+	void			*master_priv; /* for use by master device */
 
 	/* Interface address info. */
 	unsigned char		broadcast[MAX_ADDR_LEN];	/* hw bcast add	*/
@@ -371,6 +372,7 @@
 						void *saddr,
 						unsigned len);
 	int			(*rebuild_header)(struct sk_buff *skb);
+	void			(*recv_from_slave)(struct sk_buff *skb);
 #define HAVE_MULTICAST			 
 	void			(*set_multicast_list)(struct net_device *dev);
 #define HAVE_SET_MAC_ADDR  		 
@@ -402,9 +404,6 @@
 	/* open/release and usage marking */
 	struct module *owner;
 
-	/* bridge stuff */
-	struct net_bridge_port	*br_port;
-
 #ifdef CONFIG_NET_FASTROUTE
 #define NETDEV_FASTROUTE_HMASK 0xF
 	/* Semi-private data. Keep it at the end of device struct. */
@@ -709,7 +708,7 @@
 extern int		netdev_max_backlog;
 extern unsigned long	netdev_fc_xoff;
 extern atomic_t netdev_dropping;
-extern int		netdev_set_master(struct net_device *dev, struct net_device *master);
+extern int		netdev_set_master(struct net_device *dev, struct net_device *master, void *master_priv);
 extern struct sk_buff * skb_checksum_help(struct sk_buff *skb);
 #ifdef CONFIG_NET_FASTROUTE
 extern int		netdev_fastroute;
diff -wbBurN linux-GPL.orig/net/bridge/br.c linux-GPL/net/bridge/br.c
--- linux-GPL.orig/net/bridge/br.c	Fri May  3 13:49:45 2002
+++ linux-GPL/net/bridge/br.c	Wed Jan 29 09:42:09 2003
@@ -42,7 +42,6 @@
 {
 	printk(KERN_INFO "NET4: Ethernet Bridge 008 for NET4.0\n");
 
-	br_handle_frame_hook = br_handle_frame;
 #ifdef CONFIG_INET
 	br_ioctl_hook = br_ioctl_deviceless_stub;
 #endif
@@ -55,11 +54,6 @@
 	return 0;
 }
 
-static void __br_clear_frame_hook(void)
-{
-	br_handle_frame_hook = NULL;
-}
-
 static void __br_clear_ioctl_hook(void)
 {
 #ifdef CONFIG_INET
@@ -71,7 +65,6 @@
 {
 	unregister_netdevice_notifier(&br_device_notifier);
 	br_call_ioctl_atomic(__br_clear_ioctl_hook);
-	net_call_rx_atomic(__br_clear_frame_hook);
 #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
 	br_fdb_get_hook = NULL;
 	br_fdb_put_hook = NULL;
diff -wbBurN linux-GPL.orig/net/bridge/br_device.c linux-GPL/net/bridge/br_device.c
--- linux-GPL.orig/net/bridge/br_device.c	Fri May  3 13:49:45 2002
+++ linux-GPL/net/bridge/br_device.c	Thu Jan 30 13:56:31 2003
@@ -128,6 +128,7 @@
 	dev->do_ioctl = br_dev_do_ioctl;
 	dev->get_stats = br_dev_get_stats;
 	dev->hard_start_xmit = br_dev_xmit;
+	dev->recv_from_slave = br_handle_frame;
 	dev->open = br_dev_open;
 	dev->set_multicast_list = br_dev_set_multicast_list;
 	dev->stop = br_dev_stop;
diff -wbBurN linux-GPL.orig/net/bridge/br_if.c linux-GPL/net/bridge/br_if.c
--- linux-GPL.orig/net/bridge/br_if.c	Fri May  3 13:49:45 2002
+++ linux-GPL/net/bridge/br_if.c	Fri Jan 31 09:16:14 2003
@@ -43,13 +43,23 @@
 	struct net_bridge_port *p;
 	struct net_bridge_port **pptr;
 
-	if ((p = dev->br_port) == NULL)
+	if ((p = dev->master_priv) == NULL)
 		return -EINVAL;
 
 	br_stp_disable_port(p);
 
 	dev_set_promiscuity(dev, -1);
-	dev->br_port = NULL;
+
+#if 0
+	/* This yields "alloc_skb called nonatomically from interrupt". */
+	netdev_set_master(dev, NULL, NULL);
+#else
+	/* This is the essence of netdev_set_master() but without the locks and
+	 * rtmsg_ifinfo(RTM_NEWLINK...) call. */
+	dev->flags &= ~IFF_SLAVE;
+	dev->master = NULL;
+	dev->master_priv = NULL;
+#endif
 
 	pptr = &br->port_list;
 	while (*pptr != NULL) {
@@ -150,8 +160,6 @@
 	p->path_cost = br_initial_port_cost(dev);
 	p->priority = 0x80;
 
-	dev->br_port = p;
-
 	for (i=1;i<255;i++)
 		if (br_get_port(br, i) == NULL)
 			break;
@@ -161,6 +169,17 @@
 		return NULL;
 	}
 
+#if 0
+	/* This yields "alloc_skb called nonatomically from interrupt". */
+	netdev_set_master(dev, &br->dev, p);
+#else
+	/* This is the essence of netdev_set_master() but without the locks and
+	 * rtmsg_ifinfo(RTM_NEWLINK...) call. */
+	dev->master_priv = p;
+	dev->master = &br->dev;
+	dev->flags |= IFF_SLAVE;
+#endif
+
 	p->port_no = i;
 	br_init_port(p);
 	p->state = BR_STATE_DISABLED;
@@ -220,7 +239,7 @@
 {
 	struct net_bridge_port *p;
 
-	if (dev->br_port != NULL)
+	if (dev->master_priv != NULL)
 		return -EBUSY;
 
 	if (dev->flags & IFF_LOOPBACK || dev->type != ARPHRD_ETHER)
diff -wbBurN linux-GPL.orig/net/bridge/br_input.c linux-GPL/net/bridge/br_input.c
--- linux-GPL.orig/net/bridge/br_input.c	Fri May  3 13:49:45 2002
+++ linux-GPL/net/bridge/br_input.c	Wed Jan 29 13:28:37 2003
@@ -56,7 +56,7 @@
 
 	dest = skb->mac.ethernet->h_dest;
 
-	p = skb->dev->br_port;
+	p = skb->dev->master_priv;
 	br = p->br;
 	passedup = 0;
 
@@ -144,7 +144,7 @@
 {
 	struct net_bridge *br;
 
-	br = skb->dev->br_port->br;
+	br = ((struct net_bridge_port*)skb->dev->master_priv)->br;
 	read_lock(&br->lock);
 	__br_handle_frame(skb);
 	read_unlock(&br->lock);
diff -wbBurN linux-GPL.orig/net/bridge/br_notify.c linux-GPL/net/bridge/br_notify.c
--- linux-GPL.orig/net/bridge/br_notify.c	Fri May  3 13:49:45 2002
+++ linux-GPL/net/bridge/br_notify.c	Tue Jan 28 15:00:19 2003
@@ -32,7 +32,7 @@
 	struct net_bridge_port *p;
 
 	dev = ptr;
-	p = dev->br_port;
+	p = dev->master_priv;
 
 	if (p == NULL)
 		return NOTIFY_DONE;
@@ -53,7 +53,7 @@
 	case NETDEV_DOWN:
 		if (p->br->dev.flags & IFF_UP) {
 			read_lock(&p->br->lock);
-			br_stp_disable_port(dev->br_port);
+			br_stp_disable_port(p);
 			read_unlock(&p->br->lock);
 		}
 		break;
@@ -61,13 +61,13 @@
 	case NETDEV_UP:
 		if (p->br->dev.flags & IFF_UP) {
 			read_lock(&p->br->lock);
-			br_stp_enable_port(dev->br_port);
+			br_stp_enable_port(p);
 			read_unlock(&p->br->lock);
 		}
 		break;
 
 	case NETDEV_UNREGISTER:
-		br_del_if(dev->br_port->br, dev);
+		br_del_if(p->br, dev);
 		break;
 	}
 
diff -wbBurN linux-GPL.orig/net/bridge/br_stp_bpdu.c linux-GPL/net/bridge/br_stp_bpdu.c
--- linux-GPL.orig/net/bridge/br_stp_bpdu.c	Fri May  3 13:49:45 2002
+++ linux-GPL/net/bridge/br_stp_bpdu.c	Tue Jan 28 15:00:55 2003
@@ -139,7 +139,7 @@
 	struct net_bridge_port *p;
 
 	buf = skb->mac.raw + 14;
-	p = skb->dev->br_port;
+	p = skb->dev->master_priv;
 	if (!p->br->stp_enabled || memcmp(buf, header, 6)) {
 		kfree_skb(skb);
 		return;
diff -wbBurN linux-GPL.orig/net/core/dev.c linux-GPL/net/core/dev.c
--- linux-GPL.orig/net/core/dev.c	Fri May  3 13:49:45 2002
+++ linux-GPL/net/core/dev.c	Fri Jan 31 15:46:21 2003
@@ -1307,15 +1307,15 @@
 	return ret;
 }
 
-/* Reparent skb to master device. This function is called
- * only from net_rx_action under BR_NETPROTO_LOCK. It is misuse
- * of BR_NETPROTO_LOCK, but it is OK for now.
+/* If the master device has no recv_from_slave() handler, just reparent skb to
+ * the master device. This function is called only from net_rx_action under
+ * BR_NETPROTO_LOCK. It is misuse of BR_NETPROTO_LOCK, but it is OK for now.
  */
 static __inline__ void skb_bond(struct sk_buff *skb)
 {
 	struct net_device *dev = skb->dev;
 	
-	if (dev->master) {
+	if (dev->master && !dev->master->recv_from_slave) {
 		dev_hold(dev->master);
 		skb->dev = dev->master;
 		dev_put(dev);
@@ -1383,11 +1383,7 @@
 	br_write_unlock_bh(BR_NETPROTO_LOCK);
 }
 
-#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
-void (*br_handle_frame_hook)(struct sk_buff *skb) = NULL;
-#endif
-
-static __inline__ int handle_bridge(struct sk_buff *skb,
+static __inline__ int handle_master_recv(struct sk_buff *skb,
 				     struct packet_type *pt_prev)
 {
 	int ret = NET_RX_DROP;
@@ -1401,7 +1397,7 @@
 		}
 	}
 
-	br_handle_frame_hook(skb);
+	skb->dev->master->recv_from_slave(skb);
 	return ret;
 }
 
@@ -1476,14 +1472,12 @@
 #endif /* CONFIG_NET_DIVERT */
 
 			
-#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
-			if (skb->dev->br_port != NULL &&
-			    br_handle_frame_hook != NULL) {
-				handle_bridge(skb, pt_prev);
+			if (skb->dev->master != NULL
+			    && skb->dev->master->recv_from_slave != NULL) {
+				handle_master_recv(skb, pt_prev);
 				dev_put(rx_dev);
 				continue;
 			}
-#endif
 
 			for (ptype=ptype_base[ntohs(type)&15];ptype;ptype=ptype->next) {
 				if (ptype->type == type &&
@@ -1916,6 +1910,7 @@
  *	netdev_set_master	-	set up master/slave pair
  *	@slave: slave device
  *	@master: new master device
+ *	@master_priv: private data for master device
  *
  *	Changes the master device of the slave. Pass %NULL to break the
  *	bonding. The caller must hold the RTNL semaphore. On a failure
@@ -1924,7 +1919,8 @@
  *	function returns zero.
  */
  
-int netdev_set_master(struct net_device *slave, struct net_device *master)
+int netdev_set_master(struct net_device *slave,
+		      struct net_device *master, void *master_priv)
 {
 	struct net_device *old = slave->master;
 
@@ -1938,16 +1934,18 @@
 
 	br_write_lock_bh(BR_NETPROTO_LOCK);
 	slave->master = master;
+	if (master) {
+		slave->master_priv = master_priv;
+		slave->flags |= IFF_SLAVE;
+	} else {
+		slave->master_priv = NULL;
+		slave->flags &= ~IFF_SLAVE;
+	}
 	br_write_unlock_bh(BR_NETPROTO_LOCK);
 
 	if (old)
 		dev_put(old);
 
-	if (master)
-		slave->flags |= IFF_SLAVE;
-	else
-		slave->flags &= ~IFF_SLAVE;
-
 	rtmsg_ifinfo(RTM_NEWLINK, slave, IFF_SLAVE);
 	return 0;
 }
diff -wbBurN linux-GPL.orig/net/netsyms.c linux-GPL/net/netsyms.c
--- linux-GPL.orig/net/netsyms.c	Thu Sep  5 08:05:15 2002
+++ linux-GPL/net/netsyms.c	Wed Jan 29 09:40:44 2003
@@ -227,7 +227,6 @@
 EXPORT_SYMBOL(scm_detach_fds);
 
 #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
-EXPORT_SYMBOL(br_handle_frame_hook);
 #ifdef CONFIG_INET
 EXPORT_SYMBOL(br_ioctl_hook);
 #endif

-- 
Dan Eble <dane@aiinet.com>  _____  .
                           |  _  |/|
Applied Innovation Inc.    | |_| | |
http://www.aiinet.com/     |__/|_|_|

-
: send the line "unsubscribe linux-net" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux 802.1Q VLAN]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Git]     [Bugtraq]     [Yosemite News and Information]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux PCI]     [Linux Admin]     [Samba]

  Powered by Linux