* [PATCH] Change MAC without bringing interface down
@ 2003-08-18 9:13 Tommi Virtanen
2003-08-18 11:19 ` David S. Miller
0 siblings, 1 reply; 15+ messages in thread
From: Tommi Virtanen @ 2003-08-18 9:13 UTC (permalink / raw)
To: netdev
Hi. There are cases when you want to change your MAC address,
such as in Linux-HA when the other box fails, and your hot
standby activates itself.
Some NICs, such as e100, e1000 and uml ;) allow you to do that
without bringing the interface down. Which is nice, because it
allows the link to stay up, and not make switches scratch their
head for up to a minute.
The problem is, if you do that, the old MAC address is stored
in the hh_cache entries, and used in future traffic also.
Here's a patch that
1. makes eth_header_cache_update also update the source MAC in
hh_cache.
2. adds a NETDEV_CHANGEADDR notifier in net/core/neighbour.c
that walks through all the neighbour entries and updates
the hh_cache's for all the neighbour entries related to
given device.
3. adds neighbour_init() to allow registration of said notifier.
Please comment.
===== include/net/neighbour.h 1.1 vs edited =====
--- 1.1/include/net/neighbour.h Tue Feb 5 19:39:48 2002
+++ edited/include/net/neighbour.h Mon Aug 18 11:17:25 2003
@@ -275,6 +275,8 @@
return neigh_create(tbl, pkey, dev);
}
+extern void neighbour_init(void);
+
#endif
#endif
===== net/core/dev.c 1.36 vs edited =====
--- 1.36/net/core/dev.c Fri May 23 20:59:51 2003
+++ edited/net/core/dev.c Mon Aug 18 11:54:30 2003
@@ -93,6 +93,7 @@
#include <linux/if_bridge.h>
#include <linux/divert.h>
#include <net/dst.h>
+#include <net/neighbour.h>
#include <net/pkt_sched.h>
#include <net/profile.h>
#include <net/checksum.h>
@@ -2849,6 +2850,7 @@
open_softirq(NET_RX_SOFTIRQ, net_rx_action, NULL);
dst_init();
+ neighbour_init();
dev_mcast_init();
#ifdef CONFIG_NET_SCHED
===== net/core/neighbour.c 1.9 vs edited =====
--- 1.9/net/core/neighbour.c Thu Jun 12 09:24:41 2003
+++ edited/net/core/neighbour.c Mon Aug 18 11:53:50 2003
@@ -1558,3 +1558,46 @@
}
#endif /* CONFIG_SYSCTL */
+
+static int neighbour_dev_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+ struct net_device *dev = ptr;
+
+ switch (event) {
+ struct neigh_table *tbl;
+ case NETDEV_CHANGEADDR:
+ read_lock(&neigh_tbl_lock);
+ for (tbl = neigh_tables; tbl; tbl=tbl->next) {
+ int i;
+
+ for (i=0; i<=NEIGH_HASHMASK; i++) {
+ struct neighbour *n, **np;
+
+ np = &tbl->hash_buckets[i];
+ write_lock(&tbl->lock);
+
+ while ((n = *np) != NULL) {
+ if (n->dev == dev) {
+ neigh_update_hhs(n);
+ }
+ np = &n->next;
+ }
+ write_unlock(&tbl->lock);
+ }
+ }
+ read_unlock(&neigh_tbl_lock);
+ break;
+ }
+ return NOTIFY_DONE;
+}
+
+struct notifier_block neighbour_dev_notifier = {
+ neighbour_dev_event,
+ NULL,
+ 0
+};
+
+void __init neighbour_init(void)
+{
+ register_netdevice_notifier(&neighbour_dev_notifier);
+}
===== net/ethernet/eth.c 1.3 vs edited =====
--- 1.3/net/ethernet/eth.c Fri Jun 20 00:22:53 2003
+++ edited/net/ethernet/eth.c Mon Aug 18 11:55:36 2003
@@ -238,6 +238,11 @@
void eth_header_cache_update(struct hh_cache *hh, struct net_device *dev, unsigned char * haddr)
{
- memcpy(((u8*)hh->hh_data) + HH_DATA_OFF(sizeof(struct ethhdr)),
- haddr, dev->addr_len);
+ struct ethhdr *eth;
+
+ eth = (struct ethhdr*)
+ (((u8*)hh->hh_data) + (HH_DATA_OFF(sizeof(*eth))));
+
+ memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
+ memcpy(eth->h_dest, haddr, dev->addr_len);
}
--
:(){ :|:&};:
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] Change MAC without bringing interface down
2003-08-18 9:13 [PATCH] Change MAC without bringing interface down Tommi Virtanen
@ 2003-08-18 11:19 ` David S. Miller
2003-08-18 12:13 ` jamal
2003-08-18 14:24 ` Tommi Virtanen
0 siblings, 2 replies; 15+ messages in thread
From: David S. Miller @ 2003-08-18 11:19 UTC (permalink / raw)
To: Tommi Virtanen; +Cc: netdev
On Mon, 18 Aug 2003 12:13:12 +0300
Tommi Virtanen <tv@debian.org> wrote:
> Here's a patch that
>
> 1. makes eth_header_cache_update also update the source MAC in
> hh_cache.
>
> 2. adds a NETDEV_CHANGEADDR notifier in net/core/neighbour.c
> that walks through all the neighbour entries and updates
> the hh_cache's for all the neighbour entries related to
> given device.
>
> 3. adds neighbour_init() to allow registration of said notifier.
I would suggest to fix this by instead flushing the hh
entries (just like neigh_destroy() does).
This way, we don't have to fix up every single header cache
implementation, that's painful :(
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] Change MAC without bringing interface down
2003-08-18 12:13 ` jamal
@ 2003-08-18 12:12 ` David S. Miller
2003-08-18 13:03 ` jamal
2003-08-18 16:04 ` Tommi Virtanen
0 siblings, 2 replies; 15+ messages in thread
From: David S. Miller @ 2003-08-18 12:12 UTC (permalink / raw)
To: hadi; +Cc: tv, netdev
On 18 Aug 2003 08:13:44 -0400
jamal <hadi@cyberus.ca> wrote:
> Editing the header may be the better approach if you have a few hundred
> hhs already inserted (this was the issue i was faced with when VRRP was
> failing over when i was playing with it). I tried to flush the cache but
> it took longer to recover it.
There is another reason I want the cache flushed.
Those hh cache entries are what ARP resolved to when we
had the previous MAC address, not the one we have now.
The ARPs may come back differently with the new MAC
address.
I _REALLY REALLY_ don't want to have to change the
->update() implementations. Although one thing I
would consider is a new ->update_src() operation
and if this were NULL we flush the entries instead.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] Change MAC without bringing interface down
2003-08-18 11:19 ` David S. Miller
@ 2003-08-18 12:13 ` jamal
2003-08-18 12:12 ` David S. Miller
2003-08-18 14:24 ` Tommi Virtanen
1 sibling, 1 reply; 15+ messages in thread
From: jamal @ 2003-08-18 12:13 UTC (permalink / raw)
To: David S. Miller; +Cc: Tommi Virtanen, netdev
[-- Attachment #1: Type: text/plain, Size: 1406 bytes --]
Editing the header may be the better approach if you have a few hundred
hhs already inserted (this was the issue i was faced with when VRRP was
failing over when i was playing with it). I tried to flush the cache but
it took longer to recover it.
The patch posted may not be the better way to do this. It should be per
neighbour table owner - at the moment only ARP and ndisc really care
about this.
Heres an old patch i have circa 2.4.2 that i have been sitting on
planning to convert it to latest kernels; the ndisc portion is missing;
If this is found agreeable Tommi you can clean it up and bring it to par
with latest kernel
cheers,
jamal
On Mon, 2003-08-18 at 07:19, David S. Miller wrote:
> On Mon, 18 Aug 2003 12:13:12 +0300
> Tommi Virtanen <tv@debian.org> wrote:
>
> > Here's a patch that
> >
> > 1. makes eth_header_cache_update also update the source MAC in
> > hh_cache.
> >
> > 2. adds a NETDEV_CHANGEADDR notifier in net/core/neighbour.c
> > that walks through all the neighbour entries and updates
> > the hh_cache's for all the neighbour entries related to
> > given device.
> >
> > 3. adds neighbour_init() to allow registration of said notifier.
>
> I would suggest to fix this by instead flushing the hh
> entries (just like neigh_destroy() does).
>
> This way, we don't have to fix up every single header cache
> implementation, that's painful :(
>
>
[-- Attachment #2: neighp --]
[-- Type: text/plain, Size: 4496 bytes --]
--- 242/include/net/neighbour.h 2003-07-20 19:42:33.000000000 -0400
+++ 242/include/net/patchedneighbour.h 2003-07-20 19:42:38.000000000 -0400
@@ -180,6 +180,7 @@
extern void neigh_destroy(struct neighbour *neigh);
extern int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb);
extern int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, int override, int arp);
+extern int neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev);
extern int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev);
extern int neigh_resolve_output(struct sk_buff *skb);
extern int neigh_connected_output(struct sk_buff *skb);
--- 242/net/core/neighbour.c 2003-07-20 19:38:19.000000000 -0400
+++ 242/net/core/patchedneighbour.c 2003-08-18 07:15:35.000000000 -0400
@@ -50,6 +50,7 @@
static void neigh_app_notify(struct neighbour *n);
#endif
static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev);
+int neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev);
static int neigh_glbl_allocs;
static struct neigh_table *neigh_tables;
@@ -410,6 +411,52 @@
return -ENOENT;
}
+void update_neigh_hh(struct neighbour *neigh)
+{
+
+ struct hh_cache *hh;
+
+ int (*update)(struct neighbour *neigh, struct hh_cache *hh) =
+ neigh->dev->hard_header_cache;
+
+ if (update) {
+ for (hh=neigh->hh; hh; hh=hh->hh_next) {
+ write_lock_bh(&hh->hh_lock);
+ update(neigh, hh);
+ write_unlock_bh(&hh->hh_lock);
+ }
+ }
+ else {
+ printk("device neigh %p does not have a update method!\n",neigh);
+ }
+}
+
+int neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev)
+{
+ int i;
+
+ write_lock_bh(&tbl->lock);
+
+ for (i=0; i<=NEIGH_HASHMASK; i++) {
+ struct neighbour *n, **np;
+
+ np = &tbl->hash_buckets[i];
+ while ((n = *np) != NULL) {
+ if (dev && n->dev != dev) {
+ np = &n->next;
+ continue;
+ }
+ *np = n->next;
+ write_lock_bh(&n->lock);
+ update_neigh_hh(n);
+ write_unlock_bh(&n->lock);
+ }
+ }
+
+ write_unlock_bh(&tbl->lock);
+ return 0;
+}
+
static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
{
struct pneigh_entry *n, **np;
@@ -432,6 +479,7 @@
}
+
/*
* neighbour must already be out of the table;
*
@@ -488,8 +536,9 @@
neigh->output = neigh->ops->output;
- for (hh = neigh->hh; hh; hh = hh->hh_next)
+ for (hh = neigh->hh; hh; hh = hh->hh_next) {
hh->hh_output = neigh->ops->output;
+ }
}
/* Neighbour state is OK;
@@ -507,8 +556,10 @@
neigh->output = neigh->ops->connected_output;
- for (hh = neigh->hh; hh; hh = hh->hh_next)
+ for (hh = neigh->hh; hh; hh = hh->hh_next) {
hh->hh_output = neigh->ops->hh_output;
+ }
+
}
/*
@@ -924,6 +975,7 @@
atomic_inc(&hh->hh_refcnt);
dst->hh = hh;
}
+
}
/* This function can be used in contexts, where only old dev_queue_xmit
@@ -961,6 +1013,7 @@
int err;
struct net_device *dev = neigh->dev;
if (dev->hard_header_cache && dst->hh == NULL) {
+
write_lock_bh(&neigh->lock);
if (dst->hh == NULL)
neigh_hh_init(neigh, dst, dst->ops->protocol);
--- 242/net/ipv4/arp.c 2003-07-20 19:37:52.000000000 -0400
+++ 242/net/ipv4/patchedarp.c 2003-08-18 07:19:08.000000000 -0400
@@ -1,6 +1,6 @@
/* linux/net/inet/arp.c
*
- * Version: $Id: arp.c,v 1.90 2000/10/04 09:20:56 anton Exp $
+ * Version: $Id: arp.c,v 1.1 2003/07/04 14:04:46 root Exp root $
*
* Copyright (C) 1994 by Florian La Roche
*
@@ -123,6 +123,7 @@
static void arp_error_report(struct neighbour *neigh, struct sk_buff *skb);
static void parp_redo(struct sk_buff *skb);
+static int arp_n_event(struct notifier_block *this, unsigned long event, void *ptr);
static struct neigh_ops arp_generic_ops =
{
AF_INET,
@@ -1140,6 +1141,30 @@
}
#endif
+
+struct notifier_block arp_netdev_notifier = {
+ arp_n_event,
+ NULL,
+ 0
+};
+
+static int arp_n_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+ struct net_device *dev = (struct net_device *)(ptr) ;
+
+ switch (event) {
+ default:
+ break;
+ case NETDEV_CHANGEADDR:
+ neigh_changeaddr(&arp_tbl, dev);
+ break;
+ }
+
+ return NOTIFY_DONE;
+
+}
+
+
/* Note, that it is not on notifier chain.
It is necessary, that this routine was called after route cache will be
flushed.
@@ -1174,6 +1199,7 @@
#ifdef CONFIG_SYSCTL
neigh_sysctl_register(NULL, &arp_tbl.parms, NET_IPV4, NET_IPV4_NEIGH, "ipv4");
#endif
+ register_netdevice_notifier(&arp_netdev_notifier);
}
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] Change MAC without bringing interface down
2003-08-18 12:12 ` David S. Miller
@ 2003-08-18 13:03 ` jamal
2003-08-18 16:04 ` Tommi Virtanen
1 sibling, 0 replies; 15+ messages in thread
From: jamal @ 2003-08-18 13:03 UTC (permalink / raw)
To: David S. Miller; +Cc: tv, netdev
This is fine by me. I 'll let Tommi take the lead on it unless he is too
busy.
cheers,
jamal
On Mon, 2003-08-18 at 08:12, David S. Miller wrote:
> On 18 Aug 2003 08:13:44 -0400
> jamal <hadi@cyberus.ca> wrote:
>
> > Editing the header may be the better approach if you have a few hundred
> > hhs already inserted (this was the issue i was faced with when VRRP was
> > failing over when i was playing with it). I tried to flush the cache but
> > it took longer to recover it.
>
> There is another reason I want the cache flushed.
>
> Those hh cache entries are what ARP resolved to when we
> had the previous MAC address, not the one we have now.
>
> The ARPs may come back differently with the new MAC
> address.
>
> I _REALLY REALLY_ don't want to have to change the
> ->update() implementations. Although one thing I
> would consider is a new ->update_src() operation
> and if this were NULL we flush the entries instead.
>
>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] Change MAC without bringing interface down
2003-08-18 14:24 ` Tommi Virtanen
@ 2003-08-18 14:20 ` David S. Miller
2003-08-18 15:10 ` jamal
1 sibling, 0 replies; 15+ messages in thread
From: David S. Miller @ 2003-08-18 14:20 UTC (permalink / raw)
To: Tommi Virtanen; +Cc: netdev
On Mon, 18 Aug 2003 17:24:55 +0300
Tommi Virtanen <tv@debian.org> wrote:
> > I would suggest to fix this by instead flushing the hh
> > entries (just like neigh_destroy() does).
>
> This may be a dumb question, but how do I do that?
>
> If I set them to neigh_blackhole, like neigh_destroy() does,
> e.g. already running gets -ENETDOWN. That's now true and it's
> not nice. I'm having trouble seeing how to "disable" the
> neighbour entry, so it won't be used again.
You have to also remove them from the list, like neigh_destroy()
does, are you doing that as well?
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] Change MAC without bringing interface down
2003-08-18 11:19 ` David S. Miller
2003-08-18 12:13 ` jamal
@ 2003-08-18 14:24 ` Tommi Virtanen
2003-08-18 14:20 ` David S. Miller
2003-08-18 15:10 ` jamal
1 sibling, 2 replies; 15+ messages in thread
From: Tommi Virtanen @ 2003-08-18 14:24 UTC (permalink / raw)
To: David S. Miller; +Cc: netdev
On Mon, Aug 18, 2003 at 04:19:11AM -0700, David S. Miller wrote:
> On Mon, 18 Aug 2003 12:13:12 +0300
> > 1. makes eth_header_cache_update also update the source MAC in
> > hh_cache.
> >
> > 2. adds a NETDEV_CHANGEADDR notifier in net/core/neighbour.c
> > that walks through all the neighbour entries and updates
> > the hh_cache's for all the neighbour entries related to
> > given device.
> I would suggest to fix this by instead flushing the hh
> entries (just like neigh_destroy() does).
This may be a dumb question, but how do I do that?
If I set them to neigh_blackhole, like neigh_destroy() does,
e.g. already running gets -ENETDOWN. That's now true and it's
not nice. I'm having trouble seeing how to "disable" the
neighbour entry, so it won't be used again.
If I use neigh_suspect() in an attempt to mark the entry as
"expired", I see traffic using the "old" MAC as source after a
while. Apparently, it gets confirmed and then the old MAC
is used again.
> This way, we don't have to fix up every single header cache
> implementation, that's painful :(
I agree with that, though I am only interested in ethernet ;)
--
:(){ :|:&};:
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] Change MAC without bringing interface down
2003-08-18 14:24 ` Tommi Virtanen
2003-08-18 14:20 ` David S. Miller
@ 2003-08-18 15:10 ` jamal
1 sibling, 0 replies; 15+ messages in thread
From: jamal @ 2003-08-18 15:10 UTC (permalink / raw)
To: Tommi Virtanen; +Cc: David S. Miller, netdev
If you are going that approach then please if you have time do some
measurement on editing vs flushing with X number of cache entries.
go with X being a max of 200.
cheers,
jamal
On Mon, 2003-08-18 at 10:24, Tommi Virtanen wrote:
>
> > This way, we don't have to fix up every single header cache
> > implementation, that's painful :(
>
> I agree with that, though I am only interested in ethernet ;)
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] Change MAC without bringing interface down
2003-08-18 12:12 ` David S. Miller
2003-08-18 13:03 ` jamal
@ 2003-08-18 16:04 ` Tommi Virtanen
2003-08-18 16:06 ` David S. Miller
1 sibling, 1 reply; 15+ messages in thread
From: Tommi Virtanen @ 2003-08-18 16:04 UTC (permalink / raw)
To: David S. Miller; +Cc: hadi, netdev
On Mon, Aug 18, 2003 at 05:12:27AM -0700, David S. Miller wrote:
> There is another reason I want the cache flushed.
Alright, here's an implementation that does that.
Please comment.
A single flood ping from uml->host survives MAC
changes perfectly without dropping a single packet.
(Can't test realworld performance right now.)
Note I had to flush the route cache also, that was
tricking me previously. Clearing neigh_table isn't
enough, as the hh is reached from dst_entries also.
===== include/net/neighbour.h 1.1 vs edited =====
--- 1.1/include/net/neighbour.h Tue Feb 5 19:39:48 2002
+++ edited/include/net/neighbour.h Mon Aug 18 18:52:30 2003
@@ -180,6 +180,7 @@
extern void neigh_destroy(struct neighbour *neigh);
extern int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb);
extern int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, int override, int arp);
+extern void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev);
extern int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev);
extern int neigh_resolve_output(struct sk_buff *skb);
extern int neigh_connected_output(struct sk_buff *skb);
===== net/core/neighbour.c 1.9 vs edited =====
--- 1.9/net/core/neighbour.c Thu Jun 12 09:24:41 2003
+++ edited/net/core/neighbour.c Mon Aug 18 18:52:41 2003
@@ -50,6 +50,7 @@
static void neigh_app_notify(struct neighbour *n);
#endif
static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev);
+void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev);
static int neigh_glbl_allocs;
static struct neigh_table *neigh_tables;
@@ -167,6 +168,33 @@
dev_put(skb->dev);
kfree_skb(skb);
}
+}
+
+void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev)
+{
+ int i;
+
+ write_lock_bh(&tbl->lock);
+
+ for (i=0; i<=NEIGH_HASHMASK; i++) {
+ struct neighbour *n, **np;
+
+ np = &tbl->hash_buckets[i];
+ while ((n = *np) != NULL) {
+ if (dev && n->dev != dev) {
+ np = &n->next;
+ continue;
+ }
+ *np = n->next;
+ write_lock_bh(&n->lock);
+ n->dead = 1;
+ neigh_del_timer(n);
+ write_unlock_bh(&n->lock);
+ neigh_release(n);
+ }
+ }
+
+ write_unlock_bh(&tbl->lock);
}
int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
===== net/ipv4/arp.c 1.11 vs edited =====
--- 1.11/net/ipv4/arp.c Fri Jun 27 09:03:01 2003
+++ edited/net/ipv4/arp.c Mon Aug 18 18:51:10 2003
@@ -1212,6 +1212,28 @@
}
#endif
+static int arp_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+ struct net_device *dev = ptr;
+
+ switch (event) {
+ case NETDEV_CHANGEADDR:
+ neigh_changeaddr(&arp_tbl, dev);
+ rt_cache_flush(0);
+ break;
+ default:
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+
+struct notifier_block arp_netdev_notifier = {
+ arp_netdev_event,
+ NULL,
+ 0
+};
+
/* Note, that it is not on notifier chain.
It is necessary, that this routine was called after route cache will be
flushed.
@@ -1243,6 +1265,7 @@
#ifdef CONFIG_SYSCTL
neigh_sysctl_register(NULL, &arp_tbl.parms, NET_IPV4, NET_IPV4_NEIGH, "ipv4");
#endif
+ register_netdevice_notifier(&arp_netdev_notifier);
}
===== net/ipv6/ndisc.c 1.22 vs edited =====
--- 1.22/net/ipv6/ndisc.c Tue Jun 24 02:21:28 2003
+++ edited/net/ipv6/ndisc.c Mon Aug 18 18:51:40 2003
@@ -1336,6 +1336,28 @@
return 0;
}
+static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+ struct net_device *dev = ptr;
+
+ switch (event) {
+ case NETDEV_CHANGEADDR:
+ neigh_changeaddr(&nd_tbl, dev);
+ rt_cache_flush(0);
+ break;
+ default:
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+
+struct notifier_block ndisc_netdev_notifier = {
+ ndisc_netdev_event,
+ NULL,
+ 0
+};
+
int __init ndisc_init(struct net_proto_family *ops)
{
struct sock *sk;
@@ -1377,6 +1399,7 @@
neigh_sysctl_register(NULL, &nd_tbl.parms, NET_IPV6, NET_IPV6_NEIGH, "ipv6");
#endif
+ register_netdevice_notifier(&ndisc_netdev_notifier);
return 0;
}
--
:(){ :|:&};:
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] Change MAC without bringing interface down
2003-08-18 16:04 ` Tommi Virtanen
@ 2003-08-18 16:06 ` David S. Miller
2003-08-18 17:11 ` Tommi Virtanen
0 siblings, 1 reply; 15+ messages in thread
From: David S. Miller @ 2003-08-18 16:06 UTC (permalink / raw)
To: Tommi Virtanen; +Cc: hadi, netdev
On Mon, 18 Aug 2003 19:04:22 +0300
Tommi Virtanen <tv@debian.org> wrote:
> ===== net/ipv6/ndisc.c 1.22 vs edited =====
> --- 1.22/net/ipv6/ndisc.c Tue Jun 24 02:21:28 2003
> +++ edited/net/ipv6/ndisc.c Mon Aug 18 18:51:40 2003
...
> + case NETDEV_CHANGEADDR:
> + neigh_changeaddr(&nd_tbl, dev);
> + rt_cache_flush(0);
Don't flush the ipv4 routing cache from ipv6 please :-)
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] Change MAC without bringing interface down
2003-08-18 16:06 ` David S. Miller
@ 2003-08-18 17:11 ` Tommi Virtanen
2003-08-18 18:51 ` Arnaldo Carvalho de Melo
0 siblings, 1 reply; 15+ messages in thread
From: Tommi Virtanen @ 2003-08-18 17:11 UTC (permalink / raw)
To: David S. Miller; +Cc: hadi, netdev
On Mon, Aug 18, 2003 at 09:06:54AM -0700, David S. Miller wrote:
> > ===== net/ipv6/ndisc.c 1.22 vs edited =====
> > --- 1.22/net/ipv6/ndisc.c Tue Jun 24 02:21:28 2003
> > +++ edited/net/ipv6/ndisc.c Mon Aug 18 18:51:40 2003
> ...
> > + case NETDEV_CHANGEADDR:
> > + neigh_changeaddr(&nd_tbl, dev);
> > + rt_cache_flush(0);
>
> Don't flush the ipv4 routing cache from ipv6 please :-)
Good point.
I don't have an IPv6 test setup, so that side is..
umm.. improvised ;)
Here's the updated patch; I feel this is suitable for
inclusion, performance can always be improved; remember, the
current situation is either 10s..1min of no traffic passing
because you had to bring down the interface, or cache lifetime
of existing flows using the old MAC. This is a whole lot
better.
===== include/net/neighbour.h 1.1 vs edited =====
--- 1.1/include/net/neighbour.h Tue Feb 5 19:39:48 2002
+++ edited/include/net/neighbour.h Mon Aug 18 18:52:30 2003
@@ -180,6 +180,7 @@
extern void neigh_destroy(struct neighbour *neigh);
extern int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb);
extern int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, int override, int arp);
+extern void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev);
extern int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev);
extern int neigh_resolve_output(struct sk_buff *skb);
extern int neigh_connected_output(struct sk_buff *skb);
===== net/core/neighbour.c 1.9 vs edited =====
--- 1.9/net/core/neighbour.c Thu Jun 12 09:24:41 2003
+++ edited/net/core/neighbour.c Mon Aug 18 18:52:41 2003
@@ -50,6 +50,7 @@
static void neigh_app_notify(struct neighbour *n);
#endif
static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev);
+void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev);
static int neigh_glbl_allocs;
static struct neigh_table *neigh_tables;
@@ -167,6 +168,33 @@
dev_put(skb->dev);
kfree_skb(skb);
}
+}
+
+void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev)
+{
+ int i;
+
+ write_lock_bh(&tbl->lock);
+
+ for (i=0; i<=NEIGH_HASHMASK; i++) {
+ struct neighbour *n, **np;
+
+ np = &tbl->hash_buckets[i];
+ while ((n = *np) != NULL) {
+ if (dev && n->dev != dev) {
+ np = &n->next;
+ continue;
+ }
+ *np = n->next;
+ write_lock_bh(&n->lock);
+ n->dead = 1;
+ neigh_del_timer(n);
+ write_unlock_bh(&n->lock);
+ neigh_release(n);
+ }
+ }
+
+ write_unlock_bh(&tbl->lock);
}
int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
===== net/ipv4/arp.c 1.11 vs edited =====
--- 1.11/net/ipv4/arp.c Fri Jun 27 09:03:01 2003
+++ edited/net/ipv4/arp.c Mon Aug 18 18:51:10 2003
@@ -1212,6 +1212,28 @@
}
#endif
+static int arp_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+ struct net_device *dev = ptr;
+
+ switch (event) {
+ case NETDEV_CHANGEADDR:
+ neigh_changeaddr(&arp_tbl, dev);
+ rt_cache_flush(0);
+ break;
+ default:
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+
+struct notifier_block arp_netdev_notifier = {
+ arp_netdev_event,
+ NULL,
+ 0
+};
+
/* Note, that it is not on notifier chain.
It is necessary, that this routine was called after route cache will be
flushed.
@@ -1243,6 +1265,7 @@
#ifdef CONFIG_SYSCTL
neigh_sysctl_register(NULL, &arp_tbl.parms, NET_IPV4, NET_IPV4_NEIGH, "ipv4");
#endif
+ register_netdevice_notifier(&arp_netdev_notifier);
}
===== net/ipv6/ndisc.c 1.22 vs edited =====
--- 1.22/net/ipv6/ndisc.c Tue Jun 24 02:21:28 2003
+++ edited/net/ipv6/ndisc.c Mon Aug 18 20:06:11 2003
@@ -1336,6 +1336,28 @@
return 0;
}
+static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+ struct net_device *dev = ptr;
+
+ switch (event) {
+ case NETDEV_CHANGEADDR:
+ neigh_changeaddr(&nd_tbl, dev);
+ fib6_run_gc(0);
+ break;
+ default:
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+
+struct notifier_block ndisc_netdev_notifier = {
+ ndisc_netdev_event,
+ NULL,
+ 0
+};
+
int __init ndisc_init(struct net_proto_family *ops)
{
struct sock *sk;
@@ -1377,6 +1399,7 @@
neigh_sysctl_register(NULL, &nd_tbl.parms, NET_IPV6, NET_IPV6_NEIGH, "ipv6");
#endif
+ register_netdevice_notifier(&ndisc_netdev_notifier);
return 0;
}
--
:(){ :|:&};:
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] Change MAC without bringing interface down
2003-08-18 17:11 ` Tommi Virtanen
@ 2003-08-18 18:51 ` Arnaldo Carvalho de Melo
2003-08-19 5:50 ` Tommi Virtanen
0 siblings, 1 reply; 15+ messages in thread
From: Arnaldo Carvalho de Melo @ 2003-08-18 18:51 UTC (permalink / raw)
To: Tommi Virtanen; +Cc: David S. Miller, hadi, netdev
Em Mon, Aug 18, 2003 at 08:11:44PM +0300, Tommi Virtanen escreveu:
> +void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev)
> +{
> + int i;
> +
> + write_lock_bh(&tbl->lock);
> +
> + for (i=0; i<=NEIGH_HASHMASK; i++) {
spaces before and after operators, please
> +struct notifier_block arp_netdev_notifier = {
> + arp_netdev_event,
> + NULL,
> + 0
> +};
c99 style please, that is:
struct notifier_block arp_netdev_notifier = {
.notifier_call = arp_netdev_event,
}
> +struct notifier_block ndisc_netdev_notifier = {
> + ndisc_netdev_event,
> + NULL,
> + 0
> +};
ditto
Thanks,
- Arnaldo
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] Change MAC without bringing interface down
2003-08-18 18:51 ` Arnaldo Carvalho de Melo
@ 2003-08-19 5:50 ` Tommi Virtanen
2003-08-19 15:42 ` Arnaldo Carvalho de Melo
2003-08-19 19:31 ` David S. Miller
0 siblings, 2 replies; 15+ messages in thread
From: Tommi Virtanen @ 2003-08-19 5:50 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo; +Cc: David S. Miller, hadi, netdev
On Mon, Aug 18, 2003 at 03:51:53PM -0300, Arnaldo Carvalho de Melo wrote:
> > + for (i=0; i<=NEIGH_HASHMASK; i++) {
> spaces before and after operators, please
> > +struct notifier_block arp_netdev_notifier = {
> > + arp_netdev_event,
> > + NULL,
> > + 0
> > +};
> c99 style please, that is:
> > +struct notifier_block ndisc_netdev_notifier = {
> > + ndisc_netdev_event,
> > + NULL,
> > + 0
> > +};
> ditto
Here's an updated patch with those nits picked. Those were
all cut-and-pasted from elsewhere, so if you want perfection,
there's lots of those to fix.
===== include/net/neighbour.h 1.1 vs edited =====
--- 1.1/include/net/neighbour.h Tue Feb 5 19:39:48 2002
+++ edited/include/net/neighbour.h Mon Aug 18 18:52:30 2003
@@ -180,6 +180,7 @@
extern void neigh_destroy(struct neighbour *neigh);
extern int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb);
extern int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, int override, int arp);
+extern void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev);
extern int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev);
extern int neigh_resolve_output(struct sk_buff *skb);
extern int neigh_connected_output(struct sk_buff *skb);
===== net/core/neighbour.c 1.9 vs edited =====
--- 1.9/net/core/neighbour.c Thu Jun 12 09:24:41 2003
+++ edited/net/core/neighbour.c Tue Aug 19 08:45:14 2003
@@ -50,6 +50,7 @@
static void neigh_app_notify(struct neighbour *n);
#endif
static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev);
+void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev);
static int neigh_glbl_allocs;
static struct neigh_table *neigh_tables;
@@ -167,6 +168,33 @@
dev_put(skb->dev);
kfree_skb(skb);
}
+}
+
+void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev)
+{
+ int i;
+
+ write_lock_bh(&tbl->lock);
+
+ for (i=0; i <= NEIGH_HASHMASK; i++) {
+ struct neighbour *n, **np;
+
+ np = &tbl->hash_buckets[i];
+ while ((n = *np) != NULL) {
+ if (dev && n->dev != dev) {
+ np = &n->next;
+ continue;
+ }
+ *np = n->next;
+ write_lock_bh(&n->lock);
+ n->dead = 1;
+ neigh_del_timer(n);
+ write_unlock_bh(&n->lock);
+ neigh_release(n);
+ }
+ }
+
+ write_unlock_bh(&tbl->lock);
}
int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
===== net/ipv4/arp.c 1.11 vs edited =====
--- 1.11/net/ipv4/arp.c Fri Jun 27 09:03:01 2003
+++ edited/net/ipv4/arp.c Tue Aug 19 08:45:36 2003
@@ -1212,6 +1212,26 @@
}
#endif
+static int arp_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+ struct net_device *dev = ptr;
+
+ switch (event) {
+ case NETDEV_CHANGEADDR:
+ neigh_changeaddr(&arp_tbl, dev);
+ rt_cache_flush(0);
+ break;
+ default:
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+
+struct notifier_block arp_netdev_notifier = {
+ .notifier_call = arp_netdev_event,
+};
+
/* Note, that it is not on notifier chain.
It is necessary, that this routine was called after route cache will be
flushed.
@@ -1243,6 +1263,7 @@
#ifdef CONFIG_SYSCTL
neigh_sysctl_register(NULL, &arp_tbl.parms, NET_IPV4, NET_IPV4_NEIGH, "ipv4");
#endif
+ register_netdevice_notifier(&arp_netdev_notifier);
}
===== net/ipv6/ndisc.c 1.22 vs edited =====
--- 1.22/net/ipv6/ndisc.c Tue Jun 24 02:21:28 2003
+++ edited/net/ipv6/ndisc.c Tue Aug 19 08:45:53 2003
@@ -1336,6 +1336,26 @@
return 0;
}
+static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+ struct net_device *dev = ptr;
+
+ switch (event) {
+ case NETDEV_CHANGEADDR:
+ neigh_changeaddr(&nd_tbl, dev);
+ fib6_run_gc(0);
+ break;
+ default:
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+
+struct notifier_block ndisc_netdev_notifier = {
+ .notifier_call = ndisc_netdev_event,
+};
+
int __init ndisc_init(struct net_proto_family *ops)
{
struct sock *sk;
@@ -1377,6 +1397,7 @@
neigh_sysctl_register(NULL, &nd_tbl.parms, NET_IPV6, NET_IPV6_NEIGH, "ipv6");
#endif
+ register_netdevice_notifier(&ndisc_netdev_notifier);
return 0;
}
--
:(){ :|:&};:
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] Change MAC without bringing interface down
2003-08-19 5:50 ` Tommi Virtanen
@ 2003-08-19 15:42 ` Arnaldo Carvalho de Melo
2003-08-19 19:31 ` David S. Miller
1 sibling, 0 replies; 15+ messages in thread
From: Arnaldo Carvalho de Melo @ 2003-08-19 15:42 UTC (permalink / raw)
To: Tommi Virtanen; +Cc: David S. Miller, hadi, netdev
Em Tue, Aug 19, 2003 at 08:50:34AM +0300, Tommi Virtanen escreveu:
> Here's an updated patch with those nits picked. Those were
> all cut-and-pasted from elsewhere, so if you want perfection,
> there's lots of those to fix.
Thank you. And yes, I wish there was a consistent style, and have been
fixing these kinds of nits for years :-)
- Arnaldo
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] Change MAC without bringing interface down
2003-08-19 5:50 ` Tommi Virtanen
2003-08-19 15:42 ` Arnaldo Carvalho de Melo
@ 2003-08-19 19:31 ` David S. Miller
1 sibling, 0 replies; 15+ messages in thread
From: David S. Miller @ 2003-08-19 19:31 UTC (permalink / raw)
To: Tommi Virtanen; +Cc: acme, hadi, netdev
On Tue, 19 Aug 2003 08:50:34 +0300
Tommi Virtanen <tv@debian.org> wrote:
> Here's an updated patch with those nits picked. Those were
> all cut-and-pasted from elsewhere, so if you want perfection,
> there's lots of those to fix.
This patch is fine, I will apply it.
Thank you.
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2003-08-19 19:31 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2003-08-18 9:13 [PATCH] Change MAC without bringing interface down Tommi Virtanen
2003-08-18 11:19 ` David S. Miller
2003-08-18 12:13 ` jamal
2003-08-18 12:12 ` David S. Miller
2003-08-18 13:03 ` jamal
2003-08-18 16:04 ` Tommi Virtanen
2003-08-18 16:06 ` David S. Miller
2003-08-18 17:11 ` Tommi Virtanen
2003-08-18 18:51 ` Arnaldo Carvalho de Melo
2003-08-19 5:50 ` Tommi Virtanen
2003-08-19 15:42 ` Arnaldo Carvalho de Melo
2003-08-19 19:31 ` David S. Miller
2003-08-18 14:24 ` Tommi Virtanen
2003-08-18 14:20 ` David S. Miller
2003-08-18 15:10 ` jamal
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).