lkml.org 
[lkml]   [2000]   [Aug]   [24]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subject[PATCH] Re: dev_mc_lock question.
Hi,

kuznet@ms2.inr.ac.ru wrote:
>
[...]
>
> Yes, I want patch. Also, could you look into drivers/net/bonding.c
> and kill that shit, which is made in its set_multicast_list()?
>

The attached patch fixes set_multicast_list() in bonding device. My
previous patch (that removes dev_mc_lock) should be applied before this
one, otherwise you'll get deadlock on smp.

--
Gleb.diff -urN -X exclude 2.4.0-test7-pre7/drivers/net/bonding.c 2.4.0-test7-pre7-bond/drivers/net/bonding.c
--- 2.4.0-test7-pre7/drivers/net/bonding.c Thu Jul 6 08:15:27 2000
+++ 2.4.0-test7-pre7-bond/drivers/net/bonding.c Thu Aug 24 16:19:13 2000
@@ -28,7 +28,10 @@
*
* v0.1 - first working version.
* v0.2 - changed stats to be calculated by summing slaves stats.
- *
+ *
+ * Fixes:
+ * Gleb Natapov : multicast handling fixed,
+ * emulation of promiscuity & allmulti added
*/

#include <linux/kernel.h>
@@ -71,6 +74,8 @@

slave_t *current_slave;
struct net_device_stats stats;
+ struct dev_mc_list *mc_list;
+ unsigned short flags;
} bonding_t;


@@ -94,6 +99,18 @@
bond->current_slave = slave->next;
slave->next->prev = slave->prev;
slave->prev->next = slave->next;
+
+ /* flush master's mc_list from slave */
+ dev_mc_list_flush (slave->dev, master->mc_list);
+
+ /* unset promiscuity level from slave */
+ if(master->flags & IFF_PROMISC)
+ dev_set_promiscuity(slave->dev, -1);
+
+ /* unset allmulti level from slave */
+ if(master->flags & IFF_ALLMULTI)
+ dev_set_allmulti(slave->dev, -1);
+
spin_unlock_bh(&master->xmit_lock);

netdev_set_master(slave->dev, NULL);
@@ -111,21 +128,81 @@
while ((slave = bond->next) != (slave_t*)bond)
release_one_slave(master, slave);

+ dev_mc_list_destroy (&bond->mc_list);
MOD_DEC_USE_COUNT;
return 0;
}

