Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH 0/24] make atomic_read() behave consistently across all architectures
From: Linus Torvalds @ 2007-08-24 17:19 UTC (permalink / raw)
  To: Denys Vlasenko
  Cc: Satyam Sharma, Christoph Lameter, Paul E. McKenney, Herbert Xu,
	Nick Piggin, Paul Mackerras, Segher Boessenkool, heiko.carstens,
	horms, linux-kernel, rpjday, ak, netdev, cfriesen, akpm,
	jesper.juhl, linux-arch, zlynx, schwidefsky, Chris Snook, davem,
	wensong, wjiang
In-Reply-To: <200708241319.05760.vda.linux@googlemail.com>



On Fri, 24 Aug 2007, Denys Vlasenko wrote:
>
> > No, you don't use "x.counter++". But you *do* use
> >
> > 	if (atomic_read(&x) <= 1)
> >
> > and loading into a register is stupid and pointless, when you could just
> > do it as a regular memory-operand to the cmp instruction.
> 
> It doesn't mean that (volatile int*) cast is bad, it means that current gcc
> is bad (or "not good enough"). IOW: instead of avoiding volatile cast,
> it's better to fix the compiler.

I would agree that fixing the compiler in this case would be a good thing, 
even quite regardless of any "atomic_read()" discussion.

I just have a strong suspicion that "volatile" performance is so low down 
the list of any C compiler persons interest, that it's never going to 
happen. And quite frankly, I cannot blame the gcc guys for it.

That's especially as "volatile" really isn't a very good feature of the C 
language, and is likely to get *less* interesting rather than more (as 
user space starts to be more and more threaded, "volatile" gets less and 
less useful.

[ Ie, currently, I think you can validly use "volatile" in a "sigatomic_t" 
  kind of way, where there is a single thread, but with asynchronous 
  events. In that kind of situation, I think it's probably useful. But 
  once you get multiple threads, it gets pointless.

  Sure: you could use "volatile" together with something like Dekker's or 
  Peterson's algorithm that doesn't depend on cache coherency (that's 
  basically what the C "volatile" keyword approximates: not atomic 
  accesses, but *uncached* accesses! But let's face it, that's way past 
  insane. ]

So I wouldn't expect "volatile" to ever really generate better code. It 
might happen as a side effect of other improvements (eg, I might hope that 
the SSA work would eventually lead to gcc having a much better defined 
model of valid optimizations, and maybe better code generation for 
volatile accesses fall out cleanly out of that), but in the end, it's such 
an ugly special case in C, and so seldom used, that I wouldn't depend on 
it.

> Linus, in all honesty gcc has many more cases of suboptimal code,
> case of "volatile" is just one of many.

Well, the thing is, quite often, many of those "suboptimal code" 
generations fall into two distinct classes:

 - complex C code. I can't really blame the compiler too much for this. 
   Some things are *hard* to optimize, and for various scalability 
   reasons, you often end up having limits in the compiler where it 
   doesn't even _try_ doing certain optimizations if you have excessive 
   complexity.

 - bad register allocation. Register allocation really is hard, and 
   sometimes gcc just does the "obviously wrong" thing, and you end up 
   having totally unnecessary spills.

> Off the top of my head:

Yes, "unsigned long long" with x86 has always generated atrocious code. In 
fact, I would say that historically it was really *really* bad. These 
days, gcc actually does a pretty good job, but I'm not surprised that it's 
still quite possible to find cases where it did some optimization (in this 
case, apparently noticing that "shift by >= 32 bits" causes the low 
register to be pointless) and then missed *another* optimization (better 
register use) because that optimization had been done *before* the first 
optimization was done.

That's a *classic* example of compiler code generation issues, and quite 
frankly, I think that's very different from the issue of "volatile".

Quite frankly, I'd like there to be more competition in the open source 
compiler game, and that might cause some upheavals, but on the whole, gcc 
actually does a pretty damn good job. 

			Linus

^ permalink raw reply

* Re: [3/4] 2.6.23-rc3: known regressions v3
From: Michal Piotrowski @ 2007-08-24 17:38 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Andrew Morton, LKML, Netdev, Stephen Hemminger, Thomas Meyer,
	Shish, Karl Meyer, Francois Romieu, linux-pm, Rafael J. Wysocki,
	Pavel Machek, Arkadiusz Miskiewicz, Thomas Voegtle
In-Reply-To: <46CF0DEF.5040107@googlemail.com>

Hi all,

Here is a list of some known regressions in 2.6.23-rc3.

Feel free to add new regressions/remove fixed etc.
http://kernelnewbies.org/known_regressions

List of Aces

Name                    Regressions fixed since 21-Jun-2007
Adrian Bunk                            9
Andi Kleen                             5
Linus Torvalds                         5
Andrew Morton                          4
Al Viro                                3
Alan Stern                             3
Cornelia Huck                          3
Jens Axboe                             3
Tejun Heo                              3



Networking

Subject         : NETDEV WATCHDOG: eth0: transmit timed out
References      : http://lkml.org/lkml/2007/8/13/737
Last known good : ?
Submitter       : Karl Meyer <adhocrocker@gmail.com>
Caused-By       : ?
Handled-By      : Francois Romieu <romieu@fr.zoreil.com>
Status          : problem is being debugged

Subject         : Weird network problems with 2.6.23-rc2
References      : http://lkml.org/lkml/2007/8/11/40
Last known good : ?
Submitter       : Shish <shish@shishnet.org>
Caused-By       : ?
Handled-By      : ?
Status          : unknown

Subject         : New wake ups from sky2
References      : http://lkml.org/lkml/2007/7/20/386
Last known good : ?
Submitter       : Thomas Meyer <thomas@m3y3r.de>
Caused-By       : Stephen Hemminger <shemminger@osdl.org>
                  commit eb35cf60e462491249166182e3e755d3d5d91a28
Handled-By      : Stephen Hemminger <shemminger@osdl.org>
Status          : unknown



Power management

Subject         : 2.6.23-rc2 swsusp, suddenly increased uptime
References      : http://lkml.org/lkml/2007/8/12/249
Last known good : ?
Submitter       : Thomas Voegtle <tv@lio96.de>
Caused-By       : ?
Handled-By      : Rafael J. Wysocki <rjw@sisk.pl>
Status          : problem is being debugged

Subject         : resume from ram much slower
References      : http://lkml.org/lkml/2007/8/10/275
Last known good : 2.6.23-rc1 ?
Submitter       : Arkadiusz Miskiewicz <arekm@maven.pl>
Caused-By       : ?
Handled-By      : Rafael J. Wysocki <rjw@sisk.pl>
Status          : problem is being debugged



Regards,
Michal

--
LOG
http://www.stardust.webpages.pl/log/

^ permalink raw reply

* Re: [2/2] 2.6.23-rc3: known regressions with patches v3
From: Michal Piotrowski @ 2007-08-24 17:39 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Andrew Morton, LKML, linux-mtd, David Woodhouse, Ingo Molnar,
	Netdev, Stephen Hemminger, Florian Lohoff, Daniel K.
In-Reply-To: <46CF1705.8060904@googlemail.com>

Hi all,

Here is a list of some known regressions in 2.6.23-rc3
with patches available.

Feel free to add new regressions/remove fixed etc.
http://kernelnewbies.org/known_regressions

List of Aces

Name                    Regressions fixed since 21-Jun-2007
Adrian Bunk                            9
Andi Kleen                             5
Linus Torvalds                         5
Andrew Morton                          4
Al Viro                                3
Alan Stern                             3
Cornelia Huck                          3
Jens Axboe                             3
Tejun Heo                              3



MTD

Subject         : error: implicit declaration of function 'cfi_interleave'
References      : http://lkml.org/lkml/2007/8/6/272
Last known good : ?
Submitter       : Ingo Molnar <mingo@elte.hu>
Caused-By       : ?
Handled-By      : David Woodhouse <dwmw2@infradead.org>
Patch           : http://lkml.org/lkml/2007/8/9/586
Status          : patch available



Networking

Subject         : BUG: when using 'brctl stp'
References      : http://lkml.org/lkml/2007/8/10/441
Last known good : 2.6.23-rc1
Submitter       : Daniel K. <daniel@cluded.net>
Caused-By       : ?
Handled-By      : Stephen Hemminger <shemminger@osdl.org>
Status          : fix applied by David Miller

Subject         : sky2 boot crash in sky2_mac_intr
References      : http://lkml.org/lkml/2007/7/24/91
Last known good : ?
Submitter       : Florian Lohoff <flo@rfc822.org>
Caused-By       : 
Handled-By      : Stephen Hemminger <shemminger@osdl.org>
Patch           : http://marc.info/?l=linux-netdev&m=118651402523966&w=2
Status          : patch available



Regards,
Michal

--
LOG
http://www.stardust.webpages.pl/log/

^ permalink raw reply

* Re: [PATCH] i386: Fix a couple busy loops in mach_wakecpu.h:wait_for_init_deassert()
From: Linus Torvalds @ 2007-08-24 17:34 UTC (permalink / raw)
  To: Denys Vlasenko
  Cc: Kenn Humborg, Satyam Sharma, Heiko Carstens, Herbert Xu,
	Chris Snook, clameter, Linux Kernel Mailing List, linux-arch,
	netdev, Andrew Morton, ak, davem, schwidefsky, wensong, horms,
	wjiang, cfriesen, zlynx, rpjday, jesper.juhl, segher
In-Reply-To: <200708241525.51049.vda.linux@googlemail.com>



On Fri, 24 Aug 2007, Denys Vlasenko wrote:
> 
> So you are ok with compiler propagating n1 to n2 here:
> 
> n1 += atomic_read(x);
> other_variable++;
> n2 += atomic_read(x);
> 
> without accessing x second time. What's the point? Any sane coder
> will say that explicitly anyway:

No.

This is a common mistake, and it's total crap.

Any "sane coder" will often use inline functions, macros, etc helpers to 
do certain abstract things. Those things may contain "atomic_read()" 
calls.

The biggest reason for compilers doing CSE is exactly the fact that many 
opportunities for CSE simple *are*not*visible* on a source code level. 

That is true of things like atomic_read() equally as to things like shared 
offsets inside structure member accesses. No difference what-so-ever.

Yes, we have, traditionally, tried to make it *easy* for the compiler to 
generate good code. So when we can, and when we look at performance for 
some really hot path, we *will* write the source code so that the compiler 
doesn't even have the option to screw it up, and that includes things like 
doing CSE at a source code level so that we don't see the compiler 
re-doing accesses unnecessarily.

And I'm not saying we shouldn't do that. But "performance" is not an 
either-or kind of situation, and we should:

 - spend the time at a source code level: make it reasonably easy for the 
   compiler to generate good code, and use the right algorithms at a 
   higher level (and order structures etc so that they have good cache 
   behaviour).

 - .. *and* expect the compiler to handle the cases we didn't do by hand
   pretty well anyway. In particular, quite often, abstraction levels at a 
   software level means that we give compilers "stupid" code, because some 
   function may have a certain high-level abstraction rule, but then on a 
   particular architecture it's actually a no-op, and the compiler should 
   get to "untangle" our stupid code and generate good end results.

 - .. *and* expect the hardware to be sane and do a good job even when the 
   compiler didn't generate perfect code or there were unlucky cache miss
   patterns etc.

and if we do all of that, we'll get good performance. But you really do 
want all three levels. It's not enough to be good at any one level (or 
even any two).

			Linus

^ permalink raw reply

* Re: [Devel] [PATCH 1/1] Dynamically allocate the loopback device
From: Stephen Hemminger @ 2007-08-24 17:43 UTC (permalink / raw)
  To: Denis V. Lunev
  Cc: containers-qjLDD68F18O7TbgM5vRIOg, netdev-u79uwXL29TY76Z2rM5mHXA,
	davem-fT/PcQaiUtIeIZ0/mPfg9Q
In-Reply-To: <46CEFF83.3040003-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

On Fri, 24 Aug 2007 19:55:47 +0400
"Denis V. Lunev" <dlunev-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:

> dlezcano-NmTC/0ZBporQT0dZR+AlfA@public.gmane.org wrote:
> > From: Daniel Lezcano <dlezcano-NmTC/0ZBporQT0dZR+AlfA@public.gmane.org>
> > 
> > Doing this makes loopback.c a better example of how to do a
> > simple network device, and it removes the special case
> > single static allocation of a struct net_device, hopefully
> > making maintenance easier.
> > 
> > Applies against net-2.6.24
> > 
> > Tested on i386, x86_64
> > Compiled on ia64, sparc
> 
> I think that a small note, that initialization order is changed will be
> good to record. After this, loopback MUST be allocated before any other
> networking subsystem initialization. And this is an important change.
> 
> Regards,
>     Den

Yes, this code would break when other drivers are directly linked
in. 

^ permalink raw reply

* Re: RFC: issues concerning the next NAPI interface
From: Shirley Ma @ 2007-08-24 17:45 UTC (permalink / raw)
  To: Linas Vepstas
  Cc: akepner, linux-kernel, linux-ppc, Marcus, Eder, netdev,
	netdev-owner, Jan-Bernd Themann, Christoph Raisch,
	Stephen Hemminger, Stefan Roscher, Jan-Bernd Themann,
	Thomas Klein
In-Reply-To: <20070824165110.GH4282@austin.ibm.com>

> Just to be clear, in the previous email I posted on this thread, I
> described a worst-case network ping-pong test case (send a packet, wait
> for reply), and found out that a deffered interrupt scheme just damaged
> the performance of the test case. 

When splitting rx and tx handler, I found some performance gain by 
deffering interrupt scheme in tx not rx in IPoIB driver.

Shirley

^ permalink raw reply

* Re: [3/4] 2.6.23-rc3: known regressions v3
From: Stephen Hemminger @ 2007-08-24 17:46 UTC (permalink / raw)
  To: Michal Piotrowski
  Cc: Linus Torvalds, Andrew Morton, LKML, Netdev, Thomas Meyer, Shish,
	Karl Meyer, Francois Romieu, linux-pm, Rafael J. Wysocki,
	Pavel Machek, Arkadiusz Miskiewicz, Thomas Voegtle
In-Reply-To: <46CF1796.1020004@googlemail.com>

O
> Subject         : New wake ups from sky2
> References      : http://lkml.org/lkml/2007/7/20/386
> Last known good : ?
> Submitter       : Thomas Meyer <thomas@m3y3r.de>
> Caused-By       : Stephen Hemminger <shemminger@osdl.org>
>                   commit eb35cf60e462491249166182e3e755d3d5d91a28
> Handled-By      : Stephen Hemminger <shemminger@osdl.org>
> Status          : unknown
> 
>

Fix posted to netdev (sky2 1.17 series), but Jeff hasn't 
applied it.

^ permalink raw reply

* [PATCH] isdn capi driver broken on 64 bit.
From: Stephen Hemminger @ 2007-08-24 18:08 UTC (permalink / raw)
  To: Karsten Keil; +Cc: isdn4linux, netdev

The following driver API is broken on any architecture with 64 bit addresses.
because of cast that loses high bits.

Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>


--- a/drivers/isdn/capi/capidrv.c	2007-06-25 09:03:12.000000000 -0700
+++ b/drivers/isdn/capi/capidrv.c	2007-08-24 11:06:46.000000000 -0700
@@ -1855,6 +1855,9 @@ static int if_sendbuf(int id, int channe
 		return 0;
 	}
 	datahandle = nccip->datahandle;
+
+	/* This won't work on 64 bit! */
+	BUILD_BUG_ON(sizeof(skb->data) > sizeof(u32));
 	capi_fill_DATA_B3_REQ(&sendcmsg, global.ap.applid, card->msgid++,
 			      nccip->ncci,	/* adr */
 			      (u32) skb->data,	/* Data */

^ permalink raw reply

* [ofa-general] Re: [PATCH 0/9 Rev3] Implement batching skb API and support in IPoIB
From: Bill Fink @ 2007-08-24 18:08 UTC (permalink / raw)
  To: hadi
  Cc: jagana, peter.p.waskiewicz.jr, herbert, gaagaan, Robert.Olsson,
	netdev, rdreier, mcarlson, kaber, jeff, general, mchan, tgraf,
	johnpol, shemminger, David Miller, sri
In-Reply-To: <1187957657.4255.35.camel@localhost>

On Fri, 24 Aug 2007, jamal wrote:

> On Thu, 2007-23-08 at 23:18 -0400, Bill Fink wrote:
> 
> [..]
> > Here you can see there is a major difference in the TX CPU utilization
> > (99 % with TSO disabled versus only 39 % with TSO enabled), although
> > the TSO disabled case was able to squeeze out a little extra performance
> > from its extra CPU utilization.  
> 
> Good stuff. What kind of machine? SMP?

Tyan Thunder K8WE S2895ANRF motherboard with Nvidia nForce
Professional 2200+2050 chipset, 2 AMD Opteron 254 2.8 GHz CPUs,
4 GB PC3200 ECC REG-DDR 400 memory, and 2 PCI-Express x16 slots
(2 buses).

It is SMP but both the NIC interrupts and nuttcp are bound to
CPU 0.  And all other non-kernel system processes are bound to
CPU 1.

> Seems the receive side of the sender is also consuming a lot more cpu
> i suspect because receiver is generating a lot more ACKs with TSO.

Odd.  I just reran the TCP CUBIC "-M1460" tests, and with TSO enabled
on the transmitter, there were about 153709 eth2 interrupts on the
receiver, while with TSO disabled there was actually a somewhat higher
number (164988) of receiver side eth2 interrupts, although the receive
side CPU utilization was actually lower in that case.

On the transmit side (different test run), the TSO enabled case had
about 161773 eth2 interrupts whereas the TSO disabled case had about
165179 eth2 interrupts.

> Does the choice of the tcp congestion control algorithm affect results?
> it would be interesting to see both MTUs with either TCP BIC vs good old
> reno on sender (probably without changing what the receiver does). BIC
> seems to be the default lately.

These tests were with the default TCP CUBIC (with initial_ssthresh
set to 0).

With TCP BIC (and initial_ssthresh set to 0):

TSO enabled:

[root@lang2 ~]# nuttcp -w10m 192.168.88.16
11751.3750 MB /  10.00 sec = 9853.9839 Mbps 100 %TX 83 %RX

[root@lang2 ~]# nuttcp -M1460 -w10m 192.168.88.16
 4999.3321 MB /  10.06 sec = 4167.7872 Mbps 38 %TX 100 %RX

TSO disabled:

[root@lang2 ~]# nuttcp -w10m 192.168.88.16
11818.1875 MB /  10.00 sec = 9910.0682 Mbps 99 %TX 81 %RX

[root@lang2 ~]# nuttcp -M1460 -w10m 192.168.88.16
 5502.6250 MB /  10.00 sec = 4614.3297 Mbps 100 %TX 84 %RX

And with TCP Reno:

TSO enabled:

[root@lang2 ~]# nuttcp -w10m 192.168.88.16
11782.6250 MB /  10.00 sec = 9880.2613 Mbps 100 %TX 77 %RX

[root@lang2 ~]# nuttcp -M1460 -w10m 192.168.88.16
 5024.6649 MB /  10.06 sec = 4191.6574 Mbps 38 %TX 99 %RX

TSO disabled:

[root@lang2 ~]# nuttcp -w10m 192.168.88.16
11818.2500 MB /  10.00 sec = 9910.0860 Mbps 99 %TX 77 %RX

[root@lang2 ~]# nuttcp -M1460 -w10m 192.168.88.16
 5284.0000 MB /  10.00 sec = 4430.9604 Mbps 99 %TX 79 %RX

Very similar results to the original TCP CUBIC tests.

> > Interestingly, with TSO enabled, the
> > receiver actually consumed more CPU than with TSO disabled, 
> 
> I would suspect the fact that a lot more packets making it into the
> receiver for TSO contributes.
> 
> > so I guess
> > the receiver CPU saturation in that case (99 %) was what restricted
> > its performance somewhat (this was consistent across a few test runs).
> 
> Unfortunately the receiver plays a big role in such tests - if it is
> bottlenecked then you are not really testing the limits of the
> transmitter. 

It might be interesting to see what affect the LRO changes would have
on this.  Once they are in a stable released kernel, I might try that
out, or maybe even before if I get some spare time (but that's in very
short supply right now).

						-Thanks

						-Bill

^ permalink raw reply

* Re: RFC: issues concerning the next NAPI interface
From: Jan-Bernd Themann @ 2007-08-24 18:11 UTC (permalink / raw)
  To: James Chapman
  Cc: Stephen Hemminger, akepner, netdev, Christoph Raisch,
	Jan-Bernd Themann, linux-kernel, linux-ppc, Marcus Eder,
	Thomas Klein, Stefan Roscher
In-Reply-To: <46CF127D.1090609@katalix.com>

James Chapman schrieb:
> Stephen Hemminger wrote:
>> On Fri, 24 Aug 2007 17:47:15 +0200
>> Jan-Bernd Themann <ossthema@de.ibm.com> wrote:
>>
>>> Hi,
>>>
>>> On Friday 24 August 2007 17:37, akepner@sgi.com wrote:
>>>> On Fri, Aug 24, 2007 at 03:59:16PM +0200, Jan-Bernd Themann wrote:
>>>>> .......
>>>>> 3) On modern systems the incoming packets are processed very fast. 
>>>>> Especially
>>>>>    on SMP systems when we use multiple queues we process only a 
>>>>> few packets
>>>>>    per napi poll cycle. So NAPI does not work very well here and 
>>>>> the interrupt    rate is still high. What we need would be some 
>>>>> sort of timer polling mode    which will schedule a device after a 
>>>>> certain amount of time for high load    situations. With high 
>>>>> precision timers this could work well. Current
>>>>>    usual timers are too slow. A finer granularity would be needed 
>>>>> to keep the
>>>>>    latency down (and queue length moderate).
>>>>>
>>>> We found the same on ia64-sn systems with tg3 a couple of years 
>>>> ago. Using simple interrupt coalescing ("don't interrupt until 
>>>> you've received N packets or M usecs have elapsed") worked 
>>>> reasonably well in practice. If your h/w supports that (and I'd 
>>>> guess it does, since it's such a simple thing), you might try it.
>>>>
>>> I don't see how this should work. Our latest machines are fast 
>>> enough that they
>>> simply empty the queue during the first poll iteration (in most cases).
>>> Even if you wait until X packets have been received, it does not 
>>> help for
>>> the next poll cycle. The average number of packets we process per 
>>> poll queue
>>> is low. So a timer would be preferable that periodically polls the 
>>> queue, without the need of generating a HW interrupt. This would 
>>> allow us
>>> to wait until a reasonable amount of packets have been received in 
>>> the meantime
>>> to keep the poll overhead low. This would also be useful in combination
>>> with LRO.
>>>
>>
>> You need hardware support for deferred interrupts. Most devices have 
>> it (e1000, sky2, tg3)
>> and it interacts well with NAPI. It is not a generic thing you want 
>> done by the stack,
>> you want the hardware to hold off interrupts until X packets or Y 
>> usecs have expired.
>
> Does hardware interrupt mitigation really interact well with NAPI? In 
> my experience, holding off interrupts for X packets or Y usecs does 
> more harm than good; such hardware features are useful only when the 
> OS has no NAPI-like mechanism.
>
> When tuning NAPI drivers for packets/sec performance (which is a good 
> indicator of driver performance), I make sure that the driver stays in 
> NAPI polled mode while it has any rx or tx work to do. If the CPU is 
> fast enough that all work is always completed on each poll, I have the 
> driver stay in polled mode until dev->poll() is called N times with no 
> work being done. This keeps interrupts disabled for reasonable traffic 
> levels, while minimizing packet processing latency. No need for 
> hardware interrupt mitigation.
Yes, that was one idea as well. But the problem with that is that 
net_rx_action will call
the same poll function over and over again in a row if there are no 
further network
devices. The problem about this approach is that you always poll just a 
very few packets
each time. This does not work with LRO well, as there are no packets to 
aggregate...
So it would make more sense to wait for a certain time before trying it 
again.
Second problem: after the jiffies incremented by one in net_rx_action 
(after some poll rounds), net_rx_action will quit and return control to 
the softIRQ handler. The poll function
is called again as the softIRQ handler thinks there is more work to be 
done. So even
then we do not wait... After some rounds in the softIRQ handler, we 
finally wait some time.

>
>> The parameters for controlling it are already in ethtool, the issue 
>> is finding a good
>> default set of values for a wide range of applications and 
>> architectures. Maybe some
>> heuristic based on processor speed would be a good starting point. 
>> The dynamic irq
>> moderation stuff is not widely used because it is too hard to get right.
>
> I agree. It would be nice to find a way for the typical user to derive 
> best values for these knobs for his/her particular system. Perhaps a 
> tool using pktgen and network device phy internal loopback could be 
> developed?
>



^ permalink raw reply

* [ofa-general] Re: [PATCH 0/9 Rev3] Implement batching skb API and support in IPoIB
From: Rick Jones @ 2007-08-24 18:46 UTC (permalink / raw)
  To: Bill Fink
  Cc: jagana, herbert, gaagaan, Robert.Olsson, mcarlson, rdreier,
	peter.p.waskiewicz.jr, hadi, kaber, jeff, general, mchan, tgraf,
	netdev, johnpol, shemminger, David Miller, sri
In-Reply-To: <20070823231820.2ae52cc0.billfink@mindspring.com>

Bill Fink wrote:
> On Thu, 23 Aug 2007, Rick Jones wrote:
> 
> 
>>jamal wrote:
>>
>>>[TSO already passed - iirc, it has been
>>>demostranted to really not add much to throughput (cant improve much
>>>over closeness to wire speed) but improve CPU utilization].
>>
>>In the one gig space sure, but in the 10 Gig space, TSO on/off does make a 
>>difference for throughput.
> 
> 
> Not too much.
> 
> TSO enabled:
> 
> [root@lang2 ~]# ethtool -k eth2
> Offload parameters for eth2:
> rx-checksumming: on
> tx-checksumming: on
> scatter-gather: on
> tcp segmentation offload: on
> 
> [root@lang2 ~]# nuttcp -w10m 192.168.88.16
> 11813.4375 MB /  10.00 sec = 9906.1644 Mbps 99 %TX 80 %RX
> 
> TSO disabled:
> 
> [root@lang2 ~]# ethtool -K eth2 tso off
> [root@lang2 ~]# ethtool -k eth2
> Offload parameters for eth2:
> rx-checksumming: on
> tx-checksumming: on
> scatter-gather: on
> tcp segmentation offload: off
> 
> [root@lang2 ~]# nuttcp -w10m 192.168.88.16
> 11818.2500 MB /  10.00 sec = 9910.0176 Mbps 100 %TX 78 %RX
> 
> Pretty negligible difference it seems.

Leaves one wondering how often more than one segment was sent to the card in the 
9000 byte case :)

rick jones

^ permalink raw reply

* Re: RFC: issues concerning the next NAPI interface
From: Bodo Eggert @ 2007-08-24 19:04 UTC (permalink / raw)
  To: Linas Vepstas, Jan-Bernd Themann, netdev, Thomas Klein,
	Jan-Bernd Themann
In-Reply-To: <8VKwj-8ke-27@gated-at.bofh.it>

Linas Vepstas <linas@austin.ibm.com> wrote:
> On Fri, Aug 24, 2007 at 03:59:16PM +0200, Jan-Bernd Themann wrote:

>> 3) On modern systems the incoming packets are processed very fast. Especially
>> on SMP systems when we use multiple queues we process only a few packets
>> per napi poll cycle. So NAPI does not work very well here and the interrupt
>> rate is still high.
> 
> I saw this too, on a system that is "modern" but not terribly fast, and
> only slightly (2-way) smp. (the spidernet)
> 
> I experimented wih various solutions, none were terribly exciting.  The
> thing that killed all of them was a crazy test case that someone sprung on
> me:  They had written a worst-case network ping-pong app: send one
> packet, wait for reply, send one packet, etc.
> 
> If I waited (indefinitely) for a second packet to show up, the test case
> completely stalled (since no second packet would ever arrive).  And if I
> introduced a timer to wait for a second packet, then I just increased
> the latency in the response to the first packet, and this was noticed,
> and folks complained.

Possible solution / possible brainfart:

Introduce a timer, but don't start to use it to combine packets unless you
receive n packets within the timeframe. If you receive less than m packets
within one timeframe, stop using the timer. The system should now have a
decent response time when the network is idle, and when the network is
busy, nobody will complain about the latency.-)
-- 
Funny quotes:
22. When everything's going your way, you're in the wrong lane and and going
    the wrong way.
