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

From: Dan Eble (dane@aiinet.com)
Date: Fri Jan 31 2003 - 16:41:21 EST


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/     |__/|_|_|

- To unsubscribe from this list: 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



This archive was generated by hypermail 2b29 : Fri Jan 31 2003 - 22:00:02 EST