+static void bond_mc_add(bonding_t *bond, void *addr, int alen)
+{
+ slave_t *slave;
+
+ for (slave = bond->next; slave != (slave_t*)bond; slave = slave->next)
+ dev_mc_add(slave->dev, addr, alen, 0);
+}
+
+static void bond_mc_delete(bonding_t *bond, void *addr, int alen)
+{
+ slave_t *slave;
+
+ for (slave = bond->next; slave != (slave_t*)bond; slave = slave->next)
+ dev_mc_delete(slave->dev, addr, alen, 0);
+}
+
+static void bond_set_promiscuity(bonding_t *bond, int inc)
+{
+ slave_t *slave;
+
+ for (slave = bond->next; slave != (slave_t*)bond; slave = slave->next)
+ dev_set_promiscuity(slave->dev, inc);
+}
+
+static void bond_set_allmulti(bonding_t *bond, int inc)
+{
+ slave_t *slave;
+
+ for (slave = bond->next; slave != (slave_t*)bond; slave = slave->next)
+ dev_set_allmulti(slave->dev, inc);
+}
+
static void bond_set_multicast_list(struct net_device *master)
{
bonding_t *bond = master->priv;
- slave_t *slave;
+ struct dev_mc_list *dmi;
+

- for (slave = bond->next; slave != (slave_t*)bond; slave = slave->next) {
- slave->dev->mc_list = master->mc_list;
- slave->dev->mc_count = master->mc_count;
- slave->dev->flags = master->flags;
- slave->dev->set_multicast_list(slave->dev);
+ /* set promiscuity flag to slaves */
+ if( (master->flags & IFF_PROMISC) && !(bond->flags & IFF_PROMISC) )
+ bond_set_promiscuity(bond, 1);
+
+ if( !(master->flags & IFF_PROMISC) && (bond->flags & IFF_PROMISC) )
+ bond_set_promiscuity(bond, -1);
+
+ /* set allmulti flag to slaves */
+ if( (master->flags & IFF_ALLMULTI) && !(bond->flags & IFF_ALLMULTI) )
+ bond_set_allmulti(bond, 1);
+
+ if( !(master->flags & IFF_ALLMULTI) && (bond->flags & IFF_ALLMULTI) )
+ bond_set_allmulti(bond, -1);
+
+ bond->flags = master->flags;
+
+ /* looking for addresses to add to slaves' mc list */
+ for(dmi=master->mc_list; dmi!=NULL; dmi=dmi->next) {
+ if(dev_mc_list_find_dmi(dmi, bond->mc_list) == NULL)
+ bond_mc_add(bond, dmi->dmi_addr, dmi->dmi_addrlen);
+
}
+
+ /* looking for addresses to delete from slaves' list */
+ for(dmi=bond->mc_list; dmi!=NULL; dmi=dmi->next) {
+ if(dev_mc_list_find_dmi(dmi, master->mc_list) == NULL)
+ bond_mc_delete(bond, dmi->dmi_addr, dmi->dmi_addrlen);
+ }
+
+ /* save master's multicast list */
+ dev_mc_list_destroy (&bond->mc_list);
+ dev_mc_list_copy (master->mc_list, &bond->mc_list, GFP_KERNEL);
}

static int bond_enslave(struct net_device *master, struct net_device *dev)
@@ -133,7 +210,8 @@
int err;
bonding_t *bond = master->priv;
slave_t *slave;
-
+ struct dev_mc_list *dmi;
+
if (dev->type != master->type)
return -ENODEV;

@@ -151,6 +229,18 @@
slave->dev = dev;

spin_lock_bh(&master->xmit_lock);
+
+ /* set promiscuity level to new slave */
+ if(master->flags & IFF_PROMISC)
+ dev_set_promiscuity(dev, 1);
+
+ /* set allmulti level to new slave */
+ if(master->flags & IFF_ALLMULTI)
+ dev_set_allmulti(dev, 1);
+
+ /* upload master's mc_list to new slave */
+ for(dmi=master->mc_list; dmi!=NULL; dmi=dmi->next)
+ dev_mc_add (dev, dmi->dmi_addr, dmi->dmi_addrlen, 0);

dev_hold(dev);

diff -urN -X exclude 2.4.0-test7-pre7/include/linux/netdevice.h 2.4.0-test7-pre7-bond/include/linux/netdevice.h
--- 2.4.0-test7-pre7/include/linux/netdevice.h Thu Aug 24 13:50:48 2000
+++ 2.4.0-test7-pre7-bond/include/linux/netdevice.h Thu Aug 24 14:22:06 2000
@@ -619,6 +619,10 @@
extern int dev_mc_delete(struct net_device *dev, void *addr, int alen, int all);
extern int dev_mc_add(struct net_device *dev, void *addr, int alen, int newonly);
extern void dev_mc_discard(struct net_device *dev);
+extern struct dev_mc_list* dev_mc_list_find_dmi (struct dev_mc_list *dmi, struct dev_mc_list *mc_list);
+extern int dev_mc_list_copy (struct dev_mc_list *from, struct dev_mc_list **to, int gpf_flag);
+extern void dev_mc_list_destroy(struct dev_mc_list **mc_list);
+extern void dev_mc_list_flush(struct net_device *dev, struct dev_mc_list *mc_list);
extern void dev_set_promiscuity(struct net_device *dev, int inc);
extern void dev_set_allmulti(struct net_device *dev, int inc);
extern void netdev_state_change(struct net_device *dev);
diff -urN -X exclude 2.4.0-test7-pre7/net/core/dev_mcast.c 2.4.0-test7-pre7-bond/net/core/dev_mcast.c
--- 2.4.0-test7-pre7/net/core/dev_mcast.c Thu Aug 24 13:38:07 2000
+++ 2.4.0-test7-pre7-bond/net/core/dev_mcast.c Thu Aug 24 16:20:45 2000
@@ -14,6 +14,8 @@
* Alan Cox : IFF_ALLMULTI support.
* Alan Cox : New format set_multicast_list() calls.
* Gleb Natapov : Remove dev_mc_lock.
+ * Gleb Natapov : various mc_list manipulation functions
+ * added
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -95,6 +97,7 @@
__dev_mc_upload(dev);
spin_unlock_bh(&dev->xmit_lock);
}
+
/*
* Delete a device level multicast
*/
@@ -214,6 +217,80 @@
dev->mc_count = 0;

spin_unlock_bh(&dev->xmit_lock);
+}
+
+/*
+ * compare two mc addresses
+ */
+static inline int dmi_same(struct dev_mc_list *dmi1, struct dev_mc_list *dmi2)
+{
+ return memcmp(dmi1->dmi_addr,dmi2->dmi_addr,dmi1->dmi_addrlen) == 0
+ && dmi1->dmi_addrlen == dmi2->dmi_addrlen;
+}
+
+/*
+ * returns dmi entry if found, NULL otherwise
+ */
+struct dev_mc_list* dev_mc_list_find_dmi (struct dev_mc_list *dmi,
+ struct dev_mc_list *mc_list)
+{
+ struct dev_mc_list *idmi;
+
+ for(idmi=mc_list; idmi!=NULL; idmi=idmi->next)
+ if(dmi_same(dmi, idmi))
+ return idmi;
+
+ return NULL;
+}
+
+/*
+ * copy mc_list
+ */
+int dev_mc_list_copy (struct dev_mc_list *from, struct dev_mc_list **to,
+ int gpf_flag)
+{
+ struct dev_mc_list *dmi, *new_dmi;
+
+ for(dmi=from; dmi!=NULL; dmi=dmi->next) {
+ new_dmi = kmalloc(sizeof(struct dev_mc_list), gpf_flag);
+ if(new_dmi == NULL)
+ return -ENOMEM;
+ new_dmi->next = *to;
+ *to = new_dmi;
+
+ new_dmi->dmi_addrlen = dmi->dmi_addrlen;
+ memcpy(new_dmi->dmi_addr, dmi->dmi_addr, dmi->dmi_addrlen);
+ new_dmi->dmi_users = dmi->dmi_users;
+ new_dmi->dmi_gusers = dmi->dmi_gusers;
+ }
+
+ return 0;
+}
+
+/*
+ * remove all elements of mc_list
+ */
+void dev_mc_list_destroy(struct dev_mc_list **mc_list)
+{
+ struct dev_mc_list *dmi = *mc_list;
+
+ while(dmi) {
+ *mc_list = dmi->next;
+ kfree(dmi);
+ dmi = *mc_list;
+ }
+}
+
+/*
+ * flush all members of mc_list from device dev
+ */
+void dev_mc_list_flush(struct net_device *dev, struct dev_mc_list *mc_list)
+{
+ struct dev_mc_list *dmi;
+ int i;
+
+ for(dmi = mc_list; dmi!=NULL; dmi=dmi->next)
+ dev_mc_delete(dev, dmi->dmi_addr, dmi->dmi_addrlen, 0);
}

#ifdef CONFIG_PROC_FS
diff -urN -X exclude 2.4.0-test7-pre7/net/netsyms.c 2.4.0-test7-pre7-bond/net/netsyms.c
--- 2.4.0-test7-pre7/net/netsyms.c Thu Aug 24 13:37:22 2000
+++ 2.4.0-test7-pre7-bond/net/netsyms.c Thu Aug 24 15:49:05 2000
@@ -501,6 +501,10 @@
EXPORT_SYMBOL(dev_mc_add);
EXPORT_SYMBOL(dev_mc_delete);
EXPORT_SYMBOL(dev_mc_upload);
+EXPORT_SYMBOL(dev_mc_list_find_dmi);
+EXPORT_SYMBOL(dev_mc_list_copy);
+EXPORT_SYMBOL(dev_mc_list_destroy);
+EXPORT_SYMBOL(dev_mc_list_flush);
EXPORT_SYMBOL(n_tty_ioctl);
EXPORT_SYMBOL(tty_register_ldisc);
EXPORT_SYMBOL(__kill_fasync);
\
 
 \ /
  Last update: 2005-03-22 12:38    [W:0.113 / U:0.124 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site