Friß, Spammer: rsRxhvmk@CaR.7eggert.dyndns.org m@z3T.7eggert.dyndns.org

^ permalink raw reply

* Re: [PATCH v2] [02/10] pasemi_mac: Stop using the pci config space accessors for register read/writes
From: Olof Johansson @ 2007-08-24 18:11 UTC (permalink / raw)
  To: Stephen Rothwell; +Cc: netdev, jgarzik, linuxppc-dev
In-Reply-To: <20070824140531.ff7d66bf.sfr@canb.auug.org.au>

On Fri, Aug 24, 2007 at 02:05:31PM +1000, Stephen Rothwell wrote:
> On Thu, 23 Aug 2007 13:13:10 -0500 Olof Johansson <olof@lixom.net> wrote:
> >
> >  out:
> > -	pci_dev_put(mac->iob_pdev);
> > -out_put_dma_pdev:
> > -	pci_dev_put(mac->dma_pdev);
> > -out_free_netdev:
> > +	if (mac->iob_pdev)
> > +		pci_dev_put(mac->iob_pdev);
> > +	if (mac->dma_pdev)
> > +		pci_dev_put(mac->dma_pdev);
> 
> It is not documented as such (as far as I can see), but pci_dev_put is
> safe to call with NULL. And there are other places in the kernel that
> explicitly use that fact.

Some places check, others do not. I'll leave it be for now but might take
care of it during some future cleanup. Thanks for point it out though.


-Olof

^ permalink raw reply

* Re: [ANNOUNCE] iproute2-2.6.23-rc3
From: Stephen Hemminger @ 2007-08-24 19:26 UTC (permalink / raw)
  To: Jarek Poplawski; +Cc: netdev
In-Reply-To: <20070824101044.GA2913@ff.dom.local>

On Fri, 24 Aug 2007 12:10:44 +0200
Jarek Poplawski <jarkao2@o2.pl> wrote:

> On 22-08-2007 20:08, Stephen Hemminger wrote:
> > There have been a lot of changes for 2.6.23, so here is a test release
> > of iproute2 that should capture all the submitted patches
> > 
> > 
> > http://developer.osdl.org/shemminger/iproute2/download/iproute2-2.6.23-rc3.tar.gz
> 
> But... isn't it forged, btw?!

No, I just didn't sign a temporary testing version.  A final version
will be out after 2.6.23

-- 
Stephen Hemminger <shemminger@linux-foundation.org>

^ permalink raw reply

* Re: [PATCH 0/24] make atomic_read() behave consistently across all architectures
From: Denys Vlasenko @ 2007-08-24 20:21 UTC (permalink / raw)
  To: Christoph Lameter
  Cc: Paul Mackerras, Satyam Sharma, Stefan Richter, Chris Snook,
	Linux Kernel Mailing List, linux-arch, Linus Torvalds, netdev,
	Andrew Morton, ak, heiko.carstens, davem, schwidefsky, wensong,
	horms, wjiang, cfriesen, zlynx, rpjday, jesper.juhl, segher,
	Herbert Xu, Paul E. McKenney
In-Reply-To: <Pine.LNX.4.64.0708241009120.20501@schroedinger.engr.sgi.com>

On Friday 24 August 2007 18:15, Christoph Lameter wrote:
> On Fri, 24 Aug 2007, Denys Vlasenko wrote:
> > On Thursday 16 August 2007 00:22, Paul Mackerras wrote:
> > > Satyam Sharma writes:
> > > In the kernel we use atomic variables in precisely those situations
> > > where a variable is potentially accessed concurrently by multiple
> > > CPUs, and where each CPU needs to see updates done by other CPUs in a
> > > timely fashion.  That is what they are for.  Therefore the compiler
> > > must not cache values of atomic variables in registers; each
> > > atomic_read must result in a load and each atomic_set must result in a
> > > store.  Anything else will just lead to subtle bugs.
> >
> > Amen.
>
> A "timely" fashion? One cannot rely on something like that when coding.
> The visibility of updates is insured by barriers and not by some fuzzy
> notion of "timeliness".

But here you do have some notion of time:

	while (atomic_read(&x))
		continue;

"continue when other CPU(s) decrement it down to zero".
If "read" includes an insn which accesses RAM, you will
see "new" value sometime after other CPU decrements it.
"Sometime after" is on the order of nanoseconds here.
It is a valid concept of time, right?

The whole confusion is about whether atomic_read implies
"read from RAM" or not. I am in a camp which thinks it does.
You are in an opposite one.

We just need a less ambiguous name.

What about this:

/**
 * atomic_read - read atomic variable
 * @v: pointer of type atomic_t
 *
 * Atomically reads the value of @v.
 * No compiler barrier implied.
 */
#define atomic_read(v)          ((v)->counter)

+/**
+ * atomic_read_uncached - read atomic variable from memory
+ * @v: pointer of type atomic_t
+ *
+ * Atomically reads the value of @v. This is guaranteed to emit an insn
+ * which accesses memory, atomically. No ordering guarantees!
+ */
+#define atomic_read_uncached(v)  asm_or_volatile_ptr_magic(v)

I was thinking of s/atomic_read/atomic_get/ too, but it implies "taking"
atomic a-la get_cpu()...
--
vda

^ permalink raw reply

* Re: [PATCH] i386: Fix a couple busy loops in mach_wakecpu.h:wait_for_init_deassert()
From: Denys Vlasenko @ 2007-08-24 20:26 UTC (permalink / raw)
  To: Christoph Lameter
  Cc: Satyam Sharma, Heiko Carstens, Herbert Xu, Chris Snook,
	Linux Kernel Mailing List, linux-arch, Linus Torvalds, netdev,
	Andrew Morton, ak, davem, schwidefsky, wensong, horms, wjiang,
	cfriesen, zlynx, rpjday, jesper.juhl, segher, Nick Piggin
In-Reply-To: <Pine.LNX.4.64.0708241005360.20501@schroedinger.engr.sgi.com>

On Friday 24 August 2007 18:06, Christoph Lameter wrote:
> On Fri, 24 Aug 2007, Satyam Sharma wrote:
> > But if people do seem to have a mixed / confused notion of atomicity
> > and barriers, and if there's consensus, then as I'd said earlier, I
> > have no issues in going with the consensus (eg. having API variants).
> > Linus would be more difficult to convince, however, I suspect :-)
>
> The confusion may be the result of us having barrier semantics in
> atomic_read. If we take that out then we may avoid future confusions.

I think better name may help. Nuke atomic_read() altogether.

n = atomic_value(x);	// doesnt hint as strongly at reading as "atomic_read"
n = atomic_fetch(x);	// yes, we _do_ touch RAM
n = atomic_read_uncached(x); // or this

How does that sound?
--
vda

^ permalink raw reply

* Re: [PATCH] i386: Fix a couple busy loops in mach_wakecpu.h:wait_for_init_deassert()
From: Chris Snook @ 2007-08-24 20:34 UTC (permalink / raw)
  To: Denys Vlasenko
  Cc: Christoph Lameter, Satyam Sharma, Heiko Carstens, Herbert Xu,
	Linux Kernel Mailing List, linux-arch, Linus Torvalds, netdev,
	Andrew Morton, ak, davem, schwidefsky, wensong, horms, wjiang,
	cfriesen, zlynx, rpjday, jesper.juhl, segher, Nick Piggin
In-Reply-To: <200708242126.58305.vda.linux@googlemail.com>

Denys Vlasenko wrote:
> On Friday 24 August 2007 18:06, Christoph Lameter wrote:
>> On Fri, 24 Aug 2007, Satyam Sharma wrote:
>>> But if people do seem to have a mixed / confused notion of atomicity
>>> and barriers, and if there's consensus, then as I'd said earlier, I
>>> have no issues in going with the consensus (eg. having API variants).
>>> Linus would be more difficult to convince, however, I suspect :-)
>> The confusion may be the result of us having barrier semantics in
>> atomic_read. If we take that out then we may avoid future confusions.
> 
> I think better name may help. Nuke atomic_read() altogether.
> 
> n = atomic_value(x);	// doesnt hint as strongly at reading as "atomic_read"
> n = atomic_fetch(x);	// yes, we _do_ touch RAM
> n = atomic_read_uncached(x); // or this
> 
> How does that sound?

atomic_value() vs. atomic_fetch() should be rather unambiguous. 
atomic_read_uncached() begs the question of precisely which cache we are 
avoiding, and could itself cause confusion.

So, if I were writing atomic.h from scratch, knowing what I know now, I think 
I'd use atomic_value() and atomic_fetch().  The problem is that there are a lot 
of existing users of atomic_read(), and we can't write a script to correctly 
guess their intent.  I'm not sure auditing all uses of atomic_read() is really 
worth the comparatively miniscule benefits.

We could play it safe and convert them all to atomic_fetch(), or we could 
acknowledge that changing the semantics 8 months ago was not at all disastrous, 
and make them all atomic_value(), allowing people to use atomic_fetch() where 
they really care.

	-- Chris

^ permalink raw reply

* Re: RFC: issues concerning the next NAPI interface
From: Linas Vepstas @ 2007-08-24 20:42 UTC (permalink / raw)
  To: Bodo Eggert
  Cc: Jan-Bernd Themann, netdev, Thomas Klein, Jan-Bernd Themann,
	linux-kernel, linux-ppc, Christoph Raisch, Marcus Eder,
	Stefan Roscher
In-Reply-To: <E1IOeSm-0000bm-Jo@be1.lrz>

On Fri, Aug 24, 2007 at 09:04:56PM +0200, Bodo Eggert wrote:
> Linas Vepstas <linas@austin.ibm.com> wrote:
> > On Fri, Aug 24, 2007 at 03:59:16PM +0200, Jan-Bernd Themann wrote:
> >> 3) On modern systems the incoming packets are processed very fast. Especially
> >> on SMP systems when we use multiple queues we process only a few packets
> >> per napi poll cycle. So NAPI does not work very well here and the interrupt
> >> rate is still high.
> > 
> > worst-case network ping-pong app: send one
> > packet, wait for reply, send one packet, etc.
> 
> Possible solution / possible brainfart:
> 
> Introduce a timer, but don't start to use it to combine packets unless you
> receive n packets within the timeframe. If you receive less than m packets
> within one timeframe, stop using the timer. The system should now have a
> decent response time when the network is idle, and when the network is
> busy, nobody will complain about the latency.-)

Ohh, that was inspirational. Let me free-associate some wild ideas.

Suppose we keep a running average of the recent packet arrival rate,
Lets say its 10 per millisecond ("typical" for a gigabit eth runnning
flat-out).  If we could poll the driver at a rate of 10-20 per
millisecond (i.e. letting the OS do other useful work for 0.05 millisec),
then we could potentially service the card without ever having to enable 
interrupts on the card, and without hurting latency.

If the packet arrival rate becomes slow enough, we go back to an
interrupt-driven scheme (to keep latency down).

The main problem here is that, even for HZ=1000 machines, this amounts 
to 10-20 polls per jiffy.  Which, if implemented in kernel, requires 
using the high-resolution timers. And, umm, don't the HR timers require
a cpu timer interrupt to make them go? So its not clear that this is much
of a win.

The eHEA is a 10 gigabit device, so it can expect 80-100 packets per
millisecond for large packets, and even more, say 1K packets per
millisec, for small packets. (Even the spec for my 1Gb spidernet card
claims its internal rate is 1M packets/sec.) 

Another possiblity is to set HZ to 5000 or 20000 or something humongous
... after all cpu's are now faster! But, since this might be wasteful,
maybe we could make HZ be dynamically variable: have high HZ rates when
there's lots of network/disk activity, and low HZ rates when not. That
means a non-constant jiffy.

If all drivers used interrupt mitigation, then the variable-high
frequency jiffy could take thier place, and be more "fair" to everyone.
Most drivers would be polled most of the time when they're busy, and 
only use interrupts when they're not.
 
--linas

^ permalink raw reply

* [PATCH 0/3] move hardware header functions out of netdevice
From: Stephen Hemminger @ 2007-08-24 20:43 UTC (permalink / raw)
  To: David Miller; +Cc: netdev

The follow patches series starts the process of moving function
pointers out of network device structure. This saves space and
separates code from data.

The first step is moving the functions dealing with hardware
headers.

Patches are against current net-2.6.24 tree. Basic functional
testing on ethernet part, not on all the other protocols affected.

-- 
Stephen Hemminger <shemminger@linux-foundation.org>


^ permalink raw reply

* [PATCH 2/3] net: wrap hard_header_parse
From: Stephen Hemminger @ 2007-08-24 20:43 UTC (permalink / raw)
  To: David Miller; +Cc: netdev
In-Reply-To: <20070824204310.388073598@linux-foundation.org>

[-- Attachment #1: dev_header_parse.patch --]
[-- Type: text/plain, Size: 8330 bytes --]

Wrap the hard_header_parse function to simplify next step
of header_ops conversion.

Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>

--- a/include/linux/netdevice.h	2007-08-23 21:25:57.000000000 -0700
+++ b/include/linux/netdevice.h	2007-08-23 22:25:35.000000000 -0700
@@ -639,7 +639,7 @@ struct net_device
 	void			(*vlan_rx_kill_vid)(struct net_device *dev,
 						    unsigned short vid);
 
-	int			(*hard_header_parse)(struct sk_buff *skb,
+	int			(*hard_header_parse)(const struct sk_buff *skb,
 						     unsigned char *haddr);
 	int			(*neigh_setup)(struct net_device *dev, struct neigh_parms *);
 #ifdef CONFIG_NETPOLL
@@ -787,6 +787,16 @@ static inline int dev_hard_header(struct
 	return dev->hard_header(skb, dev, type, daddr, saddr, len);
 }
 
+static inline int dev_parse_header(const struct sk_buff *skb,
+				   unsigned char *haddr)
+{
+	const struct net_device *dev = skb->dev;
+
+	if (!dev->hard_header_parse)
+		return 0;
+	return dev->hard_header_parse(skb, haddr);
+}
+
 typedef int gifconf_func_t(struct net_device * dev, char __user * bufptr, int len);
 extern int		register_gifconf(unsigned int family, gifconf_func_t * gifconf);
 static inline int unregister_gifconf(unsigned int family)
--- a/net/netfilter/nfnetlink_log.c	2007-08-23 09:44:22.000000000 -0700
+++ b/net/netfilter/nfnetlink_log.c	2007-08-23 21:43:32.000000000 -0700
@@ -480,12 +480,13 @@ __build_packet_message(struct nfulnl_ins
 		NFA_PUT(inst->skb, NFULA_MARK, sizeof(tmp_uint), &tmp_uint);
 	}
 
-	if (indev && skb->dev && skb->dev->hard_header_parse) {
+	if (indev && skb->dev) {
 		struct nfulnl_msg_packet_hw phw;
-		int len = skb->dev->hard_header_parse((struct sk_buff *)skb,
-						    phw.hw_addr);
-		phw.hw_addrlen = htons(len);
-		NFA_PUT(inst->skb, NFULA_HWADDR, sizeof(phw), &phw);
+		int len = dev_parse_header(skb, phw.hw_addr);
+		if (len > 0) {
+			phw.hw_addrlen = htons(len);
+			NFA_PUT(inst->skb, NFULA_HWADDR, sizeof(phw), &phw);
+		}
 	}
 
 	if (skb->tstamp.tv64) {
--- a/net/netfilter/nfnetlink_queue.c	2007-08-23 09:44:22.000000000 -0700
+++ b/net/netfilter/nfnetlink_queue.c	2007-08-23 21:33:50.000000000 -0700
@@ -485,14 +485,13 @@ nfqnl_build_packet_message(struct nfqnl_
 		NFA_PUT(skb, NFQA_MARK, sizeof(u_int32_t), &tmp_uint);
 	}
 
-	if (indev && entskb->dev
-	    && entskb->dev->hard_header_parse) {
+	if (indev && entskb->dev) {
 		struct nfqnl_msg_packet_hw phw;
-
-		int len = entskb->dev->hard_header_parse(entskb,
-							   phw.hw_addr);
-		phw.hw_addrlen = htons(len);
-		NFA_PUT(skb, NFQA_HWADDR, sizeof(phw), &phw);
+		int len = dev_parse_header(entskb, phw.hw_addr);
+		if (len) {
+			phw.hw_addrlen = htons(len);
+			NFA_PUT(skb, NFQA_HWADDR, sizeof(phw), &phw);
+		}
 	}
 
 	if (entskb->tstamp.tv64) {
--- a/net/packet/af_packet.c	2007-08-23 21:25:57.000000000 -0700
+++ b/net/packet/af_packet.c	2007-08-23 22:25:19.000000000 -0700
@@ -512,10 +512,8 @@ static int packet_rcv(struct sk_buff *sk
 		sll->sll_ifindex = orig_dev->ifindex;
 	else
 		sll->sll_ifindex = dev->ifindex;
-	sll->sll_halen = 0;
 
-	if (dev->hard_header_parse)
-		sll->sll_halen = dev->hard_header_parse(skb, sll->sll_addr);
+	sll->sll_halen = dev_parse_header(skb, sll->sll_addr);
 
 	PACKET_SKB_CB(skb)->origlen = skb->len;
 
@@ -649,9 +647,7 @@ static int tpacket_rcv(struct sk_buff *s
 	h->tp_usec = tv.tv_usec;
 
 	sll = (struct sockaddr_ll*)((u8*)h + TPACKET_ALIGN(sizeof(*h)));
-	sll->sll_halen = 0;
-	if (dev->hard_header_parse)
-		sll->sll_halen = dev->hard_header_parse(skb, sll->sll_addr);
+	sll->sll_halen = dev_parse_header(skb, sll->sll_addr);
 	sll->sll_family = AF_PACKET;
 	sll->sll_hatype = dev->type;
 	sll->sll_protocol = skb->protocol;
--- a/net/ethernet/eth.c	2007-08-23 21:25:57.000000000 -0700
+++ b/net/ethernet/eth.c	2007-08-23 22:25:19.000000000 -0700
@@ -207,9 +207,9 @@ EXPORT_SYMBOL(eth_type_trans);
  * @skb: packet to extract header from
  * @haddr: destination buffer
  */
-static int eth_header_parse(struct sk_buff *skb, unsigned char *haddr)
+static int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr)
 {
-	struct ethhdr *eth = eth_hdr(skb);
+	const struct ethhdr *eth = eth_hdr(skb);
 	memcpy(haddr, eth->h_source, ETH_ALEN);
 	return ETH_ALEN;
 }
--- a/net/mac80211/ieee80211.c	2007-08-23 21:25:57.000000000 -0700
+++ b/net/mac80211/ieee80211.c	2007-08-23 22:25:19.000000000 -0700
@@ -53,7 +53,7 @@ static struct net_device_stats *ieee8021
 	return &(sdata->stats);
 }
 
-static int header_parse_80211(struct sk_buff *skb, unsigned char *haddr)
+static int header_parse_80211(const struct sk_buff *skb, unsigned char *haddr)
 {
 	memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */
 	return ETH_ALEN;
--- a/drivers/ieee1394/eth1394.c	2007-08-23 21:25:57.000000000 -0700
+++ b/drivers/ieee1394/eth1394.c	2007-08-23 22:25:19.000000000 -0700
@@ -162,7 +162,8 @@ static int ether1394_header(struct sk_bu
 			    unsigned short type, void *daddr, void *saddr,
 			    unsigned len);
 static int ether1394_rebuild_header(struct sk_buff *skb);
-static int ether1394_header_parse(struct sk_buff *skb, unsigned char *haddr);
+static int ether1394_header_parse(const struct sk_buff *skb,
+				  unsigned char *haddr);
 static int ether1394_header_cache(struct neighbour *neigh, struct hh_cache *hh);
 static void ether1394_header_cache_update(struct hh_cache *hh,
 					  struct net_device *dev,
@@ -752,11 +753,10 @@ static int ether1394_rebuild_header(stru
 	return 0;
 }
 
-static int ether1394_header_parse(struct sk_buff *skb, unsigned char *haddr)
+static int ether1394_header_parse(const struct sk_buff *skb,
+				  unsigned char *haddr)
 {
-	struct net_device *dev = skb->dev;
-
-	memcpy(haddr, dev->dev_addr, ETH1394_ALEN);
+	memcpy(haddr, skb->dev->dev_addr, ETH1394_ALEN);
 	return ETH1394_ALEN;
 }
 
--- a/drivers/net/wireless/airo.c	2007-08-23 09:44:10.000000000 -0700
+++ b/drivers/net/wireless/airo.c	2007-08-23 21:59:46.000000000 -0700
@@ -2481,7 +2481,7 @@ void stop_airo_card( struct net_device *
 
 EXPORT_SYMBOL(stop_airo_card);
 
-static int wll_header_parse(struct sk_buff *skb, unsigned char *haddr)
+static int wll_header_parse(const struct sk_buff *skb, unsigned char *haddr)
 {
 	memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN);
 	return ETH_ALEN;
@@ -2698,11 +2698,6 @@ static int mpi_map_card(struct airo_info
 
 static void wifi_setup(struct net_device *dev)
 {
-	dev->hard_header        = NULL;
-	dev->rebuild_header     = NULL;
-	dev->hard_header_cache  = NULL;
-	dev->header_cache_update= NULL;
-
 	dev->hard_header_parse  = wll_header_parse;
 	dev->hard_start_xmit = &airo_start_xmit11;
 	dev->get_stats = &airo_get_stats;
--- a/drivers/s390/net/qeth_main.c	2007-08-23 09:44:10.000000000 -0700
+++ b/drivers/s390/net/qeth_main.c	2007-08-23 22:02:26.000000000 -0700
@@ -6488,10 +6488,10 @@ static struct ethtool_ops qeth_ethtool_o
 };
 
 static int
-qeth_hard_header_parse(struct sk_buff *skb, unsigned char *haddr)
+qeth_hard_header_parse(const struct sk_buff *skb, unsigned char *haddr)
 {
-	struct qeth_card *card;
-	struct ethhdr *eth;
+	const struct qeth_card *card;
+	const struct ethhdr *eth;
 
 	card = qeth_get_card_from_dev(skb->dev);
 	if (card->options.layer2)
--- a/net/ipv4/netfilter/ip_queue.c	2007-08-23 21:25:57.000000000 -0700
+++ b/net/ipv4/netfilter/ip_queue.c	2007-08-23 22:04:33.000000000 -0700
@@ -249,10 +249,8 @@ ipq_build_packet_message(struct ipq_queu
 
 	if (entry->info->indev && entry->skb->dev) {
 		pmsg->hw_type = entry->skb->dev->type;
-		if (entry->skb->dev->hard_header_parse)
-			pmsg->hw_addrlen =
-				entry->skb->dev->hard_header_parse(entry->skb,
-								   pmsg->hw_addr);
+		pmsg->hw_addrlen = dev_parse_header(entry->skb,
+						    pmsg->hw_addr);
 	}
 
 	if (data_len)
--- a/net/ipv6/netfilter/ip6_queue.c	2007-08-23 09:44:22.000000000 -0700
+++ b/net/ipv6/netfilter/ip6_queue.c	2007-08-23 22:06:24.000000000 -0700
@@ -247,10 +247,7 @@ ipq_build_packet_message(struct ipq_queu
 
 	if (entry->info->indev && entry->skb->dev) {
 		pmsg->hw_type = entry->skb->dev->type;
-		if (entry->skb->dev->hard_header_parse)
-			pmsg->hw_addrlen =
-				entry->skb->dev->hard_header_parse(entry->skb,
-								   pmsg->hw_addr);
+		pmsg->hw_addrlen = dev_parse_header(entry->skb, pmsg->hw_addr);
 	}
 
 	if (data_len)

-- 
Stephen Hemminger <shemminger@linux-foundation.org>


^ permalink raw reply

* [PATCH 1/3] net: wrap netdevice hardware header creation
From: Stephen Hemminger @ 2007-08-24 20:43 UTC (permalink / raw)
  To: David Miller; +Cc: netdev
In-Reply-To: <20070824204310.388073598@linux-foundation.org>

[-- Attachment #1: dev_hard_header.patch --]
[-- Type: text/plain, Size: 13027 bytes --]

Add inline for common usage of hardware header creation, and
fix bug in IPV6 mcast where the assumption about negative return value
was wrong.

Negative return from hard_header means not enough space was available,
(ie -N bytes).

Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>


--- a/include/linux/netdevice.h	2007-08-23 09:44:19.000000000 -0700
+++ b/include/linux/netdevice.h	2007-08-24 12:47:11.000000000 -0700
@@ -778,6 +778,15 @@ extern int		dev_restart(struct net_devic
 extern int		netpoll_trap(void);
 #endif
 
+static inline int dev_hard_header(struct sk_buff *skb, struct net_device *dev,
+				  unsigned short type,
+				  void *daddr, void *saddr, unsigned len)
+{
+	if (!dev->hard_header)
+		return 0;
+	return dev->hard_header(skb, dev, type, daddr, saddr, len);
+}
+
 typedef int gifconf_func_t(struct net_device * dev, char __user * bufptr, int len);
 extern int		register_gifconf(unsigned int family, gifconf_func_t * gifconf);
 static inline int unregister_gifconf(unsigned int family)
--- a/net/ipv4/arp.c	2007-08-23 09:44:22.000000000 -0700
+++ b/net/ipv4/arp.c	2007-08-24 12:47:11.000000000 -0700
@@ -590,8 +590,7 @@ struct sk_buff *arp_create(int type, int
 	/*
 	 *	Fill the device header for the ARP frame
 	 */
-	if (dev->hard_header &&
-	    dev->hard_header(skb,dev,ptype,dest_hw,src_hw,skb->len) < 0)
+	if (dev_hard_header(skb, dev, ptype, dest_hw, src_hw, skb->len) < 0)
 		goto out;
 
 	/*
--- a/net/core/neighbour.c	2007-08-23 09:44:22.000000000 -0700
+++ b/net/core/neighbour.c	2007-08-24 12:47:11.000000000 -0700
@@ -1123,9 +1123,8 @@ int neigh_compat_output(struct sk_buff *
 
 	__skb_pull(skb, skb_network_offset(skb));
 
-	if (dev->hard_header &&
-	    dev->hard_header(skb, dev, ntohs(skb->protocol), NULL, NULL,
-			     skb->len) < 0 &&
+	if (dev_hard_header(skb, dev, ntohs(skb->protocol), NULL, NULL,
+			    skb->len) < 0 &&
 	    dev->rebuild_header(skb))
 		return 0;
 
@@ -1152,13 +1151,13 @@ int neigh_resolve_output(struct sk_buff 
 			write_lock_bh(&neigh->lock);
 			if (!dst->hh)
 				neigh_hh_init(neigh, dst, dst->ops->protocol);
-			err = dev->hard_header(skb, dev, ntohs(skb->protocol),
-					       neigh->ha, NULL, skb->len);
+			err = dev_hard_header(skb, dev, ntohs(skb->protocol),
+					      neigh->ha, NULL, skb->len);
 			write_unlock_bh(&neigh->lock);
 		} else {
 			read_lock_bh(&neigh->lock);
-			err = dev->hard_header(skb, dev, ntohs(skb->protocol),
-					       neigh->ha, NULL, skb->len);
+			err = dev_hard_header(skb, dev, ntohs(skb->protocol),
+					      neigh->ha, NULL, skb->len);
 			read_unlock_bh(&neigh->lock);
 		}
 		if (err >= 0)
@@ -1189,8 +1188,8 @@ int neigh_connected_output(struct sk_buf
 	__skb_pull(skb, skb_network_offset(skb));
 
 	read_lock_bh(&neigh->lock);
-	err = dev->hard_header(skb, dev, ntohs(skb->protocol),
-			       neigh->ha, NULL, skb->len);
+	err = dev_hard_header(skb, dev, ntohs(skb->protocol),
+			      neigh->ha, NULL, skb->len);
 	read_unlock_bh(&neigh->lock);
 	if (err >= 0)
 		err = neigh->ops->queue_xmit(skb);
--- a/net/8021q/vlan_dev.c	2007-08-23 09:44:21.000000000 -0700
+++ b/net/8021q/vlan_dev.c	2007-08-24 12:47:11.000000000 -0700
@@ -419,21 +419,19 @@ int vlan_dev_hard_header(struct sk_buff 
 
 	if (build_vlan_header) {
 		/* Now make the underlying real hard header */
-		rc = dev->hard_header(skb, dev, ETH_P_8021Q, daddr, saddr, len + VLAN_HLEN);
-
-		if (rc > 0) {
+		rc = dev_hard_header(skb, dev, ETH_P_8021Q, daddr, saddr,
+				     len + VLAN_HLEN);
+		if (rc > 0)
 			rc += VLAN_HLEN;
-		} else if (rc < 0) {
+		else if (rc < 0)
 			rc -= VLAN_HLEN;
-		}
-	} else {
+	} else
 		/* If here, then we'll just make a normal looking ethernet frame,
 		 * but, the hard_start_xmit method will insert the tag (it has to
 		 * be able to do this for bridged and other skbs that don't come
 		 * down the protocol stack in an orderly manner.
 		 */
-		rc = dev->hard_header(skb, dev, type, daddr, saddr, len);
-	}
+		rc = dev_hard_header(skb, dev, type, daddr, saddr, len);
 
 	return rc;
 }
--- a/net/core/netpoll.c	2007-08-23 09:44:22.000000000 -0700
+++ b/net/core/netpoll.c	2007-08-23 09:53:03.000000000 -0700
@@ -415,11 +415,9 @@ static void arp_reply(struct sk_buff *sk
 	send_skb->protocol = htons(ETH_P_ARP);
 
 	/* Fill the device header for the ARP frame */
-
-	if (np->dev->hard_header &&
-	    np->dev->hard_header(send_skb, skb->dev, ptype,
-				 sha, np->local_mac,
-				 send_skb->len) < 0) {
+	if (dev_hard_header(send_skb, skb->dev, ptype,
+			    sha, np->local_mac,
+			    send_skb->len) < 0) {
 		kfree_skb(send_skb);
 		return;
 	}
--- a/net/packet/af_packet.c	2007-08-23 09:44:22.000000000 -0700
+++ b/net/packet/af_packet.c	2007-08-24 12:47:11.000000000 -0700
@@ -756,16 +756,10 @@ static int packet_sendmsg(struct kiocb *
 	skb_reserve(skb, LL_RESERVED_SPACE(dev));
 	skb_reset_network_header(skb);
 
-	if (dev->hard_header) {
-		int res;
-		err = -EINVAL;
-		res = dev->hard_header(skb, dev, ntohs(proto), addr, NULL, len);
-		if (sock->type != SOCK_DGRAM) {
-			skb_reset_tail_pointer(skb);
-			skb->len = 0;
-		} else if (res < 0)
-			goto out_free;
-	}
+	err = -EINVAL;
+	if (sock->type == SOCK_DGRAM &&
+	    dev_hard_header(skb, dev, ntohs(proto), addr, NULL, len) < 0)
+		goto out_free;
 
 	/* Returns -EFAULT on error */
 	err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len);
--- a/net/802/p8023.c	2007-08-23 09:44:21.000000000 -0700
+++ b/net/802/p8023.c	2007-08-23 09:53:03.000000000 -0700
@@ -31,7 +31,7 @@ static int p8023_request(struct datalink
 {
 	struct net_device *dev = skb->dev;
 
-	dev->hard_header(skb, dev, ETH_P_802_3, dest_node, NULL, skb->len);
+	dev_hard_header(skb, dev, ETH_P_802_3, dest_node, NULL, skb->len);
 	return dev_queue_xmit(skb);
 }
 
--- a/net/decnet/dn_neigh.c	2007-08-23 09:44:22.000000000 -0700
+++ b/net/decnet/dn_neigh.c	2007-08-23 09:53:03.000000000 -0700
@@ -210,7 +210,8 @@ static int dn_neigh_output_packet(struct
 	char mac_addr[ETH_ALEN];
 
 	dn_dn2eth(mac_addr, rt->rt_local_src);
-	if (!dev->hard_header || dev->hard_header(skb, dev, ntohs(skb->protocol), neigh->ha, mac_addr, skb->len) >= 0)
+	if (dev_hard_header(skb, dev, ntohs(skb->protocol), neigh->ha,
+			    mac_addr, skb->len) >= 0)
 		return neigh->ops->queue_xmit(skb);
 
 	if (net_ratelimit())
--- a/net/econet/af_econet.c	2007-08-23 09:44:22.000000000 -0700
+++ b/net/econet/af_econet.c	2007-08-23 09:53:03.000000000 -0700
@@ -336,6 +336,7 @@ static int econet_sendmsg(struct kiocb *
 		/* Real hardware Econet.  We're not worthy etc. */
 #ifdef CONFIG_ECONET_NATIVE
 		unsigned short proto = 0;
+		int res;
 
 		dev_hold(dev);
 
@@ -354,12 +355,12 @@ static int econet_sendmsg(struct kiocb *
 		eb->sec = *saddr;
 		eb->sent = ec_tx_done;
 
-		if (dev->hard_header) {
-			int res;
+		err = -EINVAL;
+		res = dev_hard_header(skb, dev, ntohs(proto), &addr, NULL, len);
+		if (res < 0)
+			goto out_free;
+		if (res > 0) {
 			struct ec_framehdr *fh;
-			err = -EINVAL;
-			res = dev->hard_header(skb, dev, ntohs(proto),
-					       &addr, NULL, len);
 			/* Poke in our control byte and
 			   port number.  Hack, hack.  */
 			fh = (struct ec_framehdr *)(skb->data);
@@ -368,8 +369,7 @@ static int econet_sendmsg(struct kiocb *
 			if (sock->type != SOCK_DGRAM) {
 				skb_reset_tail_pointer(skb);
 				skb->len = 0;
-			} else if (res < 0)
-				goto out_free;
+			}
 		}
 
 		/* Copy the data. Returns -EFAULT on error */
--- a/net/ethernet/pe2.c	2007-08-23 09:44:22.000000000 -0700
+++ b/net/ethernet/pe2.c	2007-08-23 09:53:03.000000000 -0700
@@ -12,9 +12,7 @@ static int pEII_request(struct datalink_
 	struct net_device *dev = skb->dev;
 
 	skb->protocol = htons(ETH_P_IPX);
-	if (dev->hard_header)
-		dev->hard_header(skb, dev, ETH_P_IPX,
-				 dest_node, NULL, skb->len);
+	dev_hard_header(skb, dev, ETH_P_IPX, dest_node, NULL, skb->len);
 	return dev_queue_xmit(skb);
 }
 
--- a/net/ipv4/ipconfig.c	2007-08-23 09:44:22.000000000 -0700
+++ b/net/ipv4/ipconfig.c	2007-08-23 09:53:03.000000000 -0700
@@ -749,8 +749,8 @@ static void __init ic_bootp_send_if(stru
 	/* Chain packet down the line... */
 	skb->dev = dev;
 	skb->protocol = htons(ETH_P_IP);
-	if ((dev->hard_header &&
-	     dev->hard_header(skb, dev, ntohs(skb->protocol), dev->broadcast, dev->dev_addr, skb->len) < 0) ||
+	if (dev_hard_header(skb, dev, ntohs(skb->protocol),
+			    dev->broadcast, dev->dev_addr, skb->len) < 0) ||
 	    dev_queue_xmit(skb) < 0)
 		printk("E");
 }
--- a/net/ipv6/mcast.c	2007-08-23 09:44:22.000000000 -0700
+++ b/net/ipv6/mcast.c	2007-08-23 09:53:03.000000000 -0700
@@ -1437,17 +1437,12 @@ static struct sk_buff *mld_newpack(struc
 static inline int mld_dev_queue_xmit2(struct sk_buff *skb)
 {
 	struct net_device *dev = skb->dev;
+	unsigned char ha[MAX_ADDR_LEN];
 
-	if (dev->hard_header) {
-		unsigned char ha[MAX_ADDR_LEN];
-		int err;
-
-		ndisc_mc_map(&ipv6_hdr(skb)->daddr, ha, dev, 1);
-		err = dev->hard_header(skb, dev, ETH_P_IPV6, ha, NULL, skb->len);
-		if (err < 0) {
-			kfree_skb(skb);
-			return err;
-		}
+	ndisc_mc_map(&ipv6_hdr(skb)->daddr, ha, dev, 1);
+	if (dev_hard_header(skb, dev, ETH_P_IPV6, ha, NULL, skb->len) < 0) {
+		kfree_skb(skb);
+		return -EINVAL;
 	}
 	return dev_queue_xmit(skb);
 }
--- a/net/sched/sch_teql.c	2007-08-23 09:44:22.000000000 -0700
+++ b/net/sched/sch_teql.c	2007-08-24 12:47:11.000000000 -0700
@@ -232,9 +232,12 @@ __teql_resolve(struct sk_buff *skb, stru
 	}
 	if (neigh_event_send(n, skb_res) == 0) {
 		int err;
+
 		read_lock(&n->lock);
-		err = dev->hard_header(skb, dev, ntohs(skb->protocol), n->ha, NULL, skb->len);
+		err = dev_hard_header(skb, dev, ntohs(skb->protocol),
+				      n->ha, NULL, skb->len);
 		read_unlock(&n->lock);
+
 		if (err < 0) {
 			neigh_release(n);
 			return -EINVAL;
--- a/net/tipc/eth_media.c	2007-08-23 09:44:22.000000000 -0700
+++ b/net/tipc/eth_media.c	2007-08-23 09:53:03.000000000 -0700
@@ -76,7 +76,7 @@ static int send_msg(struct sk_buff *buf,
 		skb_reset_network_header(clone);
 		dev = ((struct eth_bearer *)(tb_ptr->usr_handle))->dev;
 		clone->dev = dev;
-		dev->hard_header(clone, dev, ETH_P_TIPC,
+		dev_hard_header(clone, dev, ETH_P_TIPC,
 				 &dest->dev_addr.eth_addr,
 				 dev->dev_addr, clone->len);
 		dev_queue_xmit(clone);
--- a/drivers/net/hamradio/bpqether.c	2007-08-23 09:44:08.000000000 -0700
+++ b/drivers/net/hamradio/bpqether.c	2007-08-24 12:47:11.000000000 -0700
@@ -283,7 +283,7 @@ static int bpq_xmit(struct sk_buff *skb,
 
 	skb->protocol = ax25_type_trans(skb, dev);
 	skb_reset_network_header(skb);
-	dev->hard_header(skb, dev, ETH_P_BPQ, bpq->dest_addr, NULL, 0);
+	dev_hard_header(skb, dev, ETH_P_BPQ, bpq->dest_addr, NULL, 0);
 	bpq->stats.tx_packets++;
 	bpq->stats.tx_bytes+=skb->len;
   
--- a/drivers/net/macvlan.c	2007-08-23 09:44:08.000000000 -0700
+++ b/drivers/net/macvlan.c	2007-08-24 12:47:11.000000000 -0700
@@ -170,8 +170,8 @@ static int macvlan_hard_header(struct sk
 	const struct macvlan_dev *vlan = netdev_priv(dev);
 	struct net_device *lowerdev = vlan->lowerdev;
 
-	return lowerdev->hard_header(skb, lowerdev, type, daddr,
-				     saddr ? : dev->dev_addr, len);
+	return dev_hard_header(skb, lowerdev, type, daddr,
+			       saddr ? : dev->dev_addr, len);
 }
 
 static int macvlan_open(struct net_device *dev)
--- a/drivers/net/pppoe.c	2007-08-23 09:44:09.000000000 -0700
+++ b/drivers/net/pppoe.c	2007-08-23 09:53:03.000000000 -0700
@@ -824,8 +824,8 @@ static int pppoe_sendmsg(struct kiocb *i
 	}
 
 	error = total_len;
-	dev->hard_header(skb, dev, ETH_P_PPP_SES,
-			 po->pppoe_pa.remote, NULL, total_len);
+	dev_hard_header(skb, dev, ETH_P_PPP_SES,
+			po->pppoe_pa.remote, NULL, total_len);
 
 	memcpy(ph, &hdr, sizeof(struct pppoe_hdr));
 
@@ -896,8 +896,8 @@ static int __pppoe_xmit(struct sock *sk,
 
 	skb2->dev = dev;
 
-	dev->hard_header(skb2, dev, ETH_P_PPP_SES,
-			 po->pppoe_pa.remote, NULL, data_len);
+	dev_hard_header(skb2, dev, ETH_P_PPP_SES,
+			po->pppoe_pa.remote, NULL, data_len);
 
 	/* We're transmitting skb2, and assuming that dev_queue_xmit
 	 * will free it.  The generic ppp layer however, is expecting
--- a/include/net/dn_route.h	2007-08-23 09:44:21.000000000 -0700
+++ b/include/net/dn_route.h	2007-08-23 09:53:03.000000000 -0700
@@ -100,8 +100,7 @@ static inline void dn_rt_finish_output(s
 	if ((dev->type != ARPHRD_ETHER) && (dev->type != ARPHRD_LOOPBACK))
 		dst = NULL;
 
-	if (!dev->hard_header || (dev->hard_header(skb, dev, ETH_P_DNA_RT,
-			dst, src, skb->len) >= 0))
+	if (dev_hard_header(skb, dev, ETH_P_DNA_RT, dst, src, skb->len) >= 0)
 		dn_rt_send(skb);
 	else
 		kfree_skb(skb);
--- a/drivers/net/wan/lapbether.c	2007-08-24 12:47:11.000000000 -0700
+++ b/drivers/net/wan/lapbether.c	2007-08-24 12:47:23.000000000 -0700
@@ -213,7 +213,7 @@ static void lapbeth_data_transmit(struct
 
 	skb->dev = dev = lapbeth->ethdev;
 
-	dev->hard_header(skb, dev, ETH_P_DEC, bcast_addr, NULL, 0);
+	dev_hard_header(skb, dev, ETH_P_DEC, bcast_addr, NULL, 0);
 
 	dev_queue_xmit(skb);
 }

-- 
Stephen Hemminger <shemminger@linux-foundation.org>


^ permalink raw reply

* [PATCH 3/3] net: move hardware header operations out of netdevice
From: Stephen Hemminger @ 2007-08-24 20:43 UTC (permalink / raw)
  To: David Miller; +Cc: netdev
In-Reply-To: <20070824204310.388073598@linux-foundation.org>

[-- Attachment #1: hh_cache.patch --]
[-- Type: TEXT/PLAIN, Size: 87588 bytes --]

Since hardware header operations are part of the protocol class
not the device instance, make them into a separate object and
save memory.

Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>


--- a/drivers/net/loopback.c	2007-08-24 13:41:02.000000000 -0700
+++ b/drivers/net/loopback.c	2007-08-24 13:41:16.000000000 -0700
@@ -208,14 +208,11 @@ struct net_device loopback_dev = {
 	.get_stats		= &get_stats,
 	.mtu			= (16 * 1024) + 20 + 20 + 12,
 	.hard_start_xmit	= loopback_xmit,
-	.hard_header		= eth_header,
-	.hard_header_cache	= eth_header_cache,
-	.header_cache_update	= eth_header_cache_update,
-	.hard_header_len	= ETH_HLEN,	/* 14	*/
+
 	.addr_len		= ETH_ALEN,	/* 6	*/
 	.tx_queue_len		= 0,
 	.type			= ARPHRD_LOOPBACK,	/* 0x0001*/
-	.rebuild_header		= eth_rebuild_header,
+
 	.flags			= IFF_LOOPBACK,
 	.features 		= NETIF_F_SG | NETIF_F_FRAGLIST
 #ifdef LOOPBACK_TSO
@@ -223,7 +220,9 @@ struct net_device loopback_dev = {
 #endif
 				  | NETIF_F_NO_CSUM | NETIF_F_HIGHDMA
 				  | NETIF_F_LLTX,
+
 	.ethtool_ops		= &loopback_ethtool_ops,
+	.header_ops		= &eth_header_ops,
 };
 
 /* Setup and register the loopback device. */
--- a/include/linux/etherdevice.h	2007-08-24 13:41:02.000000000 -0700
+++ b/include/linux/etherdevice.h	2007-08-24 13:41:16.000000000 -0700
@@ -29,15 +29,19 @@
 #include <linux/random.h>
 
 #ifdef __KERNEL__
-extern int		eth_header(struct sk_buff *skb, struct net_device *dev,
-				   unsigned short type, void *daddr,
-				   void *saddr, unsigned len);
-extern int		eth_rebuild_header(struct sk_buff *skb);
 extern __be16		eth_type_trans(struct sk_buff *skb, struct net_device *dev);
-extern void		eth_header_cache_update(struct hh_cache *hh, struct net_device *dev,
-						unsigned char * haddr);
-extern int		eth_header_cache(struct neighbour *neigh,
-					 struct hh_cache *hh);
+extern const struct header_ops eth_header_ops;
+
+extern int eth_header(struct sk_buff *skb, struct net_device *dev,
+		      unsigned short type,
+		      const void *daddr, const void *saddr, unsigned len);
+extern int eth_rebuild_header(struct sk_buff *skb);
+extern int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr);
+extern int eth_header_cache(const struct neighbour *neigh, struct hh_cache *hh);
+extern void eth_header_cache_update(struct hh_cache *hh,
+				    const struct net_device *dev,
+				    const unsigned char *haddr);
+
 
 extern struct net_device *alloc_etherdev_mq(int sizeof_priv, unsigned int queue_count);
 #define alloc_etherdev(sizeof_priv) alloc_etherdev_mq(sizeof_priv, 1)
--- a/include/linux/netdevice.h	2007-08-24 13:41:15.000000000 -0700
+++ b/include/linux/netdevice.h	2007-08-24 13:41:16.000000000 -0700
@@ -248,6 +248,19 @@ struct hh_cache
 #define LL_RESERVED_SPACE_EXTRA(dev,extra) \
 	((((dev)->hard_header_len+extra)&~(HH_DATA_MOD - 1)) + HH_DATA_MOD)
 
+struct header_ops {
+	int	(*create) (struct sk_buff *skb, struct net_device *dev,
+			   unsigned short type, const void *daddr,
+			   const void *saddr, unsigned len);
+	int	(*parse)(const struct sk_buff *skb, unsigned char *haddr);
+	int	(*rebuild)(struct sk_buff *skb);
+#define HAVE_HEADER_CACHE
+	int	(*cache)(const struct neighbour *neigh, struct hh_cache *hh);
+	void	(*cache_update)(struct hh_cache *hh,
+				const struct net_device *dev,
+				const unsigned char *haddr);
+};
+
 /* These flag bits are private to the generic network queueing
  * layer, they may not be explicitly referenced by any other
  * code.
@@ -474,6 +487,9 @@ struct net_device
 #endif
 	const struct ethtool_ops *ethtool_ops;
 
+	/* Hardware header description */
+	const struct header_ops *header_ops;
+
 	/*
 	 * This marks the end of the "visible" part of the structure. All
 	 * fields hereafter are internal to the system, and may change at
@@ -597,13 +613,6 @@ struct net_device
 	int			(*open)(struct net_device *dev);
 	int			(*stop)(struct net_device *dev);
 #define HAVE_NETDEV_POLL
-	int			(*hard_header) (struct sk_buff *skb,
-						struct net_device *dev,
-						unsigned short type,
-						void *daddr,
-						void *saddr,
-						unsigned len);
-	int			(*rebuild_header)(struct sk_buff *skb);
 #define HAVE_CHANGE_RX_FLAGS
 	void			(*change_rx_flags)(struct net_device *dev,
 						   int flags);
@@ -620,12 +629,6 @@ struct net_device
 #define HAVE_SET_CONFIG
 	int			(*set_config)(struct net_device *dev,
 					      struct ifmap *map);
-#define HAVE_HEADER_CACHE
-	int			(*hard_header_cache)(struct neighbour *neigh,
-						     struct hh_cache *hh);
-	void			(*header_cache_update)(struct hh_cache *hh,
-						       struct net_device *dev,
-						       unsigned char *  haddr);
 #define HAVE_CHANGE_MTU
 	int			(*change_mtu)(struct net_device *dev, int new_mtu);
 
@@ -639,8 +642,6 @@ struct net_device
 	void			(*vlan_rx_kill_vid)(struct net_device *dev,
 						    unsigned short vid);
 
-	int			(*hard_header_parse)(const struct sk_buff *skb,
-						     unsigned char *haddr);
 	int			(*neigh_setup)(struct net_device *dev, struct neigh_parms *);
 #ifdef CONFIG_NETPOLL
 	struct netpoll_info	*npinfo;
@@ -780,11 +781,13 @@ extern int		netpoll_trap(void);
 
 static inline int dev_hard_header(struct sk_buff *skb, struct net_device *dev,
 				  unsigned short type,
-				  void *daddr, void *saddr, unsigned len)
+				  const void *daddr, const void *saddr,
+				  unsigned len)
 {
-	if (!dev->hard_header)
+	if (!dev->header_ops)
 		return 0;
-	return dev->hard_header(skb, dev, type, daddr, saddr, len);
+
+	return dev->header_ops->create(skb, dev, type, daddr, saddr, len);
 }
 
 static inline int dev_parse_header(const struct sk_buff *skb,
@@ -792,9 +795,9 @@ static inline int dev_parse_header(const
 {
 	const struct net_device *dev = skb->dev;
 
-	if (!dev->hard_header_parse)
+	if (!dev->header_ops->parse)
 		return 0;
-	return dev->hard_header_parse(skb, haddr);
+	return dev->header_ops->parse(skb, haddr);
 }
 
 typedef int gifconf_func_t(struct net_device * dev, char __user * bufptr, int len);
--- a/include/net/pkt_sched.h	2007-08-24 13:41:02.000000000 -0700
+++ b/include/net/pkt_sched.h	2007-08-24 13:41:17.000000000 -0700
@@ -97,10 +97,9 @@ extern int tc_classify(struct sk_buff *s
 /* Calculate maximal size of packet seen by hard_start_xmit
    routine of this device.
  */
-static inline unsigned psched_mtu(struct net_device *dev)
+static inline unsigned psched_mtu(const struct net_device *dev)
 {
-	unsigned mtu = dev->mtu;
-	return dev->hard_header ? mtu + dev->hard_header_len : mtu;
+	return dev->mtu + dev->hard_header_len;
 }
 
 #endif
--- a/net/core/dev.c	2007-08-24 13:41:02.000000000 -0700
+++ b/net/core/dev.c	2007-08-24 13:41:17.000000000 -0700
@@ -919,14 +919,6 @@ void dev_load(const char *name)
 		request_module("%s", name);
 }
 
-static int default_rebuild_header(struct sk_buff *skb)
-{
-	printk(KERN_DEBUG "%s: default_rebuild_header called -- BUG!\n",
-	       skb->dev ? skb->dev->name : "NULL!!!");
-	kfree_skb(skb);
-	return 1;
-}
-
 /**
  *	dev_open	- prepare an interface for use.
  *	@dev:	device to open
@@ -3460,14 +3452,6 @@ int register_netdevice(struct net_device
 		}
 	}
 
-	/*
-	 *	nil rebuild_header routine,
-	 *	that should be never called and used as just bug trap.
-	 */
-
-	if (!dev->rebuild_header)
-		dev->rebuild_header = default_rebuild_header;
-
 	ret = netdev_register_sysfs(dev);
 	if (ret)
 		goto err_uninit;
--- a/net/core/neighbour.c	2007-08-24 13:41:14.000000000 -0700
+++ b/net/core/neighbour.c	2007-08-24 13:41:17.000000000 -0700
@@ -895,8 +895,8 @@ out_unlock_bh:
 static void neigh_update_hhs(struct neighbour *neigh)
 {
 	struct hh_cache *hh;
-	void (*update)(struct hh_cache*, struct net_device*, unsigned char *) =
-		neigh->dev->header_cache_update;
+	void (*update)(struct hh_cache*, const struct net_device*, const unsigned char *)
+		= neigh->dev->header_ops->cache_update;
 
 	if (update) {
 		for (hh = neigh->hh; hh; hh = hh->hh_next) {
@@ -1093,7 +1093,8 @@ static void neigh_hh_init(struct neighbo
 		hh->hh_type = protocol;
 		atomic_set(&hh->hh_refcnt, 0);
 		hh->hh_next = NULL;
-		if (dev->hard_header_cache(n, hh)) {
+
+		if (dev->header_ops->cache(n, hh)) {
 			kfree(hh);
 			hh = NULL;
 		} else {
@@ -1125,7 +1126,7 @@ int neigh_compat_output(struct sk_buff *
 
 	if (dev_hard_header(skb, dev, ntohs(skb->protocol), NULL, NULL,
 			    skb->len) < 0 &&
-	    dev->rebuild_header(skb))
+	    dev->header_ops->rebuild(skb))
 		return 0;
 
 	return dev_queue_xmit(skb);
@@ -1147,7 +1148,7 @@ int neigh_resolve_output(struct sk_buff 
 	if (!neigh_event_send(neigh, skb)) {
 		int err;
 		struct net_device *dev = neigh->dev;
-		if (dev->hard_header_cache && !dst->hh) {
+		if (dev->header_ops->cache && !dst->hh) {
 			write_lock_bh(&neigh->lock);
 			if (!dst->hh)
 				neigh_hh_init(neigh, dst, dst->ops->protocol);
--- a/net/ethernet/eth.c	2007-08-24 13:41:15.000000000 -0700
+++ b/net/ethernet/eth.c	2007-08-24 13:41:53.000000000 -0700
@@ -75,8 +75,9 @@ __setup("ether=", netdev_boot_setup);
  * Set the protocol type. For a packet of type ETH_P_802_3 we put the length
  * in here instead. It is up to the 802.2 layer to carry protocol information.
  */
-int eth_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
-	       void *daddr, void *saddr, unsigned len)
+int eth_header(struct sk_buff *skb, struct net_device *dev,
+	       unsigned short type,
+	       const void *daddr, const void *saddr, unsigned len)
 {
 	struct ethhdr *eth = (struct ethhdr *)skb_push(skb, ETH_HLEN);
 
@@ -109,6 +110,7 @@ int eth_header(struct sk_buff *skb, stru
 
 	return -ETH_HLEN;
 }
+EXPORT_SYMBOL(eth_header);
 
 /**
  * eth_rebuild_header- rebuild the Ethernet MAC header.
@@ -141,6 +143,7 @@ int eth_rebuild_header(struct sk_buff *s
 
 	return 0;
 }
+EXPORT_SYMBOL(eth_rebuild_header);
 
 /**
  * eth_type_trans - determine the packet's protocol ID.
@@ -207,12 +210,13 @@ EXPORT_SYMBOL(eth_type_trans);
  * @skb: packet to extract header from
  * @haddr: destination buffer
  */
-static int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr)
+int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr)
 {
 	const struct ethhdr *eth = eth_hdr(skb);
 	memcpy(haddr, eth->h_source, ETH_ALEN);
 	return ETH_ALEN;
 }
+EXPORT_SYMBOL(eth_header_parse);
 
 /**
  * eth_header_cache - fill cache entry from neighbour
@@ -220,11 +224,11 @@ static int eth_header_parse(const struct
  * @hh: destination cache entry
  * Create an Ethernet header template from the neighbour.
  */
-int eth_header_cache(struct neighbour *neigh, struct hh_cache *hh)
+int eth_header_cache(const struct neighbour *neigh, struct hh_cache *hh)
 {
 	__be16 type = hh->hh_type;
 	struct ethhdr *eth;
-	struct net_device *dev = neigh->dev;
+	const struct net_device *dev = neigh->dev;
 
 	eth = (struct ethhdr *)
 	    (((u8 *) hh->hh_data) + (HH_DATA_OFF(sizeof(*eth))));
@@ -238,6 +242,7 @@ int eth_header_cache(struct neighbour *n
 	hh->hh_len = ETH_HLEN;
 	return 0;
 }
+EXPORT_SYMBOL(eth_header_cache);
 
 /**
  * eth_header_cache_update - update cache entry
@@ -247,12 +252,14 @@ int eth_header_cache(struct neighbour *n
  *
  * Called by Address Resolution module to notify changes in address.
  */
-void eth_header_cache_update(struct hh_cache *hh, struct net_device *dev,
-			     unsigned char *haddr)
+void eth_header_cache_update(struct hh_cache *hh,
+			     const struct net_device *dev,
+			     const unsigned char *haddr)
 {
 	memcpy(((u8 *) hh->hh_data) + HH_DATA_OFF(sizeof(struct ethhdr)),
 	       haddr, dev->addr_len);
 }
+EXPORT_SYMBOL(eth_header_cache_update);
 
 /**
  * eth_mac_addr - set new Ethernet hardware address
@@ -291,6 +298,14 @@ static int eth_change_mtu(struct net_dev
 	return 0;
 }
 
+const struct header_ops eth_header_ops ____cacheline_aligned = {
+	.create		= eth_header,
+	.parse		= eth_header_parse,
+	.rebuild	= eth_rebuild_header,
+	.cache		= eth_header_cache,
+	.cache_update	= eth_header_cache_update,
+};
+
 /**
  * ether_setup - setup Ethernet network device
  * @dev: network device
@@ -298,13 +313,10 @@ static int eth_change_mtu(struct net_dev
  */
 void ether_setup(struct net_device *dev)
 {
+	dev->header_ops		= &eth_header_ops;
+
 	dev->change_mtu		= eth_change_mtu;
-	dev->hard_header	= eth_header;
-	dev->rebuild_header 	= eth_rebuild_header;
 	dev->set_mac_address 	= eth_mac_addr;
-	dev->hard_header_cache	= eth_header_cache;
-	dev->header_cache_update= eth_header_cache_update;
-	dev->hard_header_parse	= eth_header_parse;
 
 	dev->type		= ARPHRD_ETHER;
 	dev->hard_header_len 	= ETH_HLEN;
--- a/net/ipv4/arp.c	2007-08-24 13:41:14.000000000 -0700
+++ b/net/ipv4/arp.c	2007-08-24 13:41:17.000000000 -0700
@@ -252,7 +252,7 @@ static int arp_constructor(struct neighb
 	neigh->parms = neigh_parms_clone(parms);
 	rcu_read_unlock();
 
-	if (dev->hard_header == NULL) {
+	if (!dev->header_ops) {
 		neigh->nud_state = NUD_NOARP;
 		neigh->ops = &arp_direct_ops;
 		neigh->output = neigh->ops->queue_xmit;
@@ -309,10 +309,12 @@ static int arp_constructor(struct neighb
 			neigh->nud_state = NUD_NOARP;
 			memcpy(neigh->ha, dev->broadcast, dev->addr_len);
 		}
-		if (dev->hard_header_cache)
+
+		if (dev->header_ops->cache)
 			neigh->ops = &arp_hh_ops;
 		else
 			neigh->ops = &arp_generic_ops;
+
 		if (neigh->nud_state&NUD_VALID)
 			neigh->output = neigh->ops->connected_output;
 		else
--- a/include/linux/if_ether.h	2007-08-24 13:41:02.000000000 -0700
+++ b/include/linux/if_ether.h	2007-08-24 13:41:17.000000000 -0700
@@ -117,6 +117,8 @@ static inline struct ethhdr *eth_hdr(con
 	return (struct ethhdr *)skb_mac_header(skb);
 }
 
+int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr);
+
 #ifdef CONFIG_SYSCTL
 extern struct ctl_table ether_table[];
 #endif
--- a/net/802/fc.c	2007-08-24 13:41:02.000000000 -0700
+++ b/net/802/fc.c	2007-08-24 13:41:17.000000000 -0700
@@ -35,7 +35,7 @@
 
 static int fc_header(struct sk_buff *skb, struct net_device *dev,
 		     unsigned short type,
-		     void *daddr, void *saddr, unsigned len)
+		     const void *daddr, const void *saddr, unsigned len)
 {
 	struct fch_hdr *fch;
 	int hdr_len;
@@ -95,11 +95,14 @@ static int fc_rebuild_header(struct sk_b
 #endif
 }
 
+static const struct header_ops fc_header_ops = {
+	.create	 = fc_header,
+	.rebuild = fc_rebuild_header,
+};
+
 static void fc_setup(struct net_device *dev)
 {
-	dev->hard_header	= fc_header;
-	dev->rebuild_header	= fc_rebuild_header;
-
+	dev->header_ops		= &fc_header_ops;
 	dev->type		= ARPHRD_IEEE802;
 	dev->hard_header_len	= FC_HLEN;
 	dev->mtu		= 2024;
--- a/net/802/fddi.c	2007-08-24 13:41:02.000000000 -0700
+++ b/net/802/fddi.c	2007-08-24 13:41:17.000000000 -0700
@@ -52,7 +52,7 @@
 
 static int fddi_header(struct sk_buff *skb, struct net_device *dev,
 		       unsigned short type,
-		       void *daddr, void *saddr, unsigned len)
+		       const void *daddr, const void *saddr, unsigned len)
 {
 	int hl = FDDI_K_SNAP_HLEN;
 	struct fddihdr *fddi;
@@ -175,11 +175,15 @@ static int fddi_change_mtu(struct net_de
 	return(0);
 }
 
+static const struct header_ops fddi_header_ops = {
+	.create		= fddi_header,
+	.rebuild	= fddi_rebuild_header,
+};
+
 static void fddi_setup(struct net_device *dev)
 {
 	dev->change_mtu		= fddi_change_mtu;
-	dev->hard_header	= fddi_header;
-	dev->rebuild_header	= fddi_rebuild_header;
+	dev->header_ops		= &fddi_header_ops;
 
 	dev->type		= ARPHRD_FDDI;
 	dev->hard_header_len	= FDDI_K_SNAP_HLEN+3;	/* Assume 802.2 SNAP hdr len + 3 pad bytes */
--- a/net/802/hippi.c	2007-08-24 13:41:02.000000000 -0700
+++ b/net/802/hippi.c	2007-08-24 13:41:17.000000000 -0700
@@ -45,8 +45,8 @@
  */
 
 static int hippi_header(struct sk_buff *skb, struct net_device *dev,
-			unsigned short type, void *daddr, void *saddr,
-			unsigned len)
+			unsigned short type,
+			const void *daddr, const void *saddr, unsigned len)
 {
 	struct hippi_hdr *hip = (struct hippi_hdr *)skb_push(skb, HIPPI_HLEN);
 	struct hippi_cb *hcb = (struct hippi_cb *) skb->cb;
@@ -182,16 +182,18 @@ static int hippi_neigh_setup_dev(struct 
 	return 0;
 }
 
+static const struct header_ops hippi_header_ops = {
+	.create		= hippi_header,
+	.rebuild	= hippi_rebuild_header,
+};
+
+
 static void hippi_setup(struct net_device *dev)
 {
 	dev->set_multicast_list		= NULL;
 	dev->change_mtu			= hippi_change_mtu;
-	dev->hard_header		= hippi_header;
-	dev->rebuild_header 		= hippi_rebuild_header;
+	dev->header_ops			= &hippi_header_ops;
 	dev->set_mac_address 		= hippi_mac_addr;
-	dev->hard_header_parse		= NULL;
-	dev->hard_header_cache		= NULL;
-	dev->header_cache_update	= NULL;
 	dev->neigh_setup 		= hippi_neigh_setup_dev;
 
 	/*
--- a/net/802/tr.c	2007-08-24 13:41:02.000000000 -0700
+++ b/net/802/tr.c	2007-08-24 13:41:17.000000000 -0700
@@ -99,7 +99,7 @@ static inline unsigned long rif_hash(con
 
 static int tr_header(struct sk_buff *skb, struct net_device *dev,
 		     unsigned short type,
-		     void *daddr, void *saddr, unsigned len)
+		     const void *daddr, const void *saddr, unsigned len)
 {
 	struct trh_hdr *trh;
 	int hdr_len;
@@ -141,7 +141,7 @@ static int tr_header(struct sk_buff *skb
 	if(daddr)
 	{
 		memcpy(trh->daddr,daddr,dev->addr_len);
-		tr_source_route(skb,trh,dev);
+		tr_source_route(skb, trh, dev);
 		return(hdr_len);
 	}
 
@@ -246,7 +246,8 @@ __be16 tr_type_trans(struct sk_buff *skb
  *	We try to do source routing...
  */
 
-void tr_source_route(struct sk_buff *skb,struct trh_hdr *trh,struct net_device *dev)
+void tr_source_route(struct sk_buff *skb,struct trh_hdr *trh,
+		     struct net_device *dev)
 {
 	int slack;
 	unsigned int hash;
@@ -589,14 +590,18 @@ static const struct file_operations rif_
 
 #endif
 
+static const struct header_ops tr_header_ops = {
+	.create = tr_header,
+	.rebuild= tr_rebuild_header,
+};
+
 static void tr_setup(struct net_device *dev)
 {
 	/*
 	 *	Configure and register
 	 */
 
-	dev->hard_header	= tr_header;
-	dev->rebuild_header	= tr_rebuild_header;
+	dev->header_ops	= &tr_header_ops;
 
 	dev->type		= ARPHRD_IEEE802_TR;
 	dev->hard_header_len	= TR_HLEN;
--- a/net/8021q/vlan.c	2007-08-24 13:41:02.000000000 -0700
+++ b/net/8021q/vlan.c	2007-08-24 13:41:17.000000000 -0700
@@ -313,6 +313,12 @@ int unregister_vlan_device(struct net_de
  */
 static struct lock_class_key vlan_netdev_xmit_lock_key;
 
+static const struct header_ops vlan_header_ops = {
+	.create	 = vlan_dev_hard_header,
+	.rebuild = vlan_dev_rebuild_header,
+	.parse	 = eth_header_parse,
+};
+
 static int vlan_dev_init(struct net_device *dev)
 {
 	struct net_device *real_dev = VLAN_DEV_INFO(dev)->real_dev;
@@ -330,18 +336,14 @@ static int vlan_dev_init(struct net_devi
 		memcpy(dev->broadcast, real_dev->broadcast, dev->addr_len);
 
 	if (real_dev->features & NETIF_F_HW_VLAN_TX) {
-		dev->hard_header     = real_dev->hard_header;
+		dev->header_ops      = real_dev->header_ops;
 		dev->hard_header_len = real_dev->hard_header_len;
 		dev->hard_start_xmit = vlan_dev_hwaccel_hard_start_xmit;
-		dev->rebuild_header  = real_dev->rebuild_header;
 	} else {
-		dev->hard_header     = vlan_dev_hard_header;
+		dev->header_ops      = &vlan_header_ops;
 		dev->hard_header_len = real_dev->hard_header_len + VLAN_HLEN;
 		dev->hard_start_xmit = vlan_dev_hard_start_xmit;
-		dev->rebuild_header  = vlan_dev_rebuild_header;
 	}
-	dev->hard_header_parse = real_dev->hard_header_parse;
-	dev->hard_header_cache = NULL;
 
 	lockdep_set_class(&dev->_xmit_lock, &vlan_netdev_xmit_lock_key);
 	return 0;
--- a/drivers/net/arcnet/arcnet.c	2007-08-24 13:41:02.000000000 -0700
+++ b/drivers/net/arcnet/arcnet.c	2007-08-24 13:41:17.000000000 -0700
@@ -102,8 +102,8 @@ static int arcnet_close(struct net_devic
 static int arcnet_send_packet(struct sk_buff *skb, struct net_device *dev);
 static void arcnet_timeout(struct net_device *dev);
 static int arcnet_header(struct sk_buff *skb, struct net_device *dev,
-			 unsigned short type, void *daddr, void *saddr,
-			 unsigned len);
+			 unsigned short type, const void *daddr,
+			 const void *saddr, unsigned len);
 static int arcnet_rebuild_header(struct sk_buff *skb);
 static struct net_device_stats *arcnet_get_stats(struct net_device *dev);
 static int go_tx(struct net_device *dev);
@@ -317,11 +317,17 @@ static int choose_mtu(void)
 	return mtu == 65535 ? XMTU : mtu;
 }
 
+static const struct header_ops arcnet_header_ops = {
+	.create = arcnet_header,
+	.rebuild = arcnet_rebuild_header,
+};
+
 
 /* Setup a struct device for ARCnet. */
 static void arcdev_setup(struct net_device *dev)
 {
 	dev->type = ARPHRD_ARCNET;
+	dev->header_ops = &arcnet_header_ops;
 	dev->hard_header_len = sizeof(struct archdr);
 	dev->mtu = choose_mtu();
 
@@ -342,8 +348,6 @@ static void arcdev_setup(struct net_devi
 	dev->hard_start_xmit = arcnet_send_packet;
 	dev->tx_timeout = arcnet_timeout;
 	dev->get_stats = arcnet_get_stats;
-	dev->hard_header = arcnet_header;
-	dev->rebuild_header = arcnet_rebuild_header;
 }
 
 struct net_device *alloc_arcdev(char *name)
@@ -488,10 +492,10 @@ static int arcnet_close(struct net_devic
 
 
 static int arcnet_header(struct sk_buff *skb, struct net_device *dev,
-			 unsigned short type, void *daddr, void *saddr,
-			 unsigned len)
+			 unsigned short type, const void *daddr,
+			 const void *saddr, unsigned len)
 {
-	struct arcnet_local *lp = dev->priv;
+	const struct arcnet_local *lp = netdev_priv(dev);
 	uint8_t _daddr, proto_num;
 	struct ArcProto *proto;
 
--- a/drivers/net/hamradio/6pack.c	2007-08-24 13:41:02.000000000 -0700
+++ b/drivers/net/hamradio/6pack.c	2007-08-24 13:41:17.000000000 -0700
@@ -3,7 +3,7 @@
  *		devices like TTY. It interfaces between a raw TTY and the
  *		kernel's AX.25 protocol layers.
  *
- * Authors:	Andreas Könsgen <ajk@iehk.rwth-aachen.de>
+ * Authors:	Andreas Könsgen <ajk@iehk.rwth-aachen.de>
  *              Ralf Baechle DL5RB <ralf@linux-mips.org>
  *
  * Quite a lot of stuff "stolen" by Joerg Reuter from slip.c, written by
@@ -288,7 +288,8 @@ static int sp_close(struct net_device *d
 
 /* Return the frame type ID */
 static int sp_header(struct sk_buff *skb, struct net_device *dev,
-	unsigned short type, void *daddr, void *saddr, unsigned len)
+		     unsigned short type, const void *daddr,
+		     const void *saddr, unsigned len)
 {
 #ifdef CONFIG_INET
 	if (type != htons(ETH_P_AX25))
@@ -323,6 +324,11 @@ static int sp_rebuild_header(struct sk_b
 #endif
 }
 
+static const struct header_ops sp_header_ops = {
+	.create		= sp_header,
+	.rebuild	= sp_rebuild_header,
+};
+
 static void sp_setup(struct net_device *dev)
 {
 	/* Finish setting up the DEVICE info. */
@@ -331,14 +337,15 @@ static void sp_setup(struct net_device *
 	dev->open		= sp_open_dev;
 	dev->destructor		= free_netdev;
 	dev->stop		= sp_close;
-	dev->hard_header	= sp_header;
+
 	dev->get_stats	        = sp_get_stats;
 	dev->set_mac_address    = sp_set_mac_address;
 	dev->hard_header_len	= AX25_MAX_HEADER_LEN;
+	dev->header_ops 	= &sp_header_ops;
+
 	dev->addr_len		= AX25_ADDR_LEN;
 	dev->type		= ARPHRD_AX25;
 	dev->tx_queue_len	= 10;
-	dev->rebuild_header	= sp_rebuild_header;
 	dev->tx_timeout		= NULL;
 
 	/* Only activated in AX.25 mode */
--- a/drivers/net/hamradio/bpqether.c	2007-08-24 13:41:14.000000000 -0700
+++ b/drivers/net/hamradio/bpqether.c	2007-08-24 13:41:17.000000000 -0700
@@ -488,8 +488,7 @@ static void bpq_setup(struct net_device 
 	dev->flags      = 0;
 
 #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
-	dev->hard_header     = ax25_hard_header;
-	dev->rebuild_header  = ax25_rebuild_header;
+	dev->header_ops      = &ax25_header_ops;
 #endif
 
 	dev->type            = ARPHRD_AX25;
--- a/drivers/net/hamradio/dmascc.c	2007-08-24 13:41:02.000000000 -0700
+++ b/drivers/net/hamradio/dmascc.c	2007-08-24 13:41:17.000000000 -0700
@@ -581,8 +581,7 @@ static int __init setup_adapter(int card
 		dev->do_ioctl = scc_ioctl;
 		dev->hard_start_xmit = scc_send_packet;
 		dev->get_stats = scc_get_stats;
-		dev->hard_header = ax25_hard_header;
-		dev->rebuild_header = ax25_rebuild_header;
+		dev->header_ops = &ax25_hard_header_ops
 		dev->set_mac_address = scc_set_mac_address;
 	}
 	if (register_netdev(info->dev[0])) {
--- a/drivers/net/hamradio/hdlcdrv.c	2007-08-24 13:41:02.000000000 -0700
+++ b/drivers/net/hamradio/hdlcdrv.c	2007-08-24 13:41:17.000000000 -0700
@@ -682,8 +682,7 @@ static void hdlcdrv_setup(struct net_dev
 
 	s->skb = NULL;
 	
-	dev->hard_header = ax25_hard_header;
-	dev->rebuild_header = ax25_rebuild_header;
+	dev->header_ops = &ax25_header_ops;
 	dev->set_mac_address = hdlcdrv_set_mac_address;
 	
 	dev->type = ARPHRD_AX25;           /* AF_AX25 device */
--- a/drivers/net/hamradio/mkiss.c	2007-08-24 13:41:02.000000000 -0700
+++ b/drivers/net/hamradio/mkiss.c	2007-08-24 13:41:17.000000000 -0700
@@ -578,8 +578,9 @@ static int ax_open_dev(struct net_device
 #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
 
 /* Return the frame type ID */
-static int ax_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
-	  void *daddr, void *saddr, unsigned len)
+static int ax_header(struct sk_buff *skb, struct net_device *dev,
+		     unsigned short type, const void *daddr,
+		     const void *saddr, unsigned len)
 {
 #ifdef CONFIG_INET
 	if (type != htons(ETH_P_AX25))
@@ -670,6 +671,11 @@ static struct net_device_stats *ax_get_s
 	return &ax->stats;
 }
 
+static const struct header_ops ax_header_ops = {
+	.create    = ax_header,
+	.rebuild   = ax_rebuild_header,
+};
+
 static void ax_setup(struct net_device *dev)
 {
 	/* Finish setting up the DEVICE info. */
@@ -683,8 +689,8 @@ static void ax_setup(struct net_device *
 	dev->addr_len        = 0;
 	dev->type            = ARPHRD_AX25;
 	dev->tx_queue_len    = 10;
-	dev->hard_header     = ax_header;
-	dev->rebuild_header  = ax_rebuild_header;
+	dev->header_ops      = &ax_header_ops;
+
 
 	memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
 	memcpy(dev->dev_addr,  &ax25_defaddr,  AX25_ADDR_LEN);
--- a/drivers/net/hamradio/scc.c	2007-08-24 13:41:02.000000000 -0700
+++ b/drivers/net/hamradio/scc.c	2007-08-24 13:41:17.000000000 -0700
@@ -1550,8 +1550,8 @@ static void scc_net_setup(struct net_dev
 	dev->stop	     = scc_net_close;
 
 	dev->hard_start_xmit = scc_net_tx;
-	dev->hard_header     = ax25_hard_header;
-	dev->rebuild_header  = ax25_rebuild_header;
+	dev->header_ops      = &ax25_hard_header_ops;
+
 	dev->set_mac_address = scc_net_set_mac_address;
 	dev->get_stats       = scc_net_get_stats;
 	dev->do_ioctl        = scc_net_ioctl;
--- a/drivers/net/hamradio/yam.c	2007-08-24 13:41:02.000000000 -0700
+++ b/drivers/net/hamradio/yam.c	2007-08-24 13:41:17.000000000 -0700
@@ -1096,8 +1096,7 @@ static void yam_setup(struct net_device 
 
 	skb_queue_head_init(&yp->send_queue);
 
-	dev->hard_header = ax25_hard_header;
-	dev->rebuild_header = ax25_rebuild_header;
+	dev->header_ops = &ax25_header_ops;
 
 	dev->set_mac_address = yam_set_mac_address;
 
--- a/drivers/net/skfp/skfddi.c	2007-08-24 13:41:02.000000000 -0700
+++ b/drivers/net/skfp/skfddi.c	2007-08-24 13:41:17.000000000 -0700
@@ -260,7 +260,6 @@ static int skfp_init_one(struct pci_dev 
 	dev->set_multicast_list = &skfp_ctl_set_multicast_list;
 	dev->set_mac_address = &skfp_ctl_set_mac_address;
 	dev->do_ioctl = &skfp_ioctl;
-	dev->header_cache_update = NULL;	/* not supported */
 
 	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
--- a/net/appletalk/dev.c	2007-08-24 13:41:02.000000000 -0700
+++ b/net/appletalk/dev.c	2007-08-24 13:41:17.000000000 -0700
@@ -24,11 +24,7 @@ static void ltalk_setup(struct net_devic
 	/* Fill in the fields of the device structure with localtalk-generic values. */
 
 	dev->change_mtu		= ltalk_change_mtu;
-	dev->hard_header	= NULL;
-	dev->rebuild_header 	= NULL;
 	dev->set_mac_address 	= ltalk_mac_addr;
-	dev->hard_header_cache	= NULL;
-	dev->header_cache_update= NULL;
 
 	dev->type		= ARPHRD_LOCALTLK;
 	dev->hard_header_len 	= LTALK_HLEN;
--- a/drivers/ieee1394/eth1394.c	2007-08-24 13:41:15.000000000 -0700
+++ b/drivers/ieee1394/eth1394.c	2007-08-24 13:41:17.000000000 -0700
@@ -159,15 +159,16 @@ MODULE_PARM_DESC(max_partial_datagrams,
 
 
 static int ether1394_header(struct sk_buff *skb, struct net_device *dev,
-			    unsigned short type, void *daddr, void *saddr,
-			    unsigned len);
+			    unsigned short type, const void *daddr,
+			    const void *saddr, unsigned len);
 static int ether1394_rebuild_header(struct sk_buff *skb);
 static int ether1394_header_parse(const struct sk_buff *skb,
 				  unsigned char *haddr);
-static int ether1394_header_cache(struct neighbour *neigh, struct hh_cache *hh);
+static int ether1394_header_cache(const struct neighbour *neigh,
+				  struct hh_cache *hh);
 static void ether1394_header_cache_update(struct hh_cache *hh,
-					  struct net_device *dev,
-					  unsigned char *haddr);
+					  const struct net_device *dev,
+					  const unsigned char *haddr);
 static int ether1394_tx(struct sk_buff *skb, struct net_device *dev);
 static void ether1394_iso(struct hpsb_iso *iso);
 
@@ -507,6 +508,14 @@ static void ether1394_reset_priv(struct 
 	spin_unlock_irqrestore(&priv->lock, flags);
 }
 
+static const struct header_ops ether1394_header_ops = {
+	.create		= ether1394_header,
+	.rebuild	= ether1394_rebuild_header,
+	.cache  	= ether1394_header_cache,
+	.cache_update	= ether1394_header_cache_update,
+	.parse		= ether1394_header_parse,
+};
+
 static void ether1394_init_dev(struct net_device *dev)
 {
 	dev->open		= ether1394_open;
@@ -516,11 +525,7 @@ static void ether1394_init_dev(struct ne
 	dev->tx_timeout		= ether1394_tx_timeout;
 	dev->change_mtu		= ether1394_change_mtu;
 
-	dev->hard_header	= ether1394_header;
-	dev->rebuild_header	= ether1394_rebuild_header;
-	dev->hard_header_cache	= ether1394_header_cache;
-	dev->header_cache_update= ether1394_header_cache_update;
-	dev->hard_header_parse	= ether1394_header_parse;
+	dev->header_ops		= &ether1394_header_ops;
 
 	SET_ETHTOOL_OPS(dev, &ethtool_ops);
 
@@ -712,8 +717,8 @@ static void ether1394_host_reset(struct 
  * saddr=NULL means use device source address
  * daddr=NULL means leave destination address (eg unresolved arp). */
 static int ether1394_header(struct sk_buff *skb, struct net_device *dev,
-			    unsigned short type, void *daddr, void *saddr,
-			    unsigned len)
+			    unsigned short type, const void *daddr,
+			    const void *saddr, unsigned len)
 {
 	struct eth1394hdr *eth =
 			(struct eth1394hdr *)skb_push(skb, ETH1394_HLEN);
@@ -760,7 +765,8 @@ static int ether1394_header_parse(const 
 	return ETH1394_ALEN;
 }
 
-static int ether1394_header_cache(struct neighbour *neigh, struct hh_cache *hh)
+static int ether1394_header_cache(const struct neighbour *neigh,
+				  struct hh_cache *hh)
 {
 	unsigned short type = hh->hh_type;
 	struct net_device *dev = neigh->dev;
@@ -779,8 +785,8 @@ static int ether1394_header_cache(struct
 
 /* Called by Address Resolution module to notify changes in address. */
 static void ether1394_header_cache_update(struct hh_cache *hh,
-					  struct net_device *dev,
-					  unsigned char * haddr)
+					  const struct net_device *dev,
+					  const unsigned char * haddr)
 {
 	memcpy((u8 *)hh->hh_data + 16 - ETH1394_HLEN, haddr, dev->addr_len);
 }
@@ -900,8 +906,8 @@ static u16 ether1394_parse_encap(struct 
 	}
 
 	/* Now add the ethernet header. */
-	if (dev->hard_header(skb, dev, ntohs(ether_type), &dest_hw, NULL,
-			     skb->len) >= 0)
+	if (dev_hard_header(skb, dev, ntohs(ether_type), &dest_hw, NULL,
+			    skb->len) >= 0)
 		ret = ether1394_type_trans(skb, dev);
 
 	return ret;
--- a/net/8021q/vlan.h	2007-08-24 13:41:02.000000000 -0700
+++ b/net/8021q/vlan.h	2007-08-24 13:41:17.000000000 -0700
@@ -53,8 +53,8 @@ int vlan_dev_rebuild_header(struct sk_bu
 int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,
 		  struct packet_type *ptype, struct net_device *orig_dev);
 int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev,
-			 unsigned short type, void *daddr, void *saddr,
-			 unsigned len);
+			 unsigned short type, const void *daddr,
+			 const void *saddr, unsigned len);
 int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev);
 int vlan_dev_hwaccel_hard_start_xmit(struct sk_buff *skb, struct net_device *dev);
 int vlan_dev_change_mtu(struct net_device *dev, int new_mtu);
--- a/net/8021q/vlan_dev.c	2007-08-24 13:41:14.000000000 -0700
+++ b/net/8021q/vlan_dev.c	2007-08-24 13:41:17.000000000 -0700
@@ -328,8 +328,8 @@ static inline unsigned short vlan_dev_ge
  *  physical devices.
  */
 int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev,
-			 unsigned short type, void *daddr, void *saddr,
-			 unsigned len)
+			 unsigned short type,
+			 const void *daddr, const void *saddr, unsigned len)
 {
 	struct vlan_hdr *vhdr;
 	unsigned short veth_TCI = 0;
--- a/drivers/net/macvlan.c	2007-08-24 13:41:14.000000000 -0700
+++ b/drivers/net/macvlan.c	2007-08-24 13:41:17.000000000 -0700
@@ -164,8 +164,8 @@ static int macvlan_hard_start_xmit(struc
 }
 
 static int macvlan_hard_header(struct sk_buff *skb, struct net_device *dev,
-			       unsigned short type, void *daddr, void *saddr,
-			       unsigned len)
+			       unsigned short type, const void *daddr,
+			       const void *saddr, unsigned len)
 {
 	const struct macvlan_dev *vlan = netdev_priv(dev);
 	struct net_device *lowerdev = vlan->lowerdev;
@@ -174,6 +174,15 @@ static int macvlan_hard_header(struct sk
 			       saddr ? : dev->dev_addr, len);
 }
 
+static const struct header_ops macvlan_hard_header_ops = {
+	.create  	= macvlan_hard_header,
+	.rebuild	= eth_rebuild_header,
+	.parse		= eth_header_parse,
+	.rebuild	= eth_rebuild_header,
+	.cache		= eth_header_cache,
+	.cache_update	= eth_header_cache_update,
+};
+
 static int macvlan_open(struct net_device *dev)
 {
 	struct macvlan_dev *vlan = netdev_priv(dev);
@@ -299,9 +308,9 @@ static void macvlan_setup(struct net_dev
 	dev->change_mtu		= macvlan_change_mtu;
 	dev->change_rx_flags	= macvlan_change_rx_flags;
 	dev->set_multicast_list	= macvlan_set_multicast_list;
-	dev->hard_header	= macvlan_hard_header;
 	dev->hard_start_xmit	= macvlan_hard_start_xmit;
 	dev->destructor		= free_netdev;
+	dev->header_ops		= &macvlan_hard_header_ops,
 	dev->ethtool_ops	= &macvlan_ethtool_ops;
 	dev->tx_queue_len	= 0;
 }
--- a/include/net/ax25.h	2007-08-24 13:41:02.000000000 -0700
+++ b/include/net/ax25.h	2007-08-24 13:41:17.000000000 -0700
@@ -363,8 +363,11 @@ extern int  ax25_rx_iframe(ax25_cb *, st
 extern int  ax25_kiss_rcv(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *);
 
 /* ax25_ip.c */
-extern int  ax25_hard_header(struct sk_buff *, struct net_device *, unsigned short, void *, void *, unsigned int);
+extern int ax25_hard_header(struct sk_buff *, struct net_device *,
+			    unsigned short, const void *,
+			    const void *, unsigned int);
 extern int  ax25_rebuild_header(struct sk_buff *);
+extern const struct header_ops ax25_header_ops;
 
 /* ax25_out.c */
 extern ax25_cb *ax25_send_frame(struct sk_buff *, int, ax25_address *, ax25_address *, ax25_digi *, struct net_device *);
--- a/net/ax25/ax25_ip.c	2007-08-24 13:41:02.000000000 -0700
+++ b/net/ax25/ax25_ip.c	2007-08-24 13:41:17.000000000 -0700
@@ -46,7 +46,9 @@
 
 #ifdef CONFIG_INET
 
-int ax25_hard_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len)
+int ax25_hard_header(struct sk_buff *skb, struct net_device *dev,
+		     unsigned short type, const void *daddr,
+		     const void *saddr, unsigned len)
 {
 	unsigned char *buff;
 
@@ -215,7 +217,9 @@ put:
 
 #else	/* INET */
 
-int ax25_hard_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len)
+int ax25_hard_header(struct sk_buff *skb, struct net_device *dev,
+		     unsigned short type, const void *daddr,
+		     const void *saddr, unsigned len)
 {
 	return -AX25_HEADER_LEN;
 }
@@ -227,5 +231,12 @@ int ax25_rebuild_header(struct sk_buff *
 
 #endif
 
+const struct header_ops ax25_header_ops = {
+	.create = ax25_hard_header,
+	.rebuild = ax25_rebuild_header,
+};
+
 EXPORT_SYMBOL(ax25_hard_header);
 EXPORT_SYMBOL(ax25_rebuild_header);
+EXPORT_SYMBOL(ax25_header_ops);
+
--- a/drivers/net/shaper.c	2007-08-24 13:41:02.000000000 -0700
+++ b/drivers/net/shaper.c	2007-08-24 13:41:17.000000000 -0700
@@ -336,15 +336,16 @@ static struct net_device_stats *shaper_g
 }
 
 static int shaper_header(struct sk_buff *skb, struct net_device *dev,
-	unsigned short type, void *daddr, void *saddr, unsigned len)
+			 unsigned short type,
+			 const void *daddr, const void *saddr, unsigned len)
 {
 	struct shaper *sh=dev->priv;
 	int v;
 	if(sh_debug)
 		printk("Shaper header\n");
-	skb->dev=sh->dev;
-	v=sh->hard_header(skb,sh->dev,type,daddr,saddr,len);
-	skb->dev=dev;
+	skb->dev = sh->dev;
+	v = dev_hard_header(skb, sh->dev, type, daddr, saddr, len);
+	skb->dev = dev;
 	return v;
 }
 
@@ -356,7 +357,7 @@ static int shaper_rebuild_header(struct 
 	if(sh_debug)
 		printk("Shaper rebuild header\n");
 	skb->dev=sh->dev;
-	v=sh->rebuild_header(skb);
+	v = sh->dev->header_ops->rebuild(skb);
 	skb->dev=dev;
 	return v;
 }
@@ -420,51 +421,17 @@ static int shaper_neigh_setup_dev(struct
 
 #endif
 
+static const struct header_ops shaper_ops = {
+	.create	 = shaper_header,
+	.rebuild = shaper_rebuild_header,
+};
+
 static int shaper_attach(struct net_device *shdev, struct shaper *sh, struct net_device *dev)
 {
 	sh->dev = dev;
-	sh->hard_start_xmit=dev->hard_start_xmit;
 	sh->get_stats=dev->get_stats;
-	if(dev->hard_header)
-	{
-		sh->hard_header=dev->hard_header;
-		shdev->hard_header = shaper_header;
-	}
-	else
-		shdev->hard_header = NULL;
-
-	if(dev->rebuild_header)
-	{
-		sh->rebuild_header	= dev->rebuild_header;
-		shdev->rebuild_header	= shaper_rebuild_header;
-	}
-	else
-		shdev->rebuild_header	= NULL;
-
-#if 0
-	if(dev->hard_header_cache)
-	{
-		sh->hard_header_cache	= dev->hard_header_cache;
-		shdev->hard_header_cache= shaper_cache;
-	}
-	else
-	{
-		shdev->hard_header_cache= NULL;
-	}
 
-	if(dev->header_cache_update)
-	{
-		sh->header_cache_update	= dev->header_cache_update;
-		shdev->header_cache_update = shaper_cache_update;
-	}
-	else
-		shdev->header_cache_update= NULL;
-#else
-	shdev->header_cache_update = NULL;
-	shdev->hard_header_cache = NULL;
-#endif
 	shdev->neigh_setup = shaper_neigh_setup_dev;
-
 	shdev->hard_header_len=dev->hard_header_len;
 	shdev->type=dev->type;
 	shdev->addr_len=dev->addr_len;
@@ -550,12 +517,6 @@ static void __init shaper_setup(struct n
 	 *	Handlers for when we attach to a device.
 	 */
 
-	dev->hard_header 	= shaper_header;
-	dev->rebuild_header 	= shaper_rebuild_header;
-#if 0
-	dev->hard_header_cache	= shaper_cache;
-	dev->header_cache_update= shaper_cache_update;
-#endif
 	dev->neigh_setup	= shaper_neigh_setup_dev;
 	dev->do_ioctl		= shaper_ioctl;
 	dev->hard_header_len	= 0;
--- a/include/linux/if_shaper.h	2007-08-24 13:41:02.000000000 -0700
+++ b/include/linux/if_shaper.h	2007-08-24 13:41:17.000000000 -0700
@@ -26,17 +26,6 @@ struct shaper
 	spinlock_t lock;
         struct net_device_stats stats;
 	struct net_device *dev;
-	int  (*hard_start_xmit) (struct sk_buff *skb,
-		struct net_device *dev);
-	int  (*hard_header) (struct sk_buff *skb,
-		struct net_device *dev,
-		unsigned short type,
-		void *daddr,
-		void *saddr,
-		unsigned len);
-	int  (*rebuild_header)(struct sk_buff *skb);
-	int (*hard_header_cache)(struct neighbour *neigh, struct hh_cache *hh);
-	void (*header_cache_update)(struct hh_cache *hh, struct net_device *dev, unsigned char *  haddr);
 	struct net_device_stats* (*get_stats)(struct net_device *dev);
 	struct timer_list timer;
 };
--- a/net/ipv4/ip_gre.c	2007-08-24 13:41:02.000000000 -0700
+++ b/net/ipv4/ip_gre.c	2007-08-24 13:41:17.000000000 -0700
@@ -684,7 +684,7 @@ static int ipgre_tunnel_xmit(struct sk_b
 		goto tx_error;
 	}
 
-	if (dev->hard_header) {
+	if (dev->header_ops) {
 		gre_hlen = 0;
 		tiph = (struct iphdr*)skb->data;
 	} else {
@@ -1063,8 +1063,9 @@ static int ipgre_tunnel_change_mtu(struc
 
  */
 
-static int ipgre_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
-			void *daddr, void *saddr, unsigned len)
+static int ipgre_header(struct sk_buff *skb, struct net_device *dev,
+			unsigned short type,
+			const void *daddr, const void *saddr, unsigned len)
 {
 	struct ip_tunnel *t = netdev_priv(dev);
 	struct iphdr *iph = (struct iphdr *)skb_push(skb, t->hlen);
@@ -1130,9 +1131,14 @@ static int ipgre_close(struct net_device
 
 #endif
 
+static const struct header_ops ipgre_header_ops = {
+	.create	= ipgre_header,
+};
+
 static void ipgre_tunnel_setup(struct net_device *dev)
 {
 	SET_MODULE_OWNER(dev);
+
 	dev->uninit		= ipgre_tunnel_uninit;
 	dev->destructor 	= free_netdev;
 	dev->hard_start_xmit	= ipgre_tunnel_xmit;
@@ -1188,7 +1194,7 @@ static int ipgre_tunnel_init(struct net_
 			if (!iph->saddr)
 				return -EINVAL;
 			dev->flags = IFF_BROADCAST;
-			dev->hard_header = ipgre_header;
+			dev->header_ops = &ipgre_header_ops;
 			dev->open = ipgre_open;
 			dev->stop = ipgre_close;
 		}
--- a/net/ipv4/ip_output.c	2007-08-24 13:41:02.000000000 -0700
+++ b/net/ipv4/ip_output.c	2007-08-24 13:41:17.000000000 -0700
@@ -169,7 +169,7 @@ static inline int ip_finish_output2(stru
 		IP_INC_STATS(IPSTATS_MIB_OUTBCASTPKTS);
 
 	/* Be paranoid, rather than too clever. */
-	if (unlikely(skb_headroom(skb) < hh_len && dev->hard_header)) {
+	if (unlikely(skb_headroom(skb) < hh_len && dev->header_ops)) {
 		struct sk_buff *skb2;
 
 		skb2 = skb_realloc_headroom(skb, LL_RESERVED_SPACE(dev));
--- a/net/ipv6/ndisc.c	2007-08-24 13:41:02.000000000 -0700
+++ b/net/ipv6/ndisc.c	2007-08-24 13:41:17.000000000 -0700
@@ -354,7 +354,7 @@ static int ndisc_constructor(struct neig
 	rcu_read_unlock();
 
 	neigh->type = is_multicast ? RTN_MULTICAST : RTN_UNICAST;
-	if (dev->hard_header == NULL) {
+	if (!dev->header_ops) {
 		neigh->nud_state = NUD_NOARP;
 		neigh->ops = &ndisc_direct_ops;
 		neigh->output = neigh->ops->queue_xmit;
@@ -371,7 +371,7 @@ static int ndisc_constructor(struct neig
 			neigh->nud_state = NUD_NOARP;
 			memcpy(neigh->ha, dev->broadcast, dev->addr_len);
 		}
-		if (dev->hard_header_cache)
+		if (dev->header_ops->cache)
 			neigh->ops = &ndisc_hh_ops;
 		else
 			neigh->ops = &ndisc_generic_ops;
@@ -808,7 +808,7 @@ static void ndisc_recv_ns(struct sk_buff
 		neigh_update(neigh, lladdr, NUD_STALE,
 			     NEIGH_UPDATE_F_WEAK_OVERRIDE|
 			     NEIGH_UPDATE_F_OVERRIDE);
-	if (neigh || !dev->hard_header) {
+	if (neigh || !dev->header_ops) {
 		ndisc_send_na(dev, neigh, saddr, &msg->target,
 			      is_router,
 			      1, (ifp != NULL && inc), inc);
--- a/net/mac80211/ieee80211.c	2007-08-24 13:41:15.000000000 -0700
+++ b/net/mac80211/ieee80211.c	2007-08-24 13:41:17.000000000 -0700
@@ -295,16 +295,24 @@ static int ieee80211_change_mtu_apdev(st
 	return 0;
 }
 
+static const struct header_ops ieee80211_header_ops = {
+	.create		= eth_header,
+	.parse		= header_parse_80211,
+	.rebuild	= eth_rebuild_header,
+	.cache		= eth_header_cache,
+	.cache_update	= eth_header_cache_update,
+};
+
 void ieee80211_if_mgmt_setup(struct net_device *dev)
 {
 	ether_setup(dev);
+	dev->header_ops = &ieee80211_header_ops;
 	dev->hard_start_xmit = ieee80211_mgmt_start_xmit;
 	dev->change_mtu = ieee80211_change_mtu_apdev;
 	dev->get_stats = ieee80211_get_stats;
 	dev->open = ieee80211_mgmt_open;
 	dev->stop = ieee80211_mgmt_stop;
 	dev->type = ARPHRD_IEEE80211_PRISM;
-	dev->hard_header_parse = header_parse_80211;
 	dev->uninit = ieee80211_if_reinit;
 	dev->destructor = ieee80211_if_free;
 }
@@ -1290,7 +1298,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(
 	mdev->open = ieee80211_master_open;
 	mdev->stop = ieee80211_master_stop;
 	mdev->type = ARPHRD_IEEE80211;
-	mdev->hard_header_parse = header_parse_80211;
+	mdev->header_ops = &ieee80211_header_ops;
 
 	sdata->type = IEEE80211_IF_TYPE_AP;
 	sdata->dev = mdev;
--- a/net/netrom/nr_dev.c	2007-08-24 13:41:02.000000000 -0700
+++ b/net/netrom/nr_dev.c	2007-08-24 13:41:17.000000000 -0700
@@ -95,8 +95,9 @@ static int nr_rebuild_header(struct sk_b
 
 #endif
 
-static int nr_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
-	void *daddr, void *saddr, unsigned len)
+static int nr_header(struct sk_buff *skb, struct net_device *dev,
+		     unsigned short type,
+		     const void *daddr, const void *saddr, unsigned len)
 {
 	unsigned char *buff = skb_push(skb, NR_NETWORK_LEN + NR_TRANSPORT_LEN);
 
@@ -193,6 +194,12 @@ static struct net_device_stats *nr_get_s
 	return &nr->stats;
 }
 
+static const struct header_ops nr_header_ops = {
+	.create	= nr_header,
+	.rebuild= nr_rebuild_header,
+};
+
+
 void nr_setup(struct net_device *dev)
 {
 	dev->mtu		= NR_MAX_PACKET_SIZE;
@@ -200,11 +207,10 @@ void nr_setup(struct net_device *dev)
 	dev->open		= nr_open;
 	dev->stop		= nr_close;
 
-	dev->hard_header	= nr_header;
+	dev->header_ops		= &nr_header_ops;
 	dev->hard_header_len	= NR_NETWORK_LEN + NR_TRANSPORT_LEN;
 	dev->addr_len		= AX25_ADDR_LEN;
 	dev->type		= ARPHRD_NETROM;
-	dev->rebuild_header	= nr_rebuild_header;
 	dev->set_mac_address    = nr_set_mac_address;
 
 	/* New-style flags. */
--- a/net/packet/af_packet.c	2007-08-24 13:41:15.000000000 -0700
+++ b/net/packet/af_packet.c	2007-08-24 13:41:17.000000000 -0700
@@ -385,7 +385,7 @@ static int packet_sendmsg_spkt(struct ki
 	skb_reset_network_header(skb);
 
 	/* Try to align data part correctly */
-	if (dev->hard_header) {
+	if (dev->header_ops) {
 		skb->data -= dev->hard_header_len;
 		skb->tail -= dev->hard_header_len;
 		if (len < dev->hard_header_len)
@@ -459,7 +459,7 @@ static int packet_rcv(struct sk_buff *sk
 
 	skb->dev = dev;
 
-	if (dev->hard_header) {
+	if (dev->header_ops) {
 		/* The device has an explicit notion of ll header,
 		   exported to higher levels.
 
@@ -571,7 +571,7 @@ static int tpacket_rcv(struct sk_buff *s
 	sk = pt->af_packet_priv;
 	po = pkt_sk(sk);
 
-	if (dev->hard_header) {
+	if (dev->header_ops) {
 		if (sk->sk_type != SOCK_DGRAM)
 			skb_push(skb, skb->data - skb_mac_header(skb));
 		else if (skb->pkt_type == PACKET_OUTGOING) {
--- a/net/rose/rose_dev.c	2007-08-24 13:41:02.000000000 -0700
+++ b/net/rose/rose_dev.c	2007-08-24 13:41:17.000000000 -0700
@@ -35,8 +35,9 @@
 #include <net/ax25.h>
 #include <net/rose.h>
 
-static int rose_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
-	void *daddr, void *saddr, unsigned len)
+static int rose_header(struct sk_buff *skb, struct net_device *dev,
+		       unsigned short type,
+		       const void *daddr, const void *saddr, unsigned len)
 {
 	unsigned char *buff = skb_push(skb, ROSE_MIN_LEN + 2);
 
@@ -148,6 +149,11 @@ static struct net_device_stats *rose_get
 	return netdev_priv(dev);
 }
 
+static const struct header_ops rose_header_ops = {
+	.create	= rose_header,
+	.rebuild= rose_rebuild_header,
+};
+
 void rose_setup(struct net_device *dev)
 {
 	dev->mtu		= ROSE_MAX_PACKET_SIZE - 2;
@@ -155,11 +161,10 @@ void rose_setup(struct net_device *dev)
 	dev->open		= rose_open;
 	dev->stop		= rose_close;
 
-	dev->hard_header	= rose_header;
+	dev->header_ops		= &rose_header_ops;
 	dev->hard_header_len	= AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN;
 	dev->addr_len		= ROSE_ADDR_LEN;
 	dev->type		= ARPHRD_ROSE;
-	dev->rebuild_header	= rose_rebuild_header;
 	dev->set_mac_address    = rose_set_mac_address;
 
 	/* New-style flags. */
--- a/net/sched/sch_teql.c	2007-08-24 13:41:14.000000000 -0700
+++ b/net/sched/sch_teql.c	2007-08-24 13:41:17.000000000 -0700
@@ -249,10 +249,10 @@ __teql_resolve(struct sk_buff *skb, stru
 	return (skb_res == NULL) ? -EAGAIN : 1;
 }
 
-static __inline__ int
-teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res, struct net_device *dev)
+static inline int teql_resolve(struct sk_buff *skb,
+			       struct sk_buff *skb_res, struct net_device *dev)
 {
-	if (dev->hard_header == NULL ||
+	if (dev->header_ops == NULL ||
 	    skb->dst == NULL ||
 	    skb->dst->neighbour == NULL)
 		return 0;
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c	2007-08-24 13:41:02.000000000 -0700
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c	2007-08-24 13:41:17.000000000 -0700
@@ -777,7 +777,7 @@ static void ipoib_timeout(struct net_dev
 static int ipoib_hard_header(struct sk_buff *skb,
 			     struct net_device *dev,
 			     unsigned short type,
-			     void *daddr, void *saddr, unsigned len)
+			     const void *daddr, const void *saddr, unsigned len)
 {
 	struct ipoib_header *header;
 
@@ -937,6 +937,10 @@ void ipoib_dev_cleanup(struct net_device
 	priv->tx_ring = NULL;
 }
 
+static const struct header_ops ipoib_header_ops = {
+	.create	= ipoib_hard_header,
+};
+
 static void ipoib_setup(struct net_device *dev)
 {
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
@@ -947,7 +951,7 @@ static void ipoib_setup(struct net_devic
 	dev->hard_start_xmit 	 = ipoib_start_xmit;
 	dev->get_stats 		 = ipoib_get_stats;
 	dev->tx_timeout 	 = ipoib_timeout;
-	dev->hard_header 	 = ipoib_hard_header;
+	dev->header_ops 	 = &ipoib_header_ops;
 	dev->set_multicast_list  = ipoib_set_mcast_list;
 	dev->neigh_setup         = ipoib_neigh_setup_dev;
 
--- a/drivers/isdn/i4l/isdn_net.c	2007-08-24 13:41:02.000000000 -0700
+++ b/drivers/isdn/i4l/isdn_net.c	2007-08-24 13:41:17.000000000 -0700
@@ -1873,54 +1873,14 @@ isdn_net_rcv_skb(int idx, struct sk_buff
 	return 0;
 }
 
-static int
-my_eth_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
-	      void *daddr, void *saddr, unsigned len)
-{
-	struct ethhdr *eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
-
-	/*
-	 * Set the protocol type. For a packet of type ETH_P_802_3 we
-	 * put the length here instead. It is up to the 802.2 layer to
-	 * carry protocol information.
-	 */
-
-	if (type != ETH_P_802_3)
-		eth->h_proto = htons(type);
-	else
-		eth->h_proto = htons(len);
-
-	/*
-	 * Set the source hardware address.
-	 */
-	if (saddr)
-		memcpy(eth->h_source, saddr, dev->addr_len);
-	else
-		memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
-
-	/*
-	 * Anyway, the loopback-device should never use this function...
-	 */
-
-	if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) {
-		memset(eth->h_dest, 0, dev->addr_len);
-		return ETH_HLEN /*(dev->hard_header_len)*/;
-	}
-	if (daddr) {
-		memcpy(eth->h_dest, daddr, dev->addr_len);
-		return ETH_HLEN /*dev->hard_header_len*/;
-	}
-	return -ETH_HLEN /*dev->hard_header_len*/;
-}
-
 /*
  *  build an header
  *  depends on encaps that is being used.
  */
 
-static int
-isdn_net_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
-		void *daddr, void *saddr, unsigned plen)
+static int isdn_net_header(struct sk_buff *skb, struct net_device *dev,
+			   unsigned short type,
+			   const void *daddr, const void *saddr, unsigned plen)
 {
 	isdn_net_local *lp = dev->priv;
 	unsigned char *p;
@@ -1928,7 +1888,7 @@ isdn_net_header(struct sk_buff *skb, str
 
 	switch (lp->p_encap) {
 		case ISDN_NET_ENCAP_ETHER:
-			len = my_eth_header(skb, dev, type, daddr, saddr, plen);
+			len = eth_header(skb, dev, type, daddr, saddr, plen);
 			break;
 #ifdef CONFIG_ISDN_PPP
 		case ISDN_NET_ENCAP_SYNCPPP:
@@ -2005,6 +1965,32 @@ isdn_net_rebuild_header(struct sk_buff *
 	return ret;
 }
 
+static int isdn_header_cache(const struct neighbour *neigh, struct hh_cache *hh)
+{
+	const struct net_device *dev = neigh->dev;
+	isdn_net_local *lp = dev->priv;
+
+	if (lp->p_encap == ISDN_NET_ENCAP_ETHER)
+		return eth_header_cache(neigh, hh);
+	return -1;
+}
+
+static void isdn_header_cache_update(struct hh_cache *hh,
+				     const struct net_device *dev,
+				     const unsigned char *haddr)
+{
+	isdn_net_local *lp = dev->priv;
+	if (lp->p_encap == ISDN_NET_ENCAP_ETHER)
+		return eth_header_cache_update(hh, dev, haddr);
+}
+
+static const struct header_ops isdn_header_ops = {
+	.create = isdn_net_header,
+	.rebuild = isdn_net_rebuild_header,
+	.cache = isdn_header_cache,
+	.cache_update = isdn_header_cache_update,
+};
+
 /*
  * Interface-setup. (just after registering a new interface)
  */
@@ -2012,18 +1998,12 @@ static int
 isdn_net_init(struct net_device *ndev)
 {
 	ushort max_hlhdr_len = 0;
-	isdn_net_local *lp = (isdn_net_local *) ndev->priv;
-	int drvidx, i;
+	int drvidx;
 
 	ether_setup(ndev);
-	lp->org_hhc = ndev->hard_header_cache;
-	lp->org_hcu = ndev->header_cache_update;
+	ndev->header_ops = NULL;
 
 	/* Setup the generic properties */
-
-	ndev->hard_header = NULL;
-	ndev->hard_header_cache = NULL;
-	ndev->header_cache_update = NULL;
 	ndev->mtu = 1500;
 	ndev->flags = IFF_NOARP|IFF_POINTOPOINT;
 	ndev->type = ARPHRD_ETHER;
@@ -2032,9 +2012,6 @@ isdn_net_init(struct net_device *ndev)
 	/* for clients with MPPP maybe higher values better */
 	ndev->tx_queue_len = 30;
 
-	for (i = 0; i < ETH_ALEN; i++)
-		ndev->broadcast[i] = 0xff;
-
 	/* The ISDN-specific entries in the device structure. */
 	ndev->open = &isdn_net_open;
 	ndev->hard_start_xmit = &isdn_net_start_xmit;
@@ -2052,7 +2029,6 @@ isdn_net_init(struct net_device *ndev)
 	ndev->hard_header_len = ETH_HLEN + max_hlhdr_len;
 	ndev->stop = &isdn_net_close;
 	ndev->get_stats = &isdn_net_get_stats;
-	ndev->rebuild_header = &isdn_net_rebuild_header;
 	ndev->do_ioctl = NULL;
 	return 0;
 }
@@ -2861,21 +2837,14 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg
 		}
 		if (cfg->p_encap != lp->p_encap) {
 			if (cfg->p_encap == ISDN_NET_ENCAP_RAWIP) {
-				p->dev.hard_header = NULL;
-				p->dev.hard_header_cache = NULL;
-				p->dev.header_cache_update = NULL;
+				p->dev.header_ops = NULL;
 				p->dev.flags = IFF_NOARP|IFF_POINTOPOINT;
 			} else {
-				p->dev.hard_header = isdn_net_header;
-				if (cfg->p_encap == ISDN_NET_ENCAP_ETHER) {
-					p->dev.hard_header_cache = lp->org_hhc;
-					p->dev.header_cache_update = lp->org_hcu;
+				p->dev.header_ops = &isdn_header_ops;
+				if (cfg->p_encap == ISDN_NET_ENCAP_ETHER)
 					p->dev.flags = IFF_BROADCAST | IFF_MULTICAST;
-				} else {
-					p->dev.hard_header_cache = NULL;
-					p->dev.header_cache_update = NULL;
+				else
 					p->dev.flags = IFF_NOARP|IFF_POINTOPOINT;
-				}
 			}
 		}
 		lp->p_encap = cfg->p_encap;
@@ -3127,8 +3096,6 @@ isdn_net_realrm(isdn_net_dev * p, isdn_n
 			((isdn_net_local *) (p->local->master->priv))->slave = p->local->slave;
 	} else {
 		/* Unregister only if it's a master-device */
-		p->dev.hard_header_cache = p->local->org_hhc;
-		p->dev.header_cache_update = p->local->org_hcu;
 		unregister_netdev(&p->dev);
 	}
 	/* Unlink device from chain */
--- a/drivers/media/dvb/dvb-core/dvb_net.c	2007-08-24 13:41:02.000000000 -0700
+++ b/drivers/media/dvb/dvb-core/dvb_net.c	2007-08-24 13:41:17.000000000 -0700
@@ -1224,10 +1224,17 @@ static struct net_device_stats * dvb_net
 	return &((struct dvb_net_priv*) dev->priv)->stats;
 }
 
+static const struct header_ops dvb_header_ops = {
+	.create		= eth_header,
+	.parse		= eth_header_parse,
+	.rebuild	= eth_rebuild_header,
+};
+
 static void dvb_net_setup(struct net_device *dev)
 {
 	ether_setup(dev);
 
+	dev->header_ops		= &dvb_header_ops;
 	dev->open		= dvb_net_open;
 	dev->stop		= dvb_net_stop;
 	dev->hard_start_xmit	= dvb_net_tx;
@@ -1236,7 +1243,7 @@ static void dvb_net_setup(struct net_dev
 	dev->set_mac_address    = dvb_net_set_mac;
 	dev->mtu		= 4096;
 	dev->mc_count           = 0;
-	dev->hard_header_cache  = NULL;
+
 	dev->flags |= IFF_NOARP;
 }
 
--- a/drivers/net/plip.c	2007-08-24 13:41:02.000000000 -0700
+++ b/drivers/net/plip.c	2007-08-24 13:41:17.000000000 -0700
@@ -148,9 +148,9 @@ static void plip_interrupt(int irq, void
 /* Functions for DEV methods */
 static int plip_tx_packet(struct sk_buff *skb, struct net_device *dev);
 static int plip_hard_header(struct sk_buff *skb, struct net_device *dev,
-                            unsigned short type, void *daddr,
-                            void *saddr, unsigned len);
-static int plip_hard_header_cache(struct neighbour *neigh,
+                            unsigned short type, const void *daddr,
+			    const void *saddr, unsigned len);
+static int plip_hard_header_cache(const struct neighbour *neigh,
                                   struct hh_cache *hh);
 static int plip_open(struct net_device *dev);
 static int plip_close(struct net_device *dev);
@@ -221,11 +221,6 @@ struct net_local {
 	int is_deferred;
 	int port_owner;
 	int should_relinquish;
-	int (*orig_hard_header)(struct sk_buff *skb, struct net_device *dev,
-	                        unsigned short type, void *daddr,
-	                        void *saddr, unsigned len);
-	int (*orig_hard_header_cache)(struct neighbour *neigh,
-	                              struct hh_cache *hh);
 	spinlock_t lock;
 	atomic_t kill_timer;
 	struct semaphore killed_timer_sem;
@@ -267,6 +262,11 @@ static inline unsigned char read_status 
 	return port->ops->read_status (port);
 }
 
+static const struct header_ops plip_header_ops = {
+	.create	= plip_hard_header,
+	.cache  = plip_hard_header_cache,
+};
+
 /* Entry point of PLIP driver.
    Probe the hardware, and register/initialize the driver.
 
@@ -287,17 +287,12 @@ plip_init_netdev(struct net_device *dev)
 	dev->stop		 = plip_close;
 	dev->get_stats 		 = plip_get_stats;
 	dev->do_ioctl		 = plip_ioctl;
-	dev->header_cache_update = NULL;
+
 	dev->tx_queue_len 	 = 10;
 	dev->flags	         = IFF_POINTOPOINT|IFF_NOARP;
 	memset(dev->dev_addr, 0xfc, ETH_ALEN);
 
-	/* Set the private structure */
-	nl->orig_hard_header    = dev->hard_header;
-	dev->hard_header        = plip_hard_header;
-
-	nl->orig_hard_header_cache = dev->hard_header_cache;
-	dev->hard_header_cache     = plip_hard_header_cache;
+	dev->header_ops          = &plip_header_ops;
 
 
 	nl->port_owner = 0;
@@ -996,14 +991,14 @@ plip_tx_packet(struct sk_buff *skb, stru
 }
 
 static void
-plip_rewrite_address(struct net_device *dev, struct ethhdr *eth)
+plip_rewrite_address(const struct net_device *dev, struct ethhdr *eth)
 {
-	struct in_device *in_dev;
+	const struct in_device *in_dev = dev->ip_ptr;
 
-	if ((in_dev=dev->ip_ptr) != NULL) {
+	if (in_dev) {
 		/* Any address will do - we take the first */
-		struct in_ifaddr *ifa=in_dev->ifa_list;
-		if (ifa != NULL) {
+		const struct in_ifaddr *ifa = in_dev->ifa_list;
+		if (ifa) {
 			memcpy(eth->h_source, dev->dev_addr, 6);
 			memset(eth->h_dest, 0xfc, 2);
 			memcpy(eth->h_dest+2, &ifa->ifa_address, 4);
@@ -1013,26 +1008,25 @@ plip_rewrite_address(struct net_device *
 
 static int
 plip_hard_header(struct sk_buff *skb, struct net_device *dev,
-                 unsigned short type, void *daddr,
-	         void *saddr, unsigned len)
+		 unsigned short type, const void *daddr,
+		 const void *saddr, unsigned len)
 {
-	struct net_local *nl = netdev_priv(dev);
 	int ret;
 
-	if ((ret = nl->orig_hard_header(skb, dev, type, daddr, saddr, len)) >= 0)
+	ret = eth_header(skb, dev, type, daddr, saddr, len);
+	if (ret >= 0)
 		plip_rewrite_address (dev, (struct ethhdr *)skb->data);
 
 	return ret;
 }
 
-int plip_hard_header_cache(struct neighbour *neigh,
+int plip_hard_header_cache(const struct neighbour *neigh,
                            struct hh_cache *hh)
 {
-	struct net_local *nl = neigh->dev->priv;
 	int ret;
 
-	if ((ret = nl->orig_hard_header_cache(neigh, hh)) == 0)
-	{
+	ret = eth_header_cache(neigh, hh);
+	if (ret == 0) {
 		struct ethhdr *eth;
 
 		eth = (struct ethhdr*)(((u8*)hh->hh_data) +
--- a/drivers/net/wireless/airo.c	2007-08-24 13:41:15.000000000 -0700
+++ b/drivers/net/wireless/airo.c	2007-08-24 13:41:17.000000000 -0700
@@ -2696,9 +2696,13 @@ static int mpi_map_card(struct airo_info
 	return rc;
 }
 
+static const struct header_ops airo_header_ops = {
+	.parse = wll_header_parse,
+};
+
 static void wifi_setup(struct net_device *dev)
 {
-	dev->hard_header_parse  = wll_header_parse;
+	dev->header_ops = &airo_header_ops;
 	dev->hard_start_xmit = &airo_start_xmit11;
 	dev->get_stats = &airo_get_stats;
 	dev->set_mac_address = &airo_set_mac_address;
--- a/drivers/net/wireless/hostap/hostap.h	2007-08-24 13:41:02.000000000 -0700
+++ b/drivers/net/wireless/hostap/hostap.h	2007-08-24 13:41:17.000000000 -0700
@@ -30,8 +30,7 @@ void hostap_dump_rx_header(const char *n
 			   const struct hfa384x_rx_frame *rx);
 void hostap_dump_tx_header(const char *name,
 			   const struct hfa384x_tx_frame *tx);
-int hostap_80211_header_parse(struct sk_buff *skb, unsigned char *haddr);
-int hostap_80211_prism_header_parse(struct sk_buff *skb, unsigned char *haddr);
+extern const struct header_ops hostap_80211_ops;
 int hostap_80211_get_hdrlen(u16 fc);
 struct net_device_stats *hostap_get_stats(struct net_device *dev);
 void hostap_setup_dev(struct net_device *dev, local_info_t *local,
--- a/drivers/net/wireless/hostap/hostap_hw.c	2007-08-24 13:41:02.000000000 -0700
+++ b/drivers/net/wireless/hostap/hostap_hw.c	2007-08-24 13:41:17.000000000 -0700
@@ -3255,11 +3255,10 @@ while (0)
 	INIT_LIST_HEAD(&local->bss_list);
 
 	hostap_setup_dev(dev, local, 1);
-	local->saved_eth_header_parse = dev->hard_header_parse;
 
 	dev->hard_start_xmit = hostap_master_start_xmit;
 	dev->type = ARPHRD_IEEE80211;
-	dev->hard_header_parse = hostap_80211_header_parse;
+	dev->header_ops = &hostap_80211_ops;
 
 	rtnl_lock();
 	ret = dev_alloc_name(dev, "wifi%d");
--- a/drivers/net/wireless/hostap/hostap_ioctl.c	2007-08-24 13:41:02.000000000 -0700
+++ b/drivers/net/wireless/hostap/hostap_ioctl.c	2007-08-24 13:41:17.000000000 -0700
@@ -896,11 +896,8 @@ static void hostap_monitor_set_type(loca
 	if (local->monitor_type == PRISM2_MONITOR_PRISM ||
 	    local->monitor_type == PRISM2_MONITOR_CAPHDR) {
 		dev->type = ARPHRD_IEEE80211_PRISM;
-		dev->hard_header_parse =
-			hostap_80211_prism_header_parse;
 	} else {
 		dev->type = ARPHRD_IEEE80211;
-		dev->hard_header_parse = hostap_80211_header_parse;
 	}
 }
 
@@ -1140,7 +1137,7 @@ static int hostap_monitor_mode_disable(l
 
 	printk(KERN_DEBUG "%s: Disabling monitor mode\n", dev->name);
 	dev->type = ARPHRD_ETHER;
-	dev->hard_header_parse = local->saved_eth_header_parse;
+
 	if (local->func->cmd(dev, HFA384X_CMDCODE_TEST |
 			     (HFA384X_TEST_STOP << 8),
 			     0, NULL, NULL))
--- a/drivers/net/wireless/hostap/hostap_main.c	2007-08-24 13:41:02.000000000 -0700
+++ b/drivers/net/wireless/hostap/hostap_main.c	2007-08-24 13:41:17.000000000 -0700
@@ -587,24 +587,27 @@ void hostap_dump_tx_header(const char *n
 }
 
 
-int hostap_80211_header_parse(struct sk_buff *skb, unsigned char *haddr)
+int hostap_80211_header_parse(const struct sk_buff *skb, unsigned char *haddr)
 {
-	memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */
-	return ETH_ALEN;
-}
+	struct hostap_interface *iface = netdev_priv(skb->dev);
+	local_info_t *local = iface->local;
 
+	if (local->monitor_type == PRISM2_MONITOR_PRISM ||
+	    local->monitor_type == PRISM2_MONITOR_CAPHDR) {
+		const unsigned char *mac = skb_mac_header(skb);
+
+		if (*(u32 *)mac == LWNG_CAP_DID_BASE) {
+			memcpy(haddr,
+			       mac + sizeof(struct linux_wlan_ng_prism_hdr) + 10,
+			       ETH_ALEN); /* addr2 */
+		} else { /* (*(u32 *)mac == htonl(LWNG_CAPHDR_VERSION)) */
+			memcpy(haddr,
+			       mac + sizeof(struct linux_wlan_ng_cap_hdr) + 10,
+			       ETH_ALEN); /* addr2 */
+		}
+	} else
+		memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */
 
-int hostap_80211_prism_header_parse(struct sk_buff *skb, unsigned char *haddr)
-{
-	const unsigned char *mac = skb_mac_header(skb);
-
-	if (*(u32 *)mac == LWNG_CAP_DID_BASE) {
-		memcpy(haddr, mac + sizeof(struct linux_wlan_ng_prism_hdr) + 10,
-		       ETH_ALEN); /* addr2 */
-	} else { /* (*(u32 *)mac == htonl(LWNG_CAPHDR_VERSION)) */
-		memcpy(haddr, mac + sizeof(struct linux_wlan_ng_cap_hdr) + 10,
-		       ETH_ALEN); /* addr2 */
-	}
 	return ETH_ALEN;
 }
 
@@ -836,6 +839,15 @@ static void prism2_tx_timeout(struct net
 	local->func->schedule_reset(local);
 }
 
+const struct header_ops hostap_80211_ops = {
+	.create		= eth_header,
+	.rebuild	= eth_rebuild_header,
+	.cache		= eth_header_cache,
+	.cache_update	= eth_header_cache_update,
+
+	.parse		= hostap_80211_header_parse,
+};
+EXPORT_SYMBOL(hostap_80211_ops);
 
 void hostap_setup_dev(struct net_device *dev, local_info_t *local,
 		      int main_dev)
@@ -876,7 +888,6 @@ void hostap_setup_dev(struct net_device 
 	netif_stop_queue(dev);
 }
 
-
 static int hostap_enable_hostapd(local_info_t *local, int rtnl_locked)
 {
 	struct net_device *dev = local->dev;
@@ -894,7 +905,7 @@ static int hostap_enable_hostapd(local_i
 
 	local->apdev->hard_start_xmit = hostap_mgmt_start_xmit;
 	local->apdev->type = ARPHRD_IEEE80211;
-	local->apdev->hard_header_parse = hostap_80211_header_parse;
+	local->apdev->header_ops = &hostap_80211_ops;
 
 	return 0;
 }
--- a/drivers/net/wireless/hostap/hostap_wlan.h	2007-08-24 13:41:02.000000000 -0700
+++ b/drivers/net/wireless/hostap/hostap_wlan.h	2007-08-24 13:41:17.000000000 -0700
@@ -735,8 +735,6 @@ struct local_info {
 		PRISM2_MONITOR_80211 = 0, PRISM2_MONITOR_PRISM = 1,
 		PRISM2_MONITOR_CAPHDR = 2
 	} monitor_type;
-	int (*saved_eth_header_parse)(struct sk_buff *skb,
-				      unsigned char *haddr);
 	int monitor_allow_fcserr;
 
 	int hostapd; /* whether user space daemon, hostapd, is used for AP
--- a/include/linux/isdn.h	2007-08-24 13:41:02.000000000 -0700
+++ b/include/linux/isdn.h	2007-08-24 13:41:17.000000000 -0700
@@ -353,13 +353,6 @@ typedef struct isdn_net_local_s {
                                        /* a particular channel (including  */
                                        /* the frame_cnt                    */
 
-  int                    (*org_hhc)(
-				    struct neighbour *neigh,
-				    struct hh_cache *hh);
-                                       /* Ptr to orig. header_cache_update */
-  void                   (*org_hcu)(struct hh_cache *,
-				    struct net_device *,
-                                    unsigned char *);
   int  pppbind;                        /* ippp device for bindings         */
   int					dialtimeout;	/* How long shall we try on dialing? (jiffies) */
   int					dialwait;		/* How long shall we wait after failed attempt? (jiffies) */
--- a/drivers/s390/net/qeth.h	2007-08-24 13:41:02.000000000 -0700
+++ b/drivers/s390/net/qeth.h	2007-08-24 13:41:17.000000000 -0700
@@ -833,8 +833,7 @@ struct qeth_card {
 	struct qeth_qdio_info qdio;
 	struct qeth_perf_stats perf_stats;
 	int use_hard_stop;
-	int (*orig_hard_header)(struct sk_buff *,struct net_device *,
-				unsigned short,void *,void *,unsigned);
+	const struct header_ops *orig_header_ops;
 	struct qeth_osn_info osn_info;
 	atomic_t force_alloc_skb;
 };
--- a/drivers/s390/net/qeth_main.c	2007-08-24 13:41:15.000000000 -0700
+++ b/drivers/s390/net/qeth_main.c	2007-08-24 13:41:17.000000000 -0700
@@ -160,6 +160,9 @@ qeth_set_multicast_list(struct net_devic
 static void
 qeth_setadp_promisc_mode(struct qeth_card *);
 
+static int
+qeth_hard_header_parse(const struct sk_buff *skb, unsigned char *haddr);
+
 static void
 qeth_notify_processes(void)
 {
@@ -3769,8 +3772,8 @@ qeth_get_netdevice(enum qeth_card_types 
 /*hard_header fake function; used in case fake_ll is set */
 static int
 qeth_fake_header(struct sk_buff *skb, struct net_device *dev,
-		     unsigned short type, void *daddr, void *saddr,
-		     unsigned len)
+		 unsigned short type, const void *daddr, const void *saddr,
+		 unsigned len)
 {
 	if(dev->type == ARPHRD_IEEE802_TR){
 		struct trh_hdr *hdr;
@@ -3793,6 +3796,11 @@ qeth_fake_header(struct sk_buff *skb, st
 	}
 }
 
+static const struct header_ops qeth_fake_ops = {
+	.create	= qeth_fake_header,
+	.parse  = qeth_hard_header_parse,
+};
+
 static int
 qeth_send_packet(struct qeth_card *, struct sk_buff *);
 
@@ -4584,7 +4592,7 @@ qeth_send_packet(struct qeth_card *card,
 		[qeth_get_priority_queue(card, skb, ipv, cast_type)];
 	if (!card->options.layer2) {
 		ipv = qeth_get_ip_version(skb);
-		if ((card->dev->hard_header == qeth_fake_header) && ipv) {
+		if ((card->dev->header_ops == &qeth_fake_ops) && ipv) {
 			new_skb = qeth_pskb_unshare(skb, GFP_ATOMIC);
 			if (!new_skb)
 				return -ENOMEM;
@@ -6493,6 +6501,9 @@ qeth_hard_header_parse(const struct sk_b
 	const struct qeth_card *card;
 	const struct ethhdr *eth;
 
+	if (dev->type != ARPHRD_IEEE802_TR)
+		return 0;
+
 	card = qeth_get_card_from_dev(skb->dev);
 	if (card->options.layer2)
 		goto haveheader;
@@ -6523,6 +6534,10 @@ haveheader:
 	return ETH_ALEN;
 }
 
+static const struct header_ops qeth_null_ops = {
+	.parse = qeth_hard_header_parse,
+};
+
 static int
 qeth_netdev_init(struct net_device *dev)
 {
@@ -6547,12 +6562,8 @@ qeth_netdev_init(struct net_device *dev)
 	dev->vlan_rx_kill_vid = qeth_vlan_rx_kill_vid;
 	dev->vlan_rx_add_vid = qeth_vlan_rx_add_vid;
 #endif
-	if (qeth_get_netdev_flags(card) & IFF_NOARP) {
-		dev->rebuild_header = NULL;
-		dev->hard_header = NULL;
-		dev->header_cache_update = NULL;
-		dev->hard_header_cache = NULL;
-	}
+	dev->header_ops = &qeth_null_ops;
+
 #ifdef CONFIG_QETH_IPV6
 	/*IPv6 address autoconfiguration stuff*/
 	if (!(card->info.unique_id & UNIQUE_ID_NOT_BY_CARD))
@@ -6560,11 +6571,8 @@ qeth_netdev_init(struct net_device *dev)
 #endif
 	if (card->options.fake_ll &&
 		(qeth_get_netdev_flags(card) & IFF_NOARP))
-			dev->hard_header = qeth_fake_header;
-	if (dev->type == ARPHRD_IEEE802_TR)
-		dev->hard_header_parse = NULL;
-	else
-		dev->hard_header_parse = qeth_hard_header_parse;
+			dev->header_ops = &qeth_fake_ops;
+
 	dev->set_mac_address = qeth_layer2_set_mac_address;
 	dev->flags |= qeth_get_netdev_flags(card);
 	if ((card->options.fake_broadcast) ||
@@ -6668,10 +6676,10 @@ retry:
 	}
 	/*network device will be recovered*/
 	if (card->dev) {
-		card->dev->hard_header = card->orig_hard_header;
+		card->dev->header_ops = card->orig_header_ops;
 		if (card->options.fake_ll &&
 		    (qeth_get_netdev_flags(card) & IFF_NOARP))
-			card->dev->hard_header = qeth_fake_header;
+			card->dev->header_ops = &qeth_fake_ops;
 		return 0;
 	}
 	/* at first set_online allocate netdev */
@@ -6685,7 +6693,7 @@ retry:
 		goto out;
 	}
 	card->dev->priv = card;
-	card->orig_hard_header = card->dev->hard_header;
+	card->orig_header_ops = card->dev->header_ops;
 	card->dev->type = qeth_get_arphdr_type(card->info.type,
 					       card->info.link_type);
 	card->dev->init = qeth_netdev_init;
@@ -8231,7 +8239,7 @@ qeth_arp_constructor(struct neighbour *n
 	if (card == NULL)
 		goto out;
 	if((card->options.layer2) ||
-	   (card->dev->hard_header == qeth_fake_header))
+	   (card->dev->header_ops == &qeth_fake_ops))
 		goto out;
 
 	rcu_read_lock();
--- a/drivers/net/appletalk/cops.c	2007-08-24 13:41:02.000000000 -0700
+++ b/drivers/net/appletalk/cops.c	2007-08-24 13:41:17.000000000 -0700
@@ -194,10 +194,6 @@ static void cops_timeout(struct net_devi
 static void cops_rx (struct net_device *dev);
 static int  cops_send_packet (struct sk_buff *skb, struct net_device *dev);
 static void set_multicast_list (struct net_device *dev);
-static int  cops_hard_header (struct sk_buff *skb, struct net_device *dev,
-			      unsigned short type, void *daddr, void *saddr, 
-			      unsigned len);
-
 static int  cops_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
 static int  cops_close (struct net_device *dev);
 static struct net_device_stats *cops_get_stats (struct net_device *dev);
@@ -333,7 +329,6 @@ static int __init cops_probe1(struct net
 	dev->base_addr = ioaddr;
 
         lp = netdev_priv(dev);
-        memset(lp, 0, sizeof(struct cops_local));
         spin_lock_init(&lp->lock);
 
 	/* Copy local board variable to lp struct. */
@@ -342,7 +337,7 @@ static int __init cops_probe1(struct net
 	dev->hard_start_xmit    = cops_send_packet;
 	dev->tx_timeout		= cops_timeout;
 	dev->watchdog_timeo	= HZ * 2;
-	dev->hard_header	= cops_hard_header;
+
         dev->get_stats          = cops_get_stats;
 	dev->open               = cops_open;
         dev->stop               = cops_close;
@@ -947,19 +942,6 @@ static void set_multicast_list(struct ne
 }
 
 /*
- *      Another Dummy function to keep the Appletalk layer happy.
- */
- 
-static int cops_hard_header(struct sk_buff *skb, struct net_device *dev,
-			    unsigned short type, void *daddr, void *saddr, 
-			    unsigned len)
-{
-        if(cops_debug >= 3)
-                printk("%s: cops_hard_header executed. Wow!\n", dev->name);
-        return 0;
-}
-
-/*
  *      System ioctls for the COPS LocalTalk card.
  */
  
--- a/drivers/net/appletalk/ltpc.c	2007-08-24 13:41:02.000000000 -0700
+++ b/drivers/net/appletalk/ltpc.c	2007-08-24 13:41:17.000000000 -0700
@@ -870,15 +870,6 @@ static void set_multicast_list(struct ne
 	/* Actually netatalk needs fixing! */
 }
 
-static int ltpc_hard_header (struct sk_buff *skb, struct net_device *dev, 
-	unsigned short type, void *daddr, void *saddr, unsigned len)
-{
-	if(debug & DEBUG_VERBOSE)
-		printk("ltpc_hard_header called for device %s\n",
-			dev->name);
-	return 0;
-}
-
 static int ltpc_poll_counter;
 
 static void ltpc_poll(unsigned long l)
@@ -1143,7 +1134,6 @@ struct net_device * __init ltpc_probe(vo
 
 	/* Fill in the fields of the device structure with ethernet-generic values. */
 	dev->hard_start_xmit = ltpc_xmit;
-	dev->hard_header = ltpc_hard_header;
 	dev->get_stats = ltpc_get_stats;
 
 	/* add the ltpc-specific things */
--- a/drivers/net/wan/cycx_x25.c	2007-08-24 13:41:02.000000000 -0700
+++ b/drivers/net/wan/cycx_x25.c	2007-08-24 13:41:17.000000000 -0700
@@ -131,14 +131,15 @@ static int cycx_wan_update(struct wan_de
 	   cycx_wan_del_if(struct wan_device *wandev, struct net_device *dev);
 
 /* Network device interface */
-static int cycx_netdevice_init(struct net_device *dev),
-	   cycx_netdevice_open(struct net_device *dev),
-	   cycx_netdevice_stop(struct net_device *dev),
-	   cycx_netdevice_hard_header(struct sk_buff *skb,
-				     struct net_device *dev, u16 type,
-				     void *daddr, void *saddr, unsigned len),
-	   cycx_netdevice_rebuild_header(struct sk_buff *skb),
-	   cycx_netdevice_hard_start_xmit(struct sk_buff *skb,
+static int cycx_netdevice_init(struct net_device *dev);
+static int cycx_netdevice_open(struct net_device *dev);
+static int cycx_netdevice_stop(struct net_device *dev);
+static int cycx_netdevice_hard_header(struct sk_buff *skb,
+				      struct net_device *dev, u16 type,
+				      const void *daddr, const void *saddr,
+				      unsigned len);
+static int cycx_netdevice_rebuild_header(struct sk_buff *skb);
+static int cycx_netdevice_hard_start_xmit(struct sk_buff *skb,
 					  struct net_device *dev);
 
 static struct net_device_stats *
@@ -468,7 +469,14 @@ static int cycx_wan_del_if(struct wan_de
 	return 0;
 }
 
+
 /* Network Device Interface */
+
+static const struct header_ops cycx_header_ops = {
+	.create = cycx_netdevice_hard_header,
+	.rebuild = cycx_netdevice_rebuild_header,
+};
+
 /* Initialize Linux network interface.
  *
  * This routine is called only once for each interface, during Linux network
@@ -483,8 +491,8 @@ static int cycx_netdevice_init(struct ne
 	/* Initialize device driver entry points */
 	dev->open		= cycx_netdevice_open;
 	dev->stop		= cycx_netdevice_stop;
-	dev->hard_header	= cycx_netdevice_hard_header;
-	dev->rebuild_header	= cycx_netdevice_rebuild_header;
+	dev->header_ops		= &cycx_header_ops;
+
 	dev->hard_start_xmit	= cycx_netdevice_hard_start_xmit;
 	dev->get_stats		= cycx_netdevice_get_stats;
 
@@ -555,7 +563,8 @@ static int cycx_netdevice_stop(struct ne
  * Return:	media header length. */
 static int cycx_netdevice_hard_header(struct sk_buff *skb,
 				      struct net_device *dev, u16 type,
-				      void *daddr, void *saddr, unsigned len)
+				      const void *daddr, const void *saddr,
+				      unsigned len)
 {
 	skb->protocol = type;
 
--- a/drivers/net/wan/dlci.c	2007-08-24 13:41:02.000000000 -0700
+++ b/drivers/net/wan/dlci.c	2007-08-24 13:41:17.000000000 -0700
@@ -66,8 +66,8 @@ static void dlci_setup(struct net_device
  */
 
 static int dlci_header(struct sk_buff *skb, struct net_device *dev, 
-                           unsigned short type, void *daddr, void *saddr, 
-                           unsigned len)
+		       unsigned short type, const void *daddr,
+		       const void *saddr, unsigned len)
 {
 	struct frhdr		hdr;
 	struct dlci_local	*dlp;
@@ -485,6 +485,10 @@ static int dlci_ioctl(unsigned int cmd, 
 	return(err);
 }
 
+static const struct header_ops dlci_header_ops = {
+	.create	= dlci_header,
+};
+
 static void dlci_setup(struct net_device *dev)
 {
 	struct dlci_local *dlp = dev->priv;
@@ -494,7 +498,7 @@ static void dlci_setup(struct net_device
 	dev->stop		= dlci_close;
 	dev->do_ioctl		= dlci_dev_ioctl;
 	dev->hard_start_xmit	= dlci_transmit;
-	dev->hard_header	= dlci_header;
+	dev->header_ops		= &dlci_header_ops;
 	dev->get_stats		= dlci_get_stats;
 	dev->change_mtu		= dlci_change_mtu;
 	dev->destructor		= free_netdev;
--- a/drivers/net/wan/hdlc.c	2007-08-24 13:41:02.000000000 -0700
+++ b/drivers/net/wan/hdlc.c	2007-08-24 13:41:17.000000000 -0700
@@ -222,6 +222,8 @@ int hdlc_ioctl(struct net_device *dev, s
 	return -EINVAL;
 }
 
+static const struct header_ops hdlc_null_ops;
+
 static void hdlc_setup_dev(struct net_device *dev)
 {
 	/* Re-init all variables changed by HDLC protocol drivers,
@@ -233,13 +235,9 @@ static void hdlc_setup_dev(struct net_de
 	dev->type		 = ARPHRD_RAWHDLC;
 	dev->hard_header_len	 = 16;
 	dev->addr_len		 = 0;
-	dev->hard_header	 = NULL;
-	dev->rebuild_header	 = NULL;
-	dev->set_mac_address	 = NULL;
-	dev->hard_header_cache	 = NULL;
-	dev->header_cache_update = NULL;
+	dev->header_ops		 = &hdlc_null_ops;
+
 	dev->change_mtu		 = hdlc_change_mtu;
-	dev->hard_header_parse	 = NULL;
 }
 
 static void hdlc_setup(struct net_device *dev)
--- a/drivers/net/wan/hdlc_cisco.c	2007-08-24 13:41:02.000000000 -0700
+++ b/drivers/net/wan/hdlc_cisco.c	2007-08-24 13:41:17.000000000 -0700
@@ -74,7 +74,7 @@ static inline struct cisco_state * state
 
 
 static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev,
-			     u16 type, void *daddr, void *saddr,
+			     u16 type, const void *daddr, const void *saddr,
 			     unsigned int len)
 {
 	struct hdlc_header *data;
@@ -309,7 +309,6 @@ static void cisco_stop(struct net_device
 }
 
 
-
 static struct hdlc_proto proto = {
 	.start		= cisco_start,
 	.stop		= cisco_stop,
@@ -317,7 +316,10 @@ static struct hdlc_proto proto = {
 	.ioctl		= cisco_ioctl,
 	.module		= THIS_MODULE,
 };
- 
+
+static const struct header_ops cisco_header_ops = {
+	.create = cisco_hard_header,
+};
  
 static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
 {
@@ -365,7 +367,7 @@ static int cisco_ioctl(struct net_device
 
 		memcpy(&state(hdlc)->settings, &new_settings, size);
 		dev->hard_start_xmit = hdlc->xmit;
-		dev->hard_header = cisco_hard_header;
+		dev->header_ops = &cisco_header_ops;
 		dev->type = ARPHRD_CISCO;
 		netif_dormant_on(dev);
 		return 0;
--- a/drivers/net/wan/hdlc_ppp.c	2007-08-24 13:41:02.000000000 -0700
+++ b/drivers/net/wan/hdlc_ppp.c	2007-08-24 13:41:17.000000000 -0700
@@ -73,7 +73,7 @@ static void ppp_close(struct net_device 
 
 	sppp_close(dev);
 	sppp_detach(dev);
-	dev->rebuild_header = NULL;
+
 	dev->change_mtu = state(hdlc)->old_change_mtu;
 	dev->mtu = HDLC_MAX_MTU;
 	dev->hard_header_len = 16;
--- a/drivers/net/wan/lmc/lmc_proto.c	2007-08-24 13:41:02.000000000 -0700
+++ b/drivers/net/wan/lmc/lmc_proto.c	2007-08-24 13:41:17.000000000 -0700
@@ -111,7 +111,7 @@ void lmc_proto_attach(lmc_softc_t *sc) /
              * They set a few basics because they don't use sync_ppp
              */
             dev->flags |= IFF_POINTOPOINT;
-            dev->hard_header = NULL;
+
             dev->hard_header_len = 0;
             dev->addr_len = 0;
         }
--- a/drivers/net/wan/syncppp.c	2007-08-24 13:41:02.000000000 -0700
+++ b/drivers/net/wan/syncppp.c	2007-08-24 13:41:17.000000000 -0700
@@ -358,8 +358,10 @@ done:
  *	Handle transmit packets.
  */
  
-static int sppp_hard_header(struct sk_buff *skb, struct net_device *dev, __u16 type,
-		void *daddr, void *saddr, unsigned int len)
+static int sppp_hard_header(struct sk_buff *skb,
+			    struct net_device *dev, __u16 type,
+			    const void *daddr, const void *saddr,
+			    unsigned int len)
 {
 	struct sppp *sp = (struct sppp *)sppp_of(dev);
 	struct ppp_header *h;
@@ -391,10 +393,9 @@ static int sppp_hard_header(struct sk_bu
 	return sizeof(struct ppp_header);
 }
 
-static int sppp_rebuild_header(struct sk_buff *skb)
-{
-	return 0;
-}
+static const struct header_ops sppp_header_ops = {
+	.create = sppp_hard_header,
+};
 
 /*
  * Send keepalive packets, every 10 seconds.
@@ -1097,8 +1098,8 @@ void sppp_attach(struct ppp_device *pd)
 	 *	hard_start_xmit.
 	 */
 	 
-	dev->hard_header = sppp_hard_header;
-	dev->rebuild_header = sppp_rebuild_header;
+	dev->header_ops = &sppp_header_ops;
+
 	dev->tx_queue_len = 10;
 	dev->type = ARPHRD_HDLC;
 	dev->addr_len = 0;
@@ -1114,8 +1115,6 @@ void sppp_attach(struct ppp_device *pd)
 	dev->stop = sppp_close;
 #endif	
 	dev->change_mtu = sppp_change_mtu;
-	dev->hard_header_cache = NULL;
-	dev->header_cache_update = NULL;
 	dev->flags = IFF_MULTICAST|IFF_POINTOPOINT|IFF_NOARP;
 }
 
--- a/drivers/net/wireless/strip.c	2007-08-24 13:41:02.000000000 -0700
+++ b/drivers/net/wireless/strip.c	2007-08-24 13:41:17.000000000 -0700
@@ -1630,8 +1630,8 @@ static void strip_IdleTask(unsigned long
  */
 
 static int strip_header(struct sk_buff *skb, struct net_device *dev,
-			unsigned short type, void *daddr, void *saddr,
-			unsigned len)
+			unsigned short type, const void *daddr,
+			const void *saddr, unsigned len)
 {
 	struct strip *strip_info = netdev_priv(dev);
 	STRIP_Header *header = (STRIP_Header *) skb_push(skb, sizeof(STRIP_Header));
@@ -2496,6 +2496,11 @@ static int strip_close_low(struct net_de
 	return 0;
 }
 
+static const struct header_ops strip_header_ops = {
+	.create = strip_header,
+	.rebuild = strip_rebuild_header,
+};
+
 /*
  * This routine is called by DDI when the
  * (dynamically assigned) device is registered
@@ -2532,8 +2537,8 @@ static void strip_dev_setup(struct net_d
 	dev->open = strip_open_low;
 	dev->stop = strip_close_low;
 	dev->hard_start_xmit = strip_xmit;
-	dev->hard_header = strip_header;
-	dev->rebuild_header = strip_rebuild_header;
+	dev->header_ops = &strip_header_ops;
+
 	dev->set_mac_address = strip_set_mac_address;
 	dev->get_stats = strip_get_stats;
 	dev->change_mtu = strip_change_mtu;
--- a/drivers/net/myri_sbus.c	2007-08-24 13:41:02.000000000 -0700
+++ b/drivers/net/myri_sbus.c	2007-08-24 13:41:17.000000000 -0700
@@ -682,8 +682,9 @@ static int myri_start_xmit(struct sk_buf
  * saddr=NULL	means use device source address
  * daddr=NULL	means leave destination address (eg unresolved arp)
  */
-static int myri_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
-		       void *daddr, void *saddr, unsigned len)
+static int myri_header(struct sk_buff *skb, struct net_device *dev,
+		       unsigned short type, const void *daddr,
+		       const void *saddr, unsigned len)
 {
 	struct ethhdr *eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
 	unsigned char *pad = (unsigned char *) skb_push(skb, MYRI_PAD_LEN);
@@ -765,18 +766,18 @@ static int myri_rebuild_header(struct sk
 	return 0;
 }
 
-int myri_header_cache(struct neighbour *neigh, struct hh_cache *hh)
+static int myri_header_cache(const struct neighbour *neigh, struct hh_cache *hh)
 {
 	unsigned short type = hh->hh_type;
 	unsigned char *pad;
 	struct ethhdr *eth;
-	struct net_device *dev = neigh->dev;
+	const struct net_device *dev = neigh->dev;
 
 	pad = ((unsigned char *) hh->hh_data) +
 		HH_DATA_OFF(sizeof(*eth) + MYRI_PAD_LEN);
 	eth = (struct ethhdr *) (pad + MYRI_PAD_LEN);
 
-	if (type == __constant_htons(ETH_P_802_3))
+	if (type == htons(ETH_P_802_3))
 		return -1;
 
 	/* Refill MyriNet padding identifiers, this is just being anal. */
@@ -792,7 +793,9 @@ int myri_header_cache(struct neighbour *
 
 
 /* Called by Address Resolution module to notify changes in address. */
-void myri_header_cache_update(struct hh_cache *hh, struct net_device *dev, unsigned char * haddr)
+void myri_header_cache_update(struct hh_cache *hh,
+			      const struct net_device *dev,
+			      const unsigned char * haddr)
 {
 	memcpy(((u8*)hh->hh_data) + HH_DATA_OFF(sizeof(struct ethhdr)),
 	       haddr, dev->addr_len);
@@ -890,6 +893,13 @@ static void dump_eeprom(struct myri_eth 
 }
 #endif
 
+static const struct header_ops myri_header_ops = {
+	.create		= myri_header,
+	.rebuild	= myri_rebuild_header,
+	.cache	 	= myri_header_cache,
+	.cache_update	= myri_header_cache_update,
+};
+
 static int __devinit myri_ether_init(struct sbus_dev *sdev)
 {
 	static int num;
@@ -1075,11 +1085,9 @@ static int __devinit myri_ether_init(str
 
 	dev->mtu		= MYRINET_MTU;
 	dev->change_mtu		= myri_change_mtu;
-	dev->hard_header	= myri_header;
-	dev->rebuild_header	= myri_rebuild_header;
+	dev->header_ops		= &myri_header_ops;
+
 	dev->hard_header_len	= (ETH_HLEN + MYRI_PAD_LEN);
-	dev->hard_header_cache 	= myri_header_cache;
-	dev->header_cache_update= myri_header_cache_update;
 
 	/* Load code onto the LANai. */
 	DET(("Loading LANAI firmware\n"));

-- 
Stephen Hemminger <shemminger@linux-foundation.org>


^ permalink raw reply

* [PATCH] via-velocity: use standard VLAN interface (resend)
From: Stephen Hemminger @ 2007-08-24 20:56 UTC (permalink / raw)
  To: Francois Romieu; +Cc: netdev

The via-velocity is using a non-standard VLAN interface configured
via module parameters (yuck).

Replace with the standard acceleration interface.
It solves a number of problems with being able to handle multiple
vlans, and dynamically reconfigure.

This is compile tested only, don't have this board.

Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>


---
 drivers/net/via-velocity.c |   71 +++++++++++++++++++++++++++------------------
 drivers/net/via-velocity.h |    3 +
 2 files changed, 45 insertions(+), 29 deletions(-)

--- a/drivers/net/via-velocity.c	2007-08-18 07:50:10.000000000 -0700
+++ b/drivers/net/via-velocity.c	2007-08-24 13:49:17.000000000 -0700
@@ -72,6 +72,7 @@
 #include <linux/mii.h>
 #include <linux/in.h>
 #include <linux/if_arp.h>
+#include <linux/if_vlan.h>
 #include <linux/ip.h>
 #include <linux/tcp.h>
 #include <linux/udp.h>
@@ -111,15 +112,6 @@ VELOCITY_PARAM(RxDescriptors, "Number of
 #define TX_DESC_DEF     64
 VELOCITY_PARAM(TxDescriptors, "Number of transmit descriptors");
 
-#define VLAN_ID_MIN     0
-#define VLAN_ID_MAX     4095
-#define VLAN_ID_DEF     0
-/* VID_setting[] is used for setting the VID of NIC.
-   0: default VID.
-   1-4094: other VIDs.
-*/
-VELOCITY_PARAM(VID_setting, "802.1Q VLAN ID");
-
 #define RX_THRESH_MIN   0
 #define RX_THRESH_MAX   3
 #define RX_THRESH_DEF   0
@@ -147,13 +139,6 @@ VELOCITY_PARAM(rx_thresh, "Receive fifo 
 */
 VELOCITY_PARAM(DMA_length, "DMA length");
 
-#define TAGGING_DEF     0
-/* enable_tagging[] is used for enabling 802.1Q VID tagging.
-   0: disable VID seeting(default).
-   1: enable VID setting.
-*/
-VELOCITY_PARAM(enable_tagging, "Enable 802.1Q tagging");
-
 #define IP_ALIG_DEF     0
 /* IP_byte_align[] is used for IP header DWORD byte aligned
    0: indicate the IP header won't be DWORD byte aligned.(Default) .
@@ -442,8 +427,7 @@ static void __devinit velocity_get_optio
 	velocity_set_int_opt(&opts->DMA_length, DMA_length[index], DMA_LENGTH_MIN, DMA_LENGTH_MAX, DMA_LENGTH_DEF, "DMA_length", devname);
 	velocity_set_int_opt(&opts->numrx, RxDescriptors[index], RX_DESC_MIN, RX_DESC_MAX, RX_DESC_DEF, "RxDescriptors", devname);
 	velocity_set_int_opt(&opts->numtx, TxDescriptors[index], TX_DESC_MIN, TX_DESC_MAX, TX_DESC_DEF, "TxDescriptors", devname);
-	velocity_set_int_opt(&opts->vid, VID_setting[index], VLAN_ID_MIN, VLAN_ID_MAX, VLAN_ID_DEF, "VID_setting", devname);
-	velocity_set_bool_opt(&opts->flags, enable_tagging[index], TAGGING_DEF, VELOCITY_FLAGS_TAGGING, "enable_tagging", devname);
+
 	velocity_set_bool_opt(&opts->flags, txcsum_offload[index], TX_CSUM_DEF, VELOCITY_FLAGS_TX_CSUM, "txcsum_offload", devname);
 	velocity_set_int_opt(&opts->flow_cntl, flow_control[index], FLOW_CNTL_MIN, FLOW_CNTL_MAX, FLOW_CNTL_DEF, "flow_control", devname);
 	velocity_set_bool_opt(&opts->flags, IP_byte_align[index], IP_ALIG_DEF, VELOCITY_FLAGS_IP_ALIGN, "IP_byte_align", devname);
@@ -465,6 +449,7 @@ static void __devinit velocity_get_optio
 static void velocity_init_cam_filter(struct velocity_info *vptr)
 {
 	struct mac_regs __iomem * regs = vptr->mac_regs;
+	unsigned short vid;
 
 	/* Turn on MCFG_PQEN, turn off MCFG_RTGOPT */
 	WORD_REG_BITS_SET(MCFG_PQEN, MCFG_RTGOPT, &regs->MCFG);
@@ -477,13 +462,19 @@ static void velocity_init_cam_filter(str
 	mac_set_cam_mask(regs, vptr->mCAMmask, VELOCITY_MULTICAST_CAM);
 
 	/* Enable first VCAM */
-	if (vptr->flags & VELOCITY_FLAGS_TAGGING) {
-		/* If Tagging option is enabled and VLAN ID is not zero, then
-		   turn on MCFG_RTGOPT also */
-		if (vptr->options.vid != 0)
-			WORD_REG_BITS_ON(MCFG_RTGOPT, &regs->MCFG);
+	if (vptr->vlgrp) {
+		for (vid = 0; vid < VLAN_VID_MASK; vid++) {
+			if (vlan_group_get_device(vptr->vlgrp, vid)) {
+				/* If Tagging option is enabled and
+				   VLAN ID is not zero, then
+				   turn on MCFG_RTGOPT also */
+				if (vid != 0)
+					WORD_REG_BITS_ON(MCFG_RTGOPT, &regs->MCFG);
 
-		mac_set_cam(regs, 0, (u8 *) & (vptr->options.vid), VELOCITY_VLAN_ID_CAM);
+				mac_set_cam(regs, 0, (u8 *) &vid,
+					    VELOCITY_VLAN_ID_CAM);
+			}
+		}
 		vptr->vCAMmask[0] |= 1;
 		mac_set_cam_mask(regs, vptr->vCAMmask, VELOCITY_VLAN_ID_CAM);
 	} else {
@@ -494,6 +485,26 @@ static void velocity_init_cam_filter(str
 	}
 }
 
+static void velocity_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
+{
+	struct velocity_info *vptr = netdev_priv(dev);
+
+        spin_lock_irq(&vptr->lock);
+	velocity_init_cam_filter(vptr);
+        spin_unlock_irq(&vptr->lock);
+}
+
+static void velocity_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
+{
+	struct velocity_info *vptr = netdev_priv(dev);
+
+        spin_lock_irq(&vptr->lock);
+	vlan_group_set_device(vptr->vlgrp, vid, NULL);
+	velocity_init_cam_filter(vptr);
+        spin_unlock_irq(&vptr->lock);
+}
+
+
 /**
  *	velocity_rx_reset	-	handle a receive reset
  *	@vptr: velocity we are resetting
@@ -791,13 +802,17 @@ static int __devinit velocity_found1(str
 	dev->do_ioctl = velocity_ioctl;
 	dev->ethtool_ops = &velocity_ethtool_ops;
 	dev->change_mtu = velocity_change_mtu;
+
+	dev->vlan_rx_add_vid = velocity_vlan_rx_add_vid;
+	dev->vlan_rx_kill_vid = velocity_vlan_rx_kill_vid;
+
 #ifdef  VELOCITY_ZERO_COPY_SUPPORT
 	dev->features |= NETIF_F_SG;
 #endif
+	dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER;
 
-	if (vptr->flags & VELOCITY_FLAGS_TX_CSUM) {
+	if (vptr->flags & VELOCITY_FLAGS_TX_CSUM)
 		dev->features |= NETIF_F_IP_CSUM;
-	}
 
 	ret = register_netdev(dev);
 	if (ret < 0)
@@ -1994,8 +2009,8 @@ static int velocity_xmit(struct sk_buff 
 		td_ptr->tdesc1.CMDZ = 2;
 	}
 
-	if (vptr->flags & VELOCITY_FLAGS_TAGGING) {
-		td_ptr->tdesc1.pqinf.VID = (vptr->options.vid & 0xfff);
+	if (vptr->vlgrp && vlan_tx_tag_present(skb)) {
+		td_ptr->tdesc1.pqinf.VID = vlan_tx_tag_get(skb);
 		td_ptr->tdesc1.pqinf.priority = 0;
 		td_ptr->tdesc1.pqinf.CFI = 0;
 		td_ptr->tdesc1.TCR |= TCR0_VETAG;
--- a/drivers/net/via-velocity.h	2007-07-10 09:40:38.000000000 -0700
+++ b/drivers/net/via-velocity.h	2007-08-24 13:49:17.000000000 -0700
@@ -1701,7 +1701,7 @@ struct velocity_opt {
 	int numrx;			/* Number of RX descriptors */
 	int numtx;			/* Number of TX descriptors */
 	enum speed_opt spd_dpx;		/* Media link mode */
-	int vid;			/* vlan id */
+
 	int DMA_length;			/* DMA length */
 	int rx_thresh;			/* RX_THRESH */
 	int flow_cntl;
@@ -1727,6 +1727,7 @@ struct velocity_info {
 	dma_addr_t tx_bufs_dma;
 	u8 *tx_bufs;
 
+	struct vlan_group    *vlgrp;
 	u8 ip_addr[4];
 	enum chip_type chip_id;
 

^ permalink raw reply

* Re: RFC: issues concerning the next NAPI interface
From: Jan-Bernd Themann @ 2007-08-24 21:11 UTC (permalink / raw)
  To: Linas Vepstas
  Cc: Bodo Eggert, netdev, Thomas Klein, Jan-Bernd Themann,
	linux-kernel, linux-ppc, Christoph Raisch, Marcus Eder,
	Stefan Roscher
In-Reply-To: <20070824204243.GI4282@austin.ibm.com>

Linas Vepstas schrieb:
> On Fri, Aug 24, 2007 at 09:04:56PM +0200, Bodo Eggert wrote:
>   
>> Linas Vepstas <linas@austin.ibm.com> wrote:
>>     
>>> On Fri, Aug 24, 2007 at 03:59:16PM +0200, Jan-Bernd Themann wrote:
>>>       
>>>> 3) On modern systems the incoming packets are processed very fast. Especially
>>>> on SMP systems when we use multiple queues we process only a few packets
>>>> per napi poll cycle. So NAPI does not work very well here and the interrupt
>>>> rate is still high.
>>>>         
>>> worst-case network ping-pong app: send one
>>> packet, wait for reply, send one packet, etc.
>>>       
>> Possible solution / possible brainfart:
>>
>> Introduce a timer, but don't start to use it to combine packets unless you
>> receive n packets within the timeframe. If you receive less than m packets
>> within one timeframe, stop using the timer. The system should now have a
>> decent response time when the network is idle, and when the network is
>> busy, nobody will complain about the latency.-)
>>     
>
> Ohh, that was inspirational. Let me free-associate some wild ideas.
>
> Suppose we keep a running average of the recent packet arrival rate,
> Lets say its 10 per millisecond ("typical" for a gigabit eth runnning
> flat-out).  If we could poll the driver at a rate of 10-20 per
> millisecond (i.e. letting the OS do other useful work for 0.05 millisec),
> then we could potentially service the card without ever having to enable 
> interrupts on the card, and without hurting latency.
>
> If the packet arrival rate becomes slow enough, we go back to an
> interrupt-driven scheme (to keep latency down).
>
> The main problem here is that, even for HZ=1000 machines, this amounts 
> to 10-20 polls per jiffy.  Which, if implemented in kernel, requires 
> using the high-resolution timers. And, umm, don't the HR timers require
> a cpu timer interrupt to make them go? So its not clear that this is much
> of a win.
>   
That is indeed a good question. At least for 10G eHEA we see
that the average number of packets/poll cycle is very low.
With high precision timers we could control the poll interval
better and thus make sure we get enough packets on the queue in
high load situations to benefit from LRO while keeping the
latency moderate. When the traffic load is low we could just
stick to plain NAPI. I don't know how expensive hp timers are,
we probably just have to test it (when they are available for
POWER in our case). However, having more packets
per poll run would make LRO more efficient and thus the total
CPU utilization would decrease.

I guess on most systems there are not many different network
cards working in parallel. So if the driver could set the poll
interval for its devices, it could be well optimized depending
on the NICs characteristics.

Maybe it would be good enough to have a timer that schedules
the device for NAPI (and thus triggers SoftIRQs, which will
trigger NAPI). Whether this timer would be used via a generic
interface or would be implemented as a proprietary solution
would depend on whether other drivers want / need this feature
as well. Drivers / NICs that work fine with plain NAPI don't
have to use timer :-)

I tried to implement something with "normal" timers, but the result
was everything but great. The timers seem to be far too slow.
I'm not sure if it helps to increase it from 1000HZ to 2500HZ
or more.

Regards,
Jan-Bernd


^ permalink raw reply

* Re: [PATCH] via-velocity: use standard VLAN interface (resend)
From: Al Viro @ 2007-08-24 21:15 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: Francois Romieu, netdev
In-Reply-To: <20070824135649.509e1fe7@freepuppy.rosehill.hemminger.net>

On Fri, Aug 24, 2007 at 01:56:49PM -0700, Stephen Hemminger wrote:

>  static void velocity_init_cam_filter(struct velocity_info *vptr)
>  {
>  	struct mac_regs __iomem * regs = vptr->mac_regs;
> +	unsigned short vid;
  
> -		mac_set_cam(regs, 0, (u8 *) & (vptr->options.vid), VELOCITY_VLAN_ID_CAM);
> +				mac_set_cam(regs, 0, (u8 *) &vid,
> +					    VELOCITY_VLAN_ID_CAM);

This mac_set_cam() dreck should be split in two properly typed functions.

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox