[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20070620180019.6685.50688.sendpatchset@localhost.localdomain>
Date: Wed, 20 Jun 2007 20:00:24 +0200 (MEST)
From: Patrick McHardy <kaber@...sh.net>
To: netdev@...r.kernel.org
Cc: Patrick McHardy <kaber@...sh.net>, shemminger@...ux-foundation.org,
davem@...emloft.net, jeff@...zik.org
Subject: [RFC NET 01/02]: Secondary unicast address support
[NETDEV]: Secondary unicast address support
Add support for configuring secondary unicast addresses on network devices.
Devices supporting this feature need to change their set_multicast_list
function to configure unicast filters as well and assign it to
dev->set_address_list instead of dev->set_multicast_list. Devices not
supporting this feature are put in promiscous mode when secondary unicast
addresses are present.
Signed-off-by: Patrick McHardy <kaber@...sh.net>
---
commit 3f3f6e18b902ee177ecf5a108ba6ecbf1b5c9ba3
tree 8883aba620211e96d7419f96960cc596506cbeef
parent 890e2ae4ef5599ee34f280af4882f97c2dcfcb7b
author Patrick McHardy <kaber@...sh.net> Wed, 20 Jun 2007 19:44:11 +0200
committer Patrick McHardy <kaber@...sh.net> Wed, 20 Jun 2007 19:44:11 +0200
include/linux/netdevice.h | 17 ++++
net/core/dev.c | 172 +++++++++++++++++++++++++++++++++++++++++++--
net/core/dev_mcast.c | 34 +--------
3 files changed, 185 insertions(+), 38 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 868140d..a1cc2ea 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -191,6 +191,14 @@ struct dev_mc_list
int dmi_gusers;
};
+struct dev_uc_list
+{
+ struct dev_uc_list *next;
+ __u8 duci_addr[MAX_ADDR_LEN];
+ unsigned char duci_addrlen;
+ int duci_users;
+};
+
struct hh_cache
{
struct hh_cache *hh_next; /* Next entry */
@@ -389,7 +397,10 @@ struct net_device
unsigned short dev_id; /* for shared network cards */
struct dev_mc_list *mc_list; /* Multicast mac addresses */
+ struct dev_uc_list *uc_list; /* Secondary unicast mac addresses */
int mc_count; /* Number of installed mcasts */
+ int uc_count; /* Number of installed ucasts */
+ int uc_promisc;
int promiscuity;
int allmulti;
@@ -493,6 +504,8 @@ struct net_device
void *saddr,
unsigned len);
int (*rebuild_header)(struct sk_buff *skb);
+#define HAVE_ADDRESS_LIST
+ void (*set_address_list)(struct net_device *dev);
#define HAVE_MULTICAST
void (*set_multicast_list)(struct net_device *dev);
#define HAVE_SET_MAC_ADDR
@@ -1006,6 +1019,10 @@ extern void dev_mc_upload(struct net_device *dev);
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 int dev_unicast_delete(struct net_device *dev, void *addr, int alen);
+extern int dev_unicast_add(struct net_device *dev, void *addr, int alen);
+extern void __dev_address_upload(struct net_device *dev);
+extern void dev_address_upload(struct net_device *dev);
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 --git a/net/core/dev.c b/net/core/dev.c
index 5974e5b..4f4beb0 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -943,7 +943,7 @@ int dev_open(struct net_device *dev)
/*
* Initialize multicasting status
*/
- dev_mc_upload(dev);
+ dev_address_upload(dev);
/*
* Wakeup transmit queue engine
@@ -2522,6 +2522,163 @@ int netdev_set_master(struct net_device *slave, struct net_device *master)
return 0;
}
+void __dev_address_upload(struct net_device *dev)
+{
+ /* Don't do anything till we up the interface
+ * [dev_open will call this function so the list will
+ * stay sane]
+ */
+
+ if (!(dev->flags&IFF_UP))
+ return;
+
+ if (!netif_device_present(dev))
+ return;
+
+ if (dev->set_address_list)
+ dev->set_address_list(dev);
+ else {
+ if (dev->uc_count > 0 && !dev->uc_promisc) {
+ dev_set_promiscuity(dev, 1);
+ dev->uc_promisc = 1;
+ } else if (dev->uc_count == 0 && dev->uc_promisc) {
+ dev_set_promiscuity(dev, -1);
+ dev->uc_promisc = 0;
+ }
+
+ if (dev->set_multicast_list)
+ dev->set_multicast_list(dev);
+ }
+}
+
+/**
+ * dev_address_upload - upload address lists to device
+ * @dev: device
+ *
+ * Upload unicast and multicast address lists to device.
+ * When the device doesn't support unicast filtering it
+ * is put in promiscous mode while addresses are present.
+ *
+ */
+void dev_address_upload(struct net_device *dev)
+{
+ netif_tx_lock_bh(dev);
+ __dev_address_upload(dev);
+ netif_tx_unlock_bh(dev);
+}
+
+/**
+ * dev_unicast_delete - Release secondary unicast address.
+ * @dev: device
+ *
+ * Release reference to a secondary unicast address and remove it
+ * from the device if the reference count drop to zero.
+ *
+ */
+int dev_unicast_delete(struct net_device *dev, void *addr, int alen)
+{
+ int err = 0;
+ struct dev_uc_list *duci, **ducip;
+
+ netif_tx_lock_bh(dev);
+
+ for (ducip = &dev->uc_list; (duci = *ducip) != NULL;
+ ducip = &duci->next) {
+ /*
+ * Find the entry we want to delete. The device could
+ * have variable length entries so check these too.
+ */
+ if (memcmp(duci->duci_addr, addr, duci->duci_addrlen) == 0 &&
+ alen == duci->duci_addrlen) {
+ if (--duci->duci_users)
+ goto done;
+
+ /*
+ * Last user. So delete the entry.
+ */
+ *ducip = duci->next;
+ dev->uc_count--;
+
+ kfree(duci);
+
+ /*
+ * We have altered the list, so the card
+ * loaded filter is now wrong. Fix it
+ */
+ __dev_address_upload(dev);
+
+ netif_tx_unlock_bh(dev);
+ return 0;
+ }
+ }
+ err = -ENOENT;
+done:
+ netif_tx_unlock_bh(dev);
+ return err;
+}
+EXPORT_SYMBOL(dev_unicast_delete);
+
+/**
+ * dev_unicast_add - add a secondary unicast address
+ * @dev: device
+ *
+ * Add a secondary unicast address to the device or increase
+ * the reference count if it already exists.
+ *
+ */
+int dev_unicast_add(struct net_device *dev, void *addr, int alen)
+{
+ int err = 0;
+ struct dev_uc_list *duci, *duci1;
+
+ duci1 = kmalloc(sizeof(*duci), GFP_ATOMIC);
+
+ netif_tx_lock_bh(dev);
+ for (duci = dev->uc_list; duci != NULL; duci = duci->next) {
+ if (memcmp(duci->duci_addr, addr, duci->duci_addrlen) == 0 &&
+ duci->duci_addrlen == alen) {
+ duci->duci_users++;
+ goto done;
+ }
+ }
+
+ if ((duci = duci1) == NULL) {
+ netif_tx_unlock_bh(dev);
+ return -ENOMEM;
+ }
+ memcpy(duci->duci_addr, addr, alen);
+ duci->duci_addrlen = alen;
+ duci->next = dev->uc_list;
+ duci->duci_users = 1;
+ dev->uc_list = duci;
+ dev->uc_count++;
+
+ __dev_address_upload(dev);
+
+ netif_tx_unlock_bh(dev);
+ return 0;
+
+done:
+ netif_tx_unlock_bh(dev);
+ kfree(duci1);
+ return err;
+}
+EXPORT_SYMBOL(dev_unicast_add);
+
+void dev_unicast_discard(struct net_device *dev)
+{
+ netif_tx_lock_bh(dev);
+
+ while (dev->uc_list != NULL) {
+ struct dev_uc_list *tmp = dev->uc_list;
+ dev->uc_list = tmp->next;
+ kfree(tmp);
+ }
+ dev->uc_count = 0;
+
+ netif_tx_unlock_bh(dev);
+}
+
/**
* dev_set_promiscuity - update promiscuity count on a device
* @dev: device
@@ -2541,7 +2698,7 @@ void dev_set_promiscuity(struct net_device *dev, int inc)
else
dev->flags |= IFF_PROMISC;
if (dev->flags != old_flags) {
- dev_mc_upload(dev);
+ dev_address_upload(dev);
printk(KERN_INFO "device %s %s promiscuous mode\n",
dev->name, (dev->flags & IFF_PROMISC) ? "entered" :
"left");
@@ -2574,7 +2731,7 @@ void dev_set_allmulti(struct net_device *dev, int inc)
if ((dev->allmulti += inc) == 0)
dev->flags &= ~IFF_ALLMULTI;
if (dev->flags ^ old_flags)
- dev_mc_upload(dev);
+ dev_address_upload(dev);
}
unsigned dev_get_flags(const struct net_device *dev)
@@ -2617,10 +2774,10 @@ int dev_change_flags(struct net_device *dev, unsigned flags)
IFF_ALLMULTI));
/*
- * Load in the correct multicast list now the flags have changed.
+ * Load in the correct address list now the flags have changed.
*/
- dev_mc_upload(dev);
+ dev_address_upload(dev);
/*
* Have we downed the interface. We handle IFF_UP ourselves
@@ -2633,7 +2790,7 @@ int dev_change_flags(struct net_device *dev, unsigned flags)
ret = ((old_flags & IFF_UP) ? dev_close : dev_open)(dev);
if (!ret)
- dev_mc_upload(dev);
+ dev_address_upload(dev);
}
if (dev->flags & IFF_UP &&
@@ -3497,8 +3654,9 @@ void unregister_netdevice(struct net_device *dev)
raw_notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev);
/*
- * Flush the multicast chain
+ * Flush the unicast and multicast chains
*/
+ dev_unicast_discard(dev);
dev_mc_discard(dev);
if (dev->uninit)
diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c
index 5a54053..45d616b 100644
--- a/net/core/dev_mcast.c
+++ b/net/core/dev_mcast.c
@@ -63,37 +63,9 @@
* We block accesses to device mc filters with netif_tx_lock.
*/
-/*
- * Update the multicast list into the physical NIC controller.
- */
-
-static void __dev_mc_upload(struct net_device *dev)
-{
- /* Don't do anything till we up the interface
- * [dev_open will call this function so the list will
- * stay sane]
- */
-
- if (!(dev->flags&IFF_UP))
- return;
-
- /*
- * Devices with no set multicast or which have been
- * detached don't get set.
- */
-
- if (dev->set_multicast_list == NULL ||
- !netif_device_present(dev))
- return;
-
- dev->set_multicast_list(dev);
-}
-
void dev_mc_upload(struct net_device *dev)
{
- netif_tx_lock_bh(dev);
- __dev_mc_upload(dev);
- netif_tx_unlock_bh(dev);
+ dev_address_upload(dev);
}
/*
@@ -135,7 +107,7 @@ int dev_mc_delete(struct net_device *dev, void *addr, int alen, int glbl)
* We have altered the list, so the card
* loaded filter is now wrong. Fix it
*/
- __dev_mc_upload(dev);
+ __dev_address_upload(dev);
netif_tx_unlock_bh(dev);
return 0;
@@ -185,7 +157,7 @@ int dev_mc_add(struct net_device *dev, void *addr, int alen, int glbl)
dev->mc_list = dmi;
dev->mc_count++;
- __dev_mc_upload(dev);
+ __dev_address_upload(dev);
netif_tx_unlock_bh(dev);
return 0;
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists