Initial import

This commit is contained in:
Martin Casado committed 2008-03-04 13:12:53 -08:00
1 parent 219b913228
commit 468e00132f
190 files changed
+25756

No files matched your search

+367
View File
@@ -0,0 +1,367 @@
All source files are Copyright (C) 2007 Board of Trustees, Leland
Stanford Jr. University and covered by the following licence.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Files in the datapath/ and its sub-directories are covered under the GNU
General Public License Version 2. Included below:
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.
+55
View File
@@ -0,0 +1,55 @@
v0.1.8 - 03 Mar 2008
--------------------
- Added support for cross-compilation.
- Various bug fixes and tweaks
v0.1.7 - 07 Feb 2008
--------------------
- Allow permanent flow entries to be set
- Added patch for tcpdump that allows parsing of OpenFlow messages
- Various bug fixes and tweaks
v0.1.6 - 05 Feb 2008
--------------------
- Added support for Linux 2.6.24
- Set nwsrc/nwdst fields in flow structs on ARP packets
- Various bug fixes and tweaks
v0.1.5 - 17 Jan 2008
--------------------
- Added support for Linux 2.4.20
- Added support for GCC 2.95
v0.1.4 - 15 Jan 2008
--------------------
- Decode and print port_status messages
- Fixed build problems on big-endian systems
- Fixed compatibility for older 2.6 kernels
- Various bug fixes and tweaks
v0.1.3 - 08 Jan 2008
--------------------
- Added support for flow expiration messages
- Decode and print all datapath-generated messages in dpctl's "monitor"
- Added "--noflow" option to controller
- Various bug fixes and tweaks
v0.1.2 - 07 Jan 2008
--------------------
- Fixed distribution to include ofp_pcap.h
- Removed autoconf C++ checks
v0.1.1 - 18 Dec 2007
--------------------
- Fixed support for Linux 2.4.35 and 2.6.22
- Added support for Linux 2.6.15
- Added "vlogconf" utility to modify logging configuration
- Added better support for SNAP headers
- Improved printing of flow information in dpctl
- Made kernel code consistently use tabs instead of spaces
- Removed libpcap requirement for building
- Various bug fixes and tweaks
v0.1.0 - 30 Nov 2007
--------------------
- Initial release
+156
View File
@@ -0,0 +1,156 @@
Installation Instructions for OpenFlow Reference Release v0.1.5
This document describes how to build, install, and execute the v0.1.5
reference implementation of OpenFlow. Please send any comments to:
<info@openflowswitch.org>
Setting up the Kernel Build Environment
---------------------------------------
The datapath kernel module must be compiled against a kernel build
directory for the Linux version the module is to run on. The datapath
module has been mainly tested on Linux 2.6.23. Support for Linux 2.4
is also in place, although it has only been lightly tested under 2.4.35.
For example, if compiling on Debian or Ubuntu, the Linux headers
and image packages must be installed (apt-get install
linux-headers-<version> linux-image-<version>).
Note: the OpenFlow datapath requires that bridging support has been
configured in the kernel, but not enabled or in use. If the bridge
module is running (check with "lsmod | grep bridge"), you must remove
it ("rmmod bridge") before starting the datapath.
Building the Code
-----------------
1. In the top source directory, configure the package, passing the
location of the kernel build directory as an argument. Use
--with-l26 for Linux 2.6, --with-l24 for Linux 2.4:
For example, if compiling for a running instance of Linux 2.6:
% ./configure --with-l26=/lib/modules/`uname -r`/build
Or if compiling for a running instance of Linux 2.4:
% ./configure --with-l24=/lib/modules/`uname -r`/build
To use a specific C compiler for compiling OpenFlow user programs,
also specify it on the configure command line, like so:
% ./configure CC=gcc-4.2
2. Run make in the top source directory:
% make
The following binaries will be built:
Datapath kernel module:
./datapath/linux-2.6/openflow_mod.ko (If compiling for Linux 2.6)
./datapath/linux-2.4/openflow_mod.o (If compiling for Linux 2.4)
Secure channel executable:
./secchan/secchan
Controller executable:
./controller/controller
Datapath administration utility:
./utilities/dpctl
3. (Optional) Run "make install" to install the executables and
manpages into the running system, by default under /usr/local.
Installing the datapath
-----------------------
To run the module, simply insmod it:
(Linux 2.6)
% insmod datapath/linux-2.6/openflow_mod.ko
(Linux 2.4)
% insmod datapath/linux-2.4/compat24_mod.o
% insmod datapath/linux-2.4/openflow_mod.o
Testing the datapath
--------------------
Once the OpenFlow datapath has been installed (you can verify that it is
running if it appears in lsmod's listing), you can configure it using
the dpctl command line utility.
1. Create a datapath instance. The command below creates a datapath with
ID 0 (see dpctl(8) for more detailed usage information).
% dpctl adddp 0
(note, while in principle openflow_mod supports multiple datapaths
within the same host, this is rarely useful in practice)
2. Use dpctl to attach the datapath to physical interfaces on the
machine. Say, for example, you want to create a trivial 2-port
switch using interfaces eth1 and eth2, you would issue the following
commands:
% dpctl addif 0 eth1
% dpctl addif 0 eth2
You can verify that the interfaces were successfully added by asking
dpctl to print the current status of datapath 0:
% dpctl show 0
3. (Optional) You can manually add flows to the datapath to test using
dpctl add-flows and view them using dpctl dump-flows. See dpctl(8)
for more details.
4. The simplest way to test the datapath is to run the provided sample
controller on the host machine to manage the datapath directly using
netlink.
% controller -v nl:0
Once the controller is running, the datapath should operate like a
learning Ethernet switch. You may monitor the flows in the datapath
flow table using "dpctl dump-flows" command.
Running the datapath with a remote controller
---------------------------------------------
1. Start the datapath and attach it to two or more physical ports as
described in the previous section.
Note: The current version of the secure channel and controller
require at least one interface not be connected to the datapath
to be functional. This interface will be used for communication
between the secure channel and the controller. Future releases will
support in-band control communication.
2. Run the controller in passive tcp mode on the host which will act as
the controller. In the example below, the controller will bind to
port 975 (the default) awaiting connections from secure channels.
% controller -v ptcp:
(See controller(8) for more details)
Make sure the machine hosting the controller is reachable by the switch.
3. Run secchan on the datapath host to start the secure channel
connecting the datapath to a remote controller. (See secchan(8)
for usage details). The channel should be configured to connect to
the controller's IP address on the port configured in step 2.
If the controller is running on host 192.168.1.2 port 975 (the
default port) and the datapath ID is 0, the secchan invocation
would look like:
% secchan -v nl:0 tcp:192.168.1.2
Bug Reporting
-------------
Please report problems to:
info@openflowswitch.org
+17
View File
@@ -0,0 +1,17 @@
# -*- makefile -*-
if HAVE_NETLINK
AM_CPPFLAGS = -DHAVE_NETLINK=1
endif
COMMON_FLAGS = -DVERSION=\"$(VERSION)\"
if NDEBUG
COMMON_FLAGS += -DNDEBUG -fomit-frame-pointer
endif
AM_CFLAGS = $(COMMON_FLAGS)
AM_CFLAGS += -Wstrict-prototypes -I $(top_srcdir)/include
if !NDEBUG
AM_LDFLAGS = -export-dynamic
endif
+2
View File
@@ -0,0 +1,2 @@
AUTOMAKE_OPTIONS=foreign
SUBDIRS = lib datapath secchan controller utilities man include third-party
+199
View File
@@ -0,0 +1,199 @@
OpenFlow Reference Release v0.1.5 <http://openflowswitch.org>
What is OpenFlow?
-----------------
OpenFlow is a flow-based switch specification designed to enable
researchers to run experiments in live networks. OpenFlow is based on a
simple Ethernet flow switch that exposes a standardized interface for
adding and removing flow entries.
An OpenFlow Switch consists of three parts: (1) A Flow Table in which
each flow entry is associated with an action telling the switch how to
process the flow, (2) A Secure Channel connecting the switch to a remote
process (a controller), allowing commands and packets to be sent between
the controller and the switch, and (3) An OpenFlow Protocol
implementation, providing an open and standard way for a controller to
talk to the switch.
An OpenFlow Switch can thus serve as a simple datapath element that
forwards packets between ports according to flow actions defined by
the controller using OpenFlow commands. Example actions are:
- Forward this flow's packets to the given port(s)
- Drop this flow's packets
- Encapsulate and forward this flow's packets to the controller.
The OpenFlow Switch is defined in detail in the OpenFlow Switch
Specification [2].
What's here?
------------
This software is a reference implementation of an OpenFlow Switch kernel
module for the Linux operating system, a secure channel implementation,
and an example controller that performs switching with MAC learning.
The rest of this file contains the following sections:
- Description of the directory hierarchy
- Platform support
- Quickstart build and install instructions
- Shortcomings
- References
Directory Hierarchy
-------------------
Source:
datapath/ Linux kernel module implementing an OpenFlow Flow Table
that incoming packets are checked against. The
kernel module uses netlink (a socket protocol for
user-kernel communication, described in RFC 3549) to
pass OpenFlow messages with the secure channel to be
relayed to the controller.
secchan/ A Secure Channel that connects to a kernel datapath
via netlink and a remote controller via TCP,
relaying OpenFlow packets received on one end to the
other. (The current implementation does not
support SSL, but this will be added in future releases.)
controller/ A simple controller that connects to a datapath via
a Secure Channel, commanding the datapath to act as
a regular MAC learning switch.
utilities/ Contains the sorce for "dpctl", a command-line utility
for controlling the OpenFlow datapath kernel module.
With it, you can add physical ports to the datapath,
add flows, monitor received packets, and query the
datapath state.
include/ Header files common to the datapath, secure channel,
and controller components.
lib/ Implementation files common to the datapath, secure
channel, and controller components.
third-party/ Contains third-party software that may be useful for
debugging. Currently, it only contains a patch to
allow tcpdump to parse OpenFlow messages.
Documentation:
README Text file describing this OpenFlow implementation,
aka this document.
INSTALLATION Detailed configure, build, and installation
instructions
man/ Man pages describing how to administer datapath,
secure channel, and controller.
Platform support
----------------
The datapath kernel module supports Linux 2.6.15 and above, however,
testing has focused on Linux 2.6.23. Support for Linux 2.4.20 and
above is also in place, although testing has focused on Linux 2.6.
Components have been built and tested on Debian and Ubuntu.
If you are able to build/run the code on platforms not mentioned
here, or have problems with supported system, please report your
experiences to:
<info@openflowswitch.org>
GCC is required for compilation.
Building and Installing (Quick Start)
-------------------------------------
Building the datapath module requires that the source for the
currently running Linux kernel be installed on the machine and
been configured.
The following instructions assume the Linux 2.6 source is located in
/usr/src/linux-2.6.23 and Linux 2.4 in /usr/src/linux-2.4.35
1. ./configure the package, passing the location of one or more
kernel source trees on the command line:
For example, if compiling for Linux 2.6:
% ./configure --with-l26=/usr/src/linux-2.6.23
Or compiling for Linux 2.4:
% ./configure --with-l24=/usr/src/linux-2.4.35
2. Run make:
% make
The following binaries should be built.
Datapath kernel module:
./datapath/linux-2.6/openflow_mod.ko (If compiling for Linux 2.6)
./datapath/linux-2.4/openflow_mod.o (If compiling for Linux 2.4)
Secure channel executable:
./secchan/secchan
Controller executable:
./controller/controller
dpctl utility:
./utility/dpctl
3. Optionally you can "make install" to install binaries and the
man pages (/usr/local/ is the default prefix). If you just want
access to the man pages without installing, set your MANPATH to
include the openflow/ source root.
4. Insert the datapath kernel module into the running Linux instance.
(Linux 2.6)
% insmod datapath/linux-2.6/openflow_mod.ko
(Linux 2.4)
% insmod datapath/linux-2.4/openflow_mod.o
5. Create datapaths by running dpctl on the Linux host (see man
dpctl(8)). Start the controller on a remote host with
controller (see man controller(8)). Start the Secure Channel
on the datapath host to connect the datapath to the controller
with secchan(see man secchan(8)).
For more detailed installation instructions, refer to [3].
Bugs/Shortcomings
-----------------
- The current flowtable does not support all statistics messages
mentioned in the Type 0 OpenFlow spec
- The secure channel and sample controller don't support SSL
- The flowtable does not support the "normal processing" action
- Configure/build system does not support separate build directory for
the datapath. ./configure must be run from the source root.
- dpctl dump-flows may freeze when large numbers of flows are in the
flow table. This has no affect on the datapath
References
----------
[1] OpenFlow: Enabling Innovation in College Networks. Whitepaper.
<http://openflowswitch.org/alpha/openflow-wp-v0.1.pdf>
[2] OpenFlow Switch Specification.
<http://openflowswitch.org/alpha/openflow-spec-v0.2.pdf>
[3] Installation Instructions: INSTALL
Contact
-------
e-mail: info@openflowswitch.org
www: http://openflowswitch.org/alpha/
+42
View File
@@ -0,0 +1,42 @@
dnl =================================================================================
dnl Distributed under the terms of the GNU GPL version 2.
dnl Copyright (c) 2007 The Board of Trustees of The Leland Stanford Junior University
dnl =================================================================================
dnl --
dnl CHECK_LINUX(OPTION, VERSION, VARIABLE, CONDITIONAL)
dnl
dnl Configure linux kernel source tree
dnl --
AC_DEFUN([CHECK_LINUX], [
AC_ARG_WITH([$1],
[AC_HELP_STRING([--with-$1=/path/to/linux-$3],
[Specify the linux $3 kernel sources])],
[path="$withval"], [path=])dnl
if test -n "$path"; then
path=`eval echo "$path"`
AC_MSG_CHECKING([for $path directory])
if test -d "$path"; then
AC_MSG_RESULT([yes])
$4=$path
AC_SUBST($4)
else
AC_MSG_RESULT([no])
AC_ERROR([source dir $path doesn't exist])
fi
AC_MSG_CHECKING([for $path kernel version])
version=`grep '^PATCHLEVEL = ' "$path/Makefile" | sed 's/PATCHLEVEL = '//`
AC_MSG_RESULT([2.$version])
if test "2.$version" != '$3'; then
AC_ERROR([Linux kernel source in $path is not version $3])
fi
if ! test -e "$path"/include/linux/version.h || \
! test -e "$path"/include/linux/autoconf.h; then
AC_MSG_ERROR([Linux kernel source in $path is not configured])
fi
fi
AM_CONDITIONAL($5, test -n "$path")
])
+55
View File
@@ -0,0 +1,55 @@
AC_PREREQ(2.59)
AC_INIT(openflow, v0.1.8, info@openflowswitch.org)
AM_INIT_AUTOMAKE
AC_PROG_CC
AC_PROG_CPP
AC_USE_SYSTEM_EXTENSIONS
AC_PROG_LIBTOOL
AC_ARG_ENABLE(
[ndebug],
[AC_HELP_STRING([--enable-ndebug],
[Disable debugging features for max performance])],
[case "${enableval}" in # (
yes) ndebug=true ;; # (
no) ndebug=false ;; # (
*) AC_MSG_ERROR([bad value ${enableval} for --enable-ndebug]) ;;
esac],
[ndebug=false])
AM_CONDITIONAL([NDEBUG], [test x$ndebug = xtrue])
CHECK_LINUX(l26, 2.6, 2.6, KSRC26, L26_ENABLED)
CHECK_LINUX(uml, 2.6, 2.6-uml, KSRCUML, UML_ENABLED)
CHECK_LINUX(l24, 2.4, 2.4, KSRC24, L24_ENABLED)
AC_CHECK_HEADER([linux/netlink.h],
[HAVE_NETLINK=yes],
[HAVE_NETLINK=no],
[#include <sys/socket.h>])
AM_CONDITIONAL([HAVE_NETLINK], [test "$HAVE_NETLINK" = yes])
AC_CHECK_LIB([socket], [connect])
AC_CHECK_LIB([resolv], [gethostbyname])
AC_CHECK_LIB([dl], [dladdr])
CFLAGS="$CFLAGS -Wall -Wno-sign-compare"
AC_CONFIG_FILES([Makefile
man/Makefile
man/man8/Makefile
datapath/Makefile
lib/Makefile
include/Makefile
controller/Makefile
utilities/Makefile
secchan/Makefile
datapath/tests/Makefile
third-party/Makefile
datapath/linux-2.6/Makefile
datapath/linux-2.6-uml/Makefile
datapath/linux-2.4/Makefile])
AC_OUTPUT
+3
View File
@@ -0,0 +1,3 @@
/Makefile
/Makefile.in
/controller
+6
View File
@@ -0,0 +1,6 @@
include ../Make.vars
bin_PROGRAMS = controller
controller_SOURCES = controller.c
controller_LDADD = ../lib/libopenflow.la
+687
View File
@@ -0,0 +1,687 @@
/* Copyright (C) 2007 Board of Trustees, Leland Stanford Jr. University.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <assert.h>
#include <errno.h>
#include <getopt.h>
#include <inttypes.h>
#include <netinet/in.h>
#include <poll.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "buffer.h"
#include "command-line.h"
#include "compiler.h"
#include "fault.h"
#include "flow.h"
#include "hash.h"
#include "list.h"
#include "mac.h"
#include "ofp-print.h"
#include "openflow.h"
#include "time.h"
#include "util.h"
#include "vconn.h"
#include "vlog-socket.h"
#include "xtoxll.h"
#include "vlog.h"
#define THIS_MODULE VLM_controller
#define MAX_SWITCHES 16
#define MAX_TXQ 128
struct switch_ {
char *name;
struct vconn *vconn;
struct pollfd *pollfd;
uint64_t datapath_id;
time_t last_control_hello;
int n_txq;
struct buffer *txq, *tx_tail;
};
/* -H, --hub: Use dumb hub instead of learning switch? */
static bool hub = false;
/* -n, --noflow: Pass traffic, but don't setup flows in switch */
static bool noflow = false;
static void parse_options(int argc, char *argv[]);
static void usage(void) NO_RETURN;
static struct switch_ *connect_switch(const char *name);
static struct switch_ *new_switch(const char *name, struct vconn *);
static void close_switch(struct switch_ *);
static void queue_tx(struct switch_ *, struct buffer *);
static void send_control_hello(struct switch_ *);
static int do_switch_recv(struct switch_ *this);
static int do_switch_send(struct switch_ *this);
static void process_packet(struct switch_ *, struct buffer *);
static void process_hub(struct switch_ *, struct ofp_packet_in *);
static void process_noflow(struct switch_ *, struct ofp_packet_in *);
static void switch_init(void);
static void process_switch(struct switch_ *, struct ofp_packet_in *);
int
main(int argc, char *argv[])
{
struct switch_ *switches[MAX_SWITCHES];
struct pollfd pollfds[MAX_SWITCHES + 1];
struct vlog_server *vlog_server;
int n_switches;
int retval;
int i;
set_program_name(argv[0]);
register_fault_handlers();
vlog_init();
parse_options(argc, argv);
if (!hub && !noflow) {
switch_init();
}
if (argc - optind < 1) {
fatal(0, "at least one vconn argument required; use --help for usage");
}
retval = vlog_server_listen(NULL, &vlog_server);
if (retval) {
fatal(retval, "Could not listen for vlog connections");
}
n_switches = 0;
for (i = 0; i < argc - optind; i++) {
struct switch_ *this = connect_switch(argv[optind + i]);
if (this) {
if (n_switches >= MAX_SWITCHES) {
fatal(0, "max %d switch connections", n_switches);
}
switches[n_switches++] = this;
}
}
if (n_switches == 0) {
fatal(0, "could not connect to any switches");
}
while (n_switches > 0) {
int retval;
/* Wait until there's something to do. */
for (i = 0; i < n_switches; i++) {
struct switch_ *this = switches[i];
int want;
if (vconn_is_passive(this->vconn)) {
want = n_switches < MAX_SWITCHES ? WANT_ACCEPT : 0;
} else {
want = WANT_RECV;
if (this->n_txq) {
want |= WANT_SEND;
}
}
this->pollfd = &pollfds[i];
this->pollfd->fd = -1;
this->pollfd->events = 0;
vconn_prepoll(this->vconn, want, this->pollfd);
}
if (vlog_server) {
pollfds[n_switches].fd = vlog_server_get_fd(vlog_server);
pollfds[n_switches].events = POLLIN;
}
do {
retval = poll(pollfds, n_switches + (vlog_server != NULL), -1);
} while (retval < 0 && errno == EINTR);
if (retval <= 0) {
fatal(retval < 0 ? errno : 0, "poll");
}
/* Let each connection deal with any pending operations. */
for (i = 0; i < n_switches; i++) {
struct switch_ *this = switches[i];
vconn_postpoll(this->vconn, &this->pollfd->revents);
if (this->pollfd->revents & POLLERR) {
this->pollfd->revents |= POLLIN | POLLOUT;
}
}
if (vlog_server && pollfds[n_switches].revents) {
vlog_server_poll(vlog_server);
}
for (i = 0; i < n_switches; ) {
struct switch_ *this = switches[i];
if (this->pollfd) {
retval = 0;
if (vconn_is_passive(this->vconn)) {
if (this->pollfd->revents & POLLIN) {
struct vconn *new_vconn;
while (n_switches < MAX_SWITCHES
&& (retval = vconn_accept(this->vconn,
&new_vconn)) == 0) {
switches[n_switches++] = new_switch("tcp",
new_vconn);
}
}
} else {
bool may_read = this->pollfd->revents & POLLIN;
bool may_write = this->pollfd->revents & POLLOUT;
if (may_read) {
retval = do_switch_recv(this);
if (!retval || retval == EAGAIN) {
retval = 0;
/* Enable writing to avoid round trip through poll
* in common case. */
may_write = true;
}
}
while ((!retval || retval == EAGAIN) && may_write) {
retval = do_switch_send(this);
may_write = !retval;
}
}
if (retval && retval != EAGAIN) {
close_switch(this);
switches[i] = switches[--n_switches];
continue;
}
} else {
/* New switch that hasn't been polled yet. */
}
i++;
}
}
return 0;
}
static int
do_switch_recv(struct switch_ *this)
{
struct buffer *msg;
int retval;
retval = vconn_recv(this->vconn, &msg);
if (!retval) {
process_packet(this, msg);
buffer_delete(msg);
}
return retval;
}
static int
do_switch_send(struct switch_ *this)
{
int retval = 0;
if (this->n_txq) {
struct buffer *next = this->txq->next;
retval = vconn_send(this->vconn, this->txq);
if (retval) {
return retval;
}
this->txq = next;
if (this->txq == NULL) {
this->tx_tail = NULL;
}
this->n_txq--;
return 0;
}
return EAGAIN;
}
struct switch_ *
connect_switch(const char *name)
{
struct vconn *vconn;
int retval;
retval = vconn_open(name, &vconn);
if (retval) {
VLOG_ERR("%s: connect: %s", name, strerror(retval));
return NULL;
}
return new_switch(name, vconn);
}
static struct switch_ *
new_switch(const char *name, struct vconn *vconn)
{
struct switch_ *this = xmalloc(sizeof *this);
memset(this, 0, sizeof *this);
this->name = xstrdup(name);
this->vconn = vconn;
this->pollfd = NULL;
this->n_txq = 0;
this->txq = NULL;
this->tx_tail = NULL;
this->last_control_hello = 0;
if (!vconn_is_passive(vconn)) {
send_control_hello(this);
}
return this;
}
static void
close_switch(struct switch_ *this)
{
if (this) {
struct buffer *cur, *next;
free(this->name);
vconn_close(this->vconn);
for (cur = this->txq; cur != NULL; cur = next) {
next = cur->next;
buffer_delete(cur);
}
free(this);
}
}
static void
send_control_hello(struct switch_ *this)
{
time_t now = time(0);
if (now >= this->last_control_hello + 1) {
struct buffer *b;
struct ofp_control_hello *och;
b = buffer_new(0);
och = buffer_put_uninit(b, sizeof *och);
memset(och, 0, sizeof *och);
och->header.version = OFP_VERSION;
och->header.length = htons(sizeof *och);
och->version = htonl(OFP_VERSION);
och->flags = htons(OFP_CHELLO_SEND_FLOW_EXP);
och->miss_send_len = htons(OFP_DEFAULT_MISS_SEND_LEN);
queue_tx(this, b);
this->last_control_hello = now;
}
}
static void
check_txq(struct switch_ *this UNUSED)
{
#if 0
struct buffer *iter;
size_t n;
assert(this->n_txq == 0
? this->txq == NULL && this->tx_tail == NULL
: this->txq != NULL && this->tx_tail != NULL);
n = 0;
for (iter = this->txq; iter != NULL; iter = iter->next) {
n++;
assert((iter->next != NULL) == (iter != this->tx_tail));
}
assert(n == this->n_txq);
#endif
}
static void
queue_tx(struct switch_ *this, struct buffer *b)
{
check_txq(this);
b->next = NULL;
if (this->n_txq++) {
this->tx_tail->next = b;
} else {
this->txq = b;
}
this->tx_tail = b;
check_txq(this);
}
static void
process_packet(struct switch_ *sw, struct buffer *msg)
{
static const size_t min_size[UINT8_MAX + 1] = {
[0 ... UINT8_MAX] = SIZE_MAX,
[OFPT_CONTROL_HELLO] = sizeof (struct ofp_control_hello),
[OFPT_DATA_HELLO] = sizeof (struct ofp_data_hello),
[OFPT_PACKET_IN] = offsetof (struct ofp_packet_in, data),
[OFPT_PACKET_OUT] = sizeof (struct ofp_packet_out),
[OFPT_FLOW_MOD] = sizeof (struct ofp_flow_mod),
[OFPT_FLOW_EXPIRED] = sizeof (struct ofp_flow_expired),
[OFPT_TABLE] = sizeof (struct ofp_table),
[OFPT_PORT_MOD] = sizeof (struct ofp_port_mod),
[OFPT_PORT_STATUS] = sizeof (struct ofp_port_status),
[OFPT_FLOW_STAT_REQUEST] = sizeof (struct ofp_flow_stat_request),
[OFPT_FLOW_STAT_REPLY] = sizeof (struct ofp_flow_stat_reply),
};
struct ofp_header *oh;
oh = msg->data;
if (msg->size < min_size[oh->type]) {
VLOG_WARN("%s: too short (%zu bytes) for type %"PRIu8" (min %zu)",
sw->name, msg->size, oh->type, min_size[oh->type]);
return;
}
if (oh->type == OFPT_DATA_HELLO) {
struct ofp_data_hello *odh = msg->data;
sw->datapath_id = odh->datapath_id;
} else if (sw->datapath_id == 0) {
send_control_hello(sw);
return;
}
if (oh->type == OFPT_PACKET_IN) {
if (sw->n_txq >= MAX_TXQ) {
VLOG_WARN("%s: tx queue overflow", sw->name);
} else if (noflow) {
process_noflow(sw, msg->data);
} else if (hub) {
process_hub(sw, msg->data);
} else {
process_switch(sw, msg->data);
}
return;
}
ofp_print(stdout, msg->data, msg->size, 2);
}
static void
process_hub(struct switch_ *sw, struct ofp_packet_in *opi)
{
size_t pkt_ofs, pkt_len;
struct buffer pkt;
struct flow flow;
/* Extract flow data from 'opi' into 'flow'. */
pkt_ofs = offsetof(struct ofp_packet_in, data);
pkt_len = ntohs(opi->header.length) - pkt_ofs;
pkt.data = opi->data;
pkt.size = pkt_len;
flow_extract(&pkt, ntohs(opi->in_port), &flow);
/* Add new flow. */
queue_tx(sw, make_add_simple_flow(&flow, ntohl(opi->buffer_id),
OFPP_FLOOD));
/* If the switch didn't buffer the packet, we need to send a copy. */
if (ntohl(opi->buffer_id) == UINT32_MAX) {
queue_tx(sw, make_unbuffered_packet_out(&pkt, ntohs(flow.in_port),
OFPP_FLOOD));
}
}
static void
process_noflow(struct switch_ *sw, struct ofp_packet_in *opi)
{
/* If the switch didn't buffer the packet, we need to send a copy. */
if (ntohl(opi->buffer_id) == UINT32_MAX) {
size_t pkt_ofs, pkt_len;
struct buffer pkt;
/* Extract flow data from 'opi' into 'flow'. */
pkt_ofs = offsetof(struct ofp_packet_in, data);
pkt_len = ntohs(opi->header.length) - pkt_ofs;
pkt.data = opi->data;
pkt.size = pkt_len;
queue_tx(sw, make_unbuffered_packet_out(&pkt, ntohs(opi->in_port),
OFPP_FLOOD));
} else {
queue_tx(sw, make_buffered_packet_out(ntohl(opi->buffer_id),
ntohs(opi->in_port), OFPP_FLOOD));
}
}
#define MAC_HASH_BITS 10
#define MAC_HASH_MASK (MAC_HASH_SIZE - 1)
#define MAC_HASH_SIZE (1u << MAC_HASH_BITS)
#define MAC_MAX 1024
struct mac_source {
struct list hash_list;
struct list lru_list;
uint64_t datapath_id;
uint8_t mac[ETH_ADDR_LEN];
uint16_t port;
};
static struct list mac_table[MAC_HASH_SIZE];
static struct list lrus;
static size_t mac_count;
static void
switch_init(void)
{
int i;
list_init(&lrus);
for (i = 0; i < MAC_HASH_SIZE; i++) {
list_init(&mac_table[i]);
}
}
static struct list *
mac_table_bucket(uint64_t datapath_id, const uint8_t mac[ETH_ADDR_LEN])
{
uint32_t hash;
hash = hash_fnv(&datapath_id, sizeof datapath_id, HASH_FNV_BASIS);
hash = hash_fnv(mac, ETH_ADDR_LEN, hash);
return &mac_table[hash & MAC_HASH_BITS];
}
static void
process_switch(struct switch_ *sw, struct ofp_packet_in *opi)
{
size_t pkt_ofs, pkt_len;
struct buffer pkt;
struct flow flow;
uint16_t out_port;
/* Extract flow data from 'opi' into 'flow'. */
pkt_ofs = offsetof(struct ofp_packet_in, data);
pkt_len = ntohs(opi->header.length) - pkt_ofs;
pkt.data = opi->data;
pkt.size = pkt_len;
flow_extract(&pkt, ntohs(opi->in_port), &flow);
/* Learn the source. */
if (!mac_is_multicast(flow.dl_src)) {
struct mac_source *src;
struct list *bucket;
bool found;
bucket = mac_table_bucket(sw->datapath_id, flow.dl_src);
found = false;
LIST_FOR_EACH (src, struct mac_source, hash_list, bucket) {
if (src->datapath_id == sw->datapath_id
&& mac_equals(src->mac, flow.dl_src)) {
found = true;
break;
}
}
if (!found) {
/* Learn a new address. */
if (mac_count >= MAC_MAX) {
/* Drop the least recently used mac source. */
struct mac_source *lru;
lru = CONTAINER_OF(lrus.next, struct mac_source, lru_list);
list_remove(&lru->hash_list);
list_remove(&lru->lru_list);
free(lru);
} else {
mac_count++;
}
/* Create new mac source */
src = xmalloc(sizeof *src);
src->datapath_id = sw->datapath_id;
memcpy(src->mac, flow.dl_src, ETH_ADDR_LEN);
src->port = -1;
list_push_front(bucket, &src->hash_list);
list_push_back(&lrus, &src->lru_list);
} else {
/* Make 'src' most-recently-used. */
list_remove(&src->lru_list);
list_push_back(&lrus, &src->lru_list);
}
if (ntohs(flow.in_port) != src->port) {
src->port = ntohs(flow.in_port);
VLOG_DBG("learned that "MAC_FMT" is on datapath %"PRIx64" port %d",
MAC_ARGS(src->mac), ntohll(src->datapath_id),
src->port);
}
} else {
VLOG_DBG("multicast packet source "MAC_FMT, MAC_ARGS(flow.dl_src));
}
/* Figure out the destination. */
out_port = OFPP_FLOOD;
if (!mac_is_multicast(flow.dl_dst)) {
struct mac_source *dst;
struct list *bucket;
bucket = mac_table_bucket(sw->datapath_id, flow.dl_dst);
LIST_FOR_EACH (dst, struct mac_source, hash_list, bucket) {
if (dst->datapath_id == sw->datapath_id
&& mac_equals(dst->mac, flow.dl_dst)) {
out_port = dst->port;
break;
}
}
}
if (out_port != OFPP_FLOOD) {
/* The output port is known, so add a new flow. */
queue_tx(sw, make_add_simple_flow(&flow, ntohl(opi->buffer_id),
out_port));
/* If the switch didn't buffer the packet, we need to send a copy. */
if (ntohl(opi->buffer_id) == UINT32_MAX) {
queue_tx(sw, make_unbuffered_packet_out(&pkt, ntohs(flow.in_port),
out_port));
}
} else {
/* We don't know that MAC. Flood the packet. */
struct buffer *b;
if (ntohl(opi->buffer_id) == UINT32_MAX) {
b = make_unbuffered_packet_out(&pkt, ntohs(flow.in_port), out_port);
} else {
b = make_buffered_packet_out(ntohl(opi->buffer_id),
ntohs(flow.in_port), out_port);
}
queue_tx(sw, b);
}
}
static void
parse_options(int argc, char *argv[])
{
static struct option long_options[] = {
{"hub", no_argument, 0, 'H'},
{"noflow", no_argument, 0, 'n'},
{"verbose", optional_argument, 0, 'v'},
{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'V'},
{0, 0, 0, 0},
};
char *short_options = long_options_to_short_options(long_options);
for (;;) {
int indexptr;
int c;
c = getopt_long(argc, argv, short_options, long_options, &indexptr);
if (c == -1) {
break;
}
switch (c) {
case 'H':
hub = true;
break;
case 'n':
noflow = true;
break;
case 'h':
usage();
case 'V':
printf("%s "VERSION" compiled "__DATE__" "__TIME__"\n", argv[0]);
exit(EXIT_SUCCESS);
case 'v':
vlog_set_verbosity(optarg);
break;
case '?':
exit(EXIT_FAILURE);
default:
abort();
}
}
free(short_options);
}
static void
usage(void)
{
printf("%s: OpenFlow controller\n"
"usage: %s [OPTIONS] VCONN\n"
"where VCONN is one of the following:\n"
#ifdef HAVE_NETLINK
" nl:DP_IDX via netlink to local datapath DP_IDX\n"
#endif
" ptcp:[PORT] listen to TCP PORT (default: %d)\n"
"\nOther options:\n"
" -H, --hub act as hub instead of learning switch\n"
" -n, --noflow pass traffic, but don't add flows\n"
" -v, --verbose set maximum verbosity level\n"
" -h, --help display this help message\n"
" -V, --version display version information\n",
program_name, program_name, OFP_TCP_PORT);
exit(EXIT_SUCCESS);
}
+2
View File
@@ -0,0 +1,2 @@
/Makefile
/Makefile.in
+35
View File
@@ -0,0 +1,35 @@
SUBDIRS = tests
if L26_ENABLED
SUBDIRS += linux-2.6
endif
if UML_ENABLED
SUBDIRS += linux-2.6-uml
endif
if L24_ENABLED
SUBDIRS += linux-2.4
endif
EXTRA_DIST = linux-2.6 linux-2.4 linux-2.6-uml\
datapath.c snap.h chain.c crc32.c crc_t.c\
flow.h forward.h table-hash.c table-mac.c\
unit.c unit.h datapath.h chain.h crc32.h\
flow.c forward.c forward_t.c table.h\
table-linear.c table_t.c unit-exports.c\
datapath_t.c datapath_t.h compat.h\
dp_dev.c
# Do not include header and source files from the top of the linux-*
# directories, as these are just symbolic links to the files in
# "datapath".
dist-hook:
rm -rf `find $(distdir)/linux-* -name Module.symvers`
rm -rf `find $(distdir)/linux-* -name .*.cmd`
rm -rf `find $(distdir)/linux-* -name .*.swp`
rm -rf `find $(distdir)/linux-* -name .*.d`
rm -rf `find $(distdir)/linux-* -name .tmp_versions`
rm -rf `find $(distdir)/linux-* -name *.o`
rm -rf `find $(distdir)/linux-* -name *.ko`
rm -rf `find $(distdir)/linux-* -name Makefile`
rm -rf `find $(distdir)/linux-* -name .gitignore`
rm -f $(distdir)/linux-*/*.h
rm -f $(distdir)/linux-*/*.c
View File
Whitespace-only changes.
+161
View File
@@ -0,0 +1,161 @@
/*
* Distributed under the terms of the GNU GPL version 2.
* Copyright (c) 2007 The Board of Trustees of The Leland Stanford Junior University
*/
#include "chain.h"
#include "flow.h"
#include "table.h"
#include <linux/rcupdate.h>
#include <linux/slab.h>
/* Attempts to append 'table' to the set of tables in 'chain'. Returns 0 or
* negative error. If 'table' is null it is assumed that table creation failed
* due to out-of-memory. */
static int add_table(struct sw_chain *chain, struct sw_table *table)
{
if (table == NULL)
return -ENOMEM;
if (chain->n_tables >= CHAIN_MAX_TABLES) {
printk("too many tables in chain\n");
table->destroy(table);
return -ENOBUFS;
}
chain->tables[chain->n_tables++] = table;
return 0;
}
/* Creates and returns a new chain associated with 'dp'. Returns NULL if the
* chain cannot be created. */
struct sw_chain *chain_create(struct datapath *dp)
{
struct sw_chain *chain = kzalloc(sizeof *chain, GFP_KERNEL);
if (chain == NULL)
return NULL;
chain->dp = dp;
if (add_table(chain, table_mac_create(TABLE_MAC_NUM_BUCKETS,
TABLE_MAC_MAX_FLOWS))
|| add_table(chain, table_hash2_create(0x1EDC6F41, TABLE_HASH_MAX_FLOWS,
0x741B8CD7, TABLE_HASH_MAX_FLOWS))
|| add_table(chain, table_linear_create(TABLE_LINEAR_MAX_FLOWS))) {
chain_destroy(chain);
return NULL;
}
return chain;
}
/* Searches 'chain' for a flow matching 'key', which must not have any wildcard
* fields. Returns the flow if successful, otherwise a null pointer.
*
* Caller must hold rcu_read_lock, and not release it until it is done with the
* returned flow. */
struct sw_flow *chain_lookup(struct sw_chain *chain,
const struct sw_flow_key *key)
{
int i;
BUG_ON(key->wildcards);
for (i = 0; i < chain->n_tables; i++) {
struct sw_table *t = chain->tables[i];
struct sw_flow *flow = t->lookup(t, key);
if (flow)
return flow;
}
return NULL;
}
/* Inserts 'flow' into 'chain', replacing any duplicate flow. Returns 0 if
* successful or a negative error.
*
* If successful, 'flow' becomes owned by the chain, otherwise it is retained
* by the caller.
*
* Caller must hold rcu_read_lock. If insertion is successful, it must not
* release rcu_read_lock until it is done with the inserted flow. */
int chain_insert(struct sw_chain *chain, struct sw_flow *flow)
{
int i;
for (i = 0; i < chain->n_tables; i++) {
struct sw_table *t = chain->tables[i];
if (t->insert(t, flow))
return 0;
}
return -ENOBUFS;
}
/* Deletes from 'chain' any and all flows that match 'key'. Returns the number
* of flows that were deleted.
*
* Expensive in the general case as currently implemented, since it requires
* iterating through the entire contents of each table for keys that contain
* wildcards. Relatively cheap for fully specified keys.
*
* The caller need not hold any locks. */
int chain_delete(struct sw_chain *chain, const struct sw_flow_key *key, int strict)
{
int count = 0;
int i;
for (i = 0; i < chain->n_tables; i++) {
struct sw_table *t = chain->tables[i];
rcu_read_lock();
count += t->delete(t, key, strict);
rcu_read_unlock();
}
return count;
}
/* Performs timeout processing on all the tables in 'chain'. Returns the
* number of flow entries deleted through expiration.
*
* Expensive as currently implemented, since it iterates through the entire
* contents of each table.
*
* The caller need not hold any locks. */
int chain_timeout(struct sw_chain *chain)
{
int count = 0;
int i;
for (i = 0; i < chain->n_tables; i++) {
struct sw_table *t = chain->tables[i];
rcu_read_lock();
count += t->timeout(chain->dp, t);
rcu_read_unlock();
}
return count;
}
/* Destroys 'chain', which must not have any users. */
void chain_destroy(struct sw_chain *chain)
{
int i;
synchronize_rcu();
for (i = 0; i < chain->n_tables; i++) {
struct sw_table *t = chain->tables[i];
t->destroy(t);
}
kfree(chain);
}
/* Prints statistics for each of the tables in 'chain'. */
void chain_print_stats(struct sw_chain *chain)
{
int i;
printk("\n");
for (i = 0; i < chain->n_tables; i++) {
struct sw_table *t = chain->tables[i];
struct sw_table_stats stats;
t->stats(t, &stats);
printk("%s: %lu/%lu flows\n",
stats.name, stats.n_flows, stats.max_flows);
}
}
+31
View File
@@ -0,0 +1,31 @@
#ifndef CHAIN_H
#define CHAIN_H 1
struct sw_flow;
struct sw_flow_key;
struct datapath;
#define TABLE_LINEAR_MAX_FLOWS 100
#define TABLE_HASH_MAX_FLOWS 65536
#define TABLE_MAC_MAX_FLOWS 1024
#define TABLE_MAC_NUM_BUCKETS 1024
/* Set of tables chained together in sequence from cheap to expensive. */
#define CHAIN_MAX_TABLES 4
struct sw_chain {
int n_tables;
struct sw_table *tables[CHAIN_MAX_TABLES];
struct datapath *dp;
};
struct sw_chain *chain_create(struct datapath *);
struct sw_flow *chain_lookup(struct sw_chain *, const struct sw_flow_key *);
int chain_insert(struct sw_chain *, struct sw_flow *);
int chain_delete(struct sw_chain *, const struct sw_flow_key *, int);
int chain_timeout(struct sw_chain *);
void chain_destroy(struct sw_chain *);
void chain_print_stats(struct sw_chain *);
#endif /* chain.h */
+17
View File
@@ -0,0 +1,17 @@
#ifndef COMPAT_H
#define COMPAT_H 1
#include <linux/version.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
#include "compat26.h"
#else
#include "compat24.h"
#endif
#endif /* compat.h */
+40
View File
@@ -0,0 +1,40 @@
/*
* Distributed under the terms of the GNU GPL version 2.
* Copyright (c) 2007 The Board of Trustees of The Leland Stanford Junior Univer
sity
*/
#include "crc32.h"
void crc32_init(struct crc32 *crc, unsigned int polynomial)
{
int i;
for (i = 0; i < CRC32_TABLE_SIZE; ++i) {
unsigned int reg = i << 24;
int j;
for (j = 0; j < CRC32_TABLE_BITS; j++) {
int topBit = (reg & 0x80000000) != 0;
reg <<= 1;
if (topBit)
reg ^= polynomial;
}
crc->table[i] = reg;
}
}
unsigned int crc32_calculate(const struct crc32 *crc,
const void *data_, size_t n_bytes)
{
// FIXME: this can be optimized by unrolling, see linux-2.6/lib/crc32.c.
const uint8_t *data = data_;
unsigned int result = 0;
size_t i;
for (i = 0; i < n_bytes; i++) {
unsigned int top = result >> 24;
top ^= data[i];
result = (result << 8) ^ crc->table[top];
}
return result;
}
+22
View File
@@ -0,0 +1,22 @@
#ifndef CRC32_H
#define CRC32_H 1
#include <linux/types.h>
#ifndef __KERNEL__
#include <stdint.h>
#endif
#include <stddef.h>
#define CRC32_TABLE_BITS 8
#define CRC32_TABLE_SIZE (1u << CRC32_TABLE_BITS)
struct crc32 {
unsigned int table[CRC32_TABLE_SIZE];
};
void crc32_init(struct crc32 *, unsigned int polynomial);
unsigned int crc32_calculate(const struct crc32 *,
const void *data_, size_t n_bytes);
#endif /* crc32.h */
+47
View File
@@ -0,0 +1,47 @@
/*
* Distributed under the terms of the GNU GPL version 2.
* Copyright (c) 2007 The Board of Trustees of The Leland Stanford Junior Univer
sity
*/
#include <linux/string.h>
#include <linux/kernel.h>
#include "crc32.h"
#include "unit.h"
static void
print_error(unsigned int poly, char *data,
unsigned int expected, unsigned int calculated)
{
unit_fail("crc error: poly=%x data=%s expected=%x calculated=%x\n",
poly, data, expected, calculated);
}
void
run_crc_t(void)
{
struct crc32 crc;
unsigned int val, i, j;
char *data[3] = { "h3rei$@neX@mp13da7@sTr117G0fCH@r$",
"1324lkqasdf0-[LKJD0;asd,.cv;/asd0:\"'~`co29",
"6" };
unsigned int polys[2] = { 0x04C11DB7,
0x1EDC6F41 };
unsigned int crc_values[2][3] = {
{ 0xDE1040C3, 0x65343A0B, 0xCEB42022 },
{ 0x6C149FAE, 0x470A6B73, 0x4D3AA134 } };
for (i = 0; i < 2; i++) {
crc32_init(&crc, polys[i]);
for (j = 0; j < 3; j++) {
val = crc32_calculate(&crc, data[j], strlen(data[j]));
if (val != crc_values[i][j]) {
print_error(polys[i], data[j], crc_values[i][j], val);
}
}
}
}
+1624
View File
File diff suppressed because it is too large. Load diff
+72
View File
@@ -0,0 +1,72 @@
/* Interface exported by OpenFlow module. */
#ifndef DATAPATH_H
#define DATAPATH_H 1
#include <linux/netlink.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include "openflow.h"
#include "flow.h"
#define NL_FLOWS_PER_MESSAGE 100
#ifdef NDEBUG
#define dprintk(x...)
#else
#define dprintk(x...) printk(x)
#endif
/* Capabilities supported by this implementation. */
#define OFP_SUPPORTED_CAPABILITIES (OFPC_MULTI_PHY_TX)
/* Actions supported by this implementation. */
#define OFP_SUPPORTED_ACTIONS ( (1 << OFPAT_OUTPUT) \
| (1 << OFPAT_SET_DL_VLAN) \
| (1 << OFPAT_SET_DL_SRC) \
| (1 << OFPAT_SET_DL_DST) \
| (1 << OFPAT_SET_NW_SRC) \
| (1 << OFPAT_SET_NW_DST) \
| (1 << OFPAT_SET_TP_SRC) \
| (1 << OFPAT_SET_TP_DST) )
struct sk_buff;
struct datapath {
int dp_idx;
/* Unique identifier for this datapath, incorporates the dp_idx and
* a hardware address */
uint64_t id;
struct timer_list timer; /* Expiration timer. */
struct sw_chain *chain; /* Forwarding rules. */
/* Data related to the "of" device of this datapath */
struct net_device dev;
struct net_device_stats stats;
/* Flags from the control hello message */
uint16_t hello_flags;
/* Maximum number of bytes that should be sent for flow misses */
uint16_t miss_send_len;
/* Switch ports. */
struct net_bridge_port *ports[OFPP_MAX];
struct list_head port_list; /* List of ports, for flooding. */
};
int dp_output_port(struct datapath *, struct sk_buff *, int out_port);
int dp_output_control(struct datapath *, struct sk_buff *,
uint32_t buffer_id, size_t max_len, int reason);
int dp_set_origin(struct datapath *, uint16_t, struct sk_buff *);
int dp_send_hello(struct datapath *);
int dp_send_flow_expired(struct datapath *, struct sw_flow *);
int dp_update_port_flags(struct datapath *dp, const struct ofp_phy_port *opp);
/* Should hold at least RCU read lock when calling */
struct datapath *dp_get(int dp_idx);
#endif /* datapath.h */
+118
View File
@@ -0,0 +1,118 @@
#include "datapath_t.h"
#include <linux/skbuff.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/if_ether.h>
#include <linux/udp.h>
#include <linux/rcupdate.h>
#include "datapath.h"
static struct sk_buff *
gen_sk_buff(struct datapath *dp, uint32_t packet_size)
{
int in_port;
struct sk_buff *skb;
struct ethhdr *eh;
struct iphdr *ih;
struct udphdr *uh;
for (in_port = 0; in_port < OFPP_MAX; in_port++) {
if (dp->ports[in_port] != NULL)
break;
}
if (in_port == OFPP_MAX) {
printk("benchmark: no in_port to send packets as\n");
return NULL;
}
skb = alloc_skb(packet_size, GFP_ATOMIC);
if (!skb) {
printk("benchmark: cannot allocate skb for benchmark\n");
return NULL;
}
skb_put(skb, packet_size);
skb_set_mac_header(skb, 0);
eh = eth_hdr(skb);
memcpy(eh->h_dest, "\x12\x34\x56\x78\x9a\xbc", ETH_ALEN);
memcpy(eh->h_source, "\xab\xcd\xef\x12\x34\x56", ETH_ALEN);
eh->h_proto = htons(ETH_P_IP);
skb_set_network_header(skb, sizeof(*eh));
ih = ip_hdr(skb);
ih->ihl = 5;
ih->version = IPVERSION;
ih->tos = 0;
ih->tot_len = htons(packet_size - sizeof(*eh));
ih->id = htons(12345);
ih->frag_off = 0;
ih->ttl = IPDEFTTL;
ih->protocol = IPPROTO_UDP;
ih->check = 0; /* want this to be right?! */
ih->saddr = 0x12345678;
ih->daddr = 0x1234abcd;
skb_set_transport_header(skb, sizeof(*eh) + sizeof(*ih));
uh = udp_hdr(skb);
uh->source = htons(1234);
uh->dest = htons(5678);
uh->len = htons(packet_size - sizeof(*eh) - sizeof(*ih));
uh->check = 0;
if (dp_set_origin(dp, in_port, skb)) {
printk("benchmark: could not set origin\n");
kfree_skb(skb);
return NULL;
}
return skb;
}
int
dp_genl_benchmark_nl(struct sk_buff *skb, struct genl_info *info)
{
struct datapath *dp;
uint32_t num_packets = 0;
int i, err = 0;
struct sk_buff *skb2;
if (!info->attrs[DP_GENL_A_DP_IDX] || !info->attrs[DP_GENL_A_NPACKETS]
|| !info->attrs[DP_GENL_A_PSIZE])
return -EINVAL;
num_packets = nla_get_u32((info->attrs[DP_GENL_A_NPACKETS]));
rcu_read_lock();
dp = dp_get(nla_get_u32((info->attrs[DP_GENL_A_DP_IDX])));
if (!dp)
err = -ENOENT;
else {
if (num_packets == 0)
goto benchmark_unlock;
skb2 = gen_sk_buff(dp, nla_get_u32((info->attrs[DP_GENL_A_PSIZE])));
if (skb2 == NULL) {
err = -ENOMEM;
goto benchmark_unlock;
}
for (i = 0; i < num_packets; i++) {
struct sk_buff *copy = skb_get(skb2);
if (copy == NULL) {
printk("benchmark: skb_get failed\n");
err = -ENOMEM;
break;
}
if ((err = dp_output_control(dp, copy, -1,
0, OFPR_ACTION)))
{
printk("benchmark: output control ret %d on iter %d\n", err, i);
break;
}
}
kfree_skb(skb2);
}
benchmark_unlock:
rcu_read_unlock();
return err;
}
+12
View File
@@ -0,0 +1,12 @@
#ifndef DATAPATH_T_H
#define DATAPATH_T_H 1
#include <linux/socket.h>
#include <linux/capability.h>
#include <linux/skbuff.h>
#include <net/genetlink.h>
#include "openflow-netlink.h"
int dp_genl_benchmark_nl(struct sk_buff *, struct genl_info *);
#endif
+78
View File
@@ -0,0 +1,78 @@
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/rcupdate.h>
#include "datapath.h"
#include "forward.h"
static int dp_dev_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
printk("xxx_do_ioctl called\n");
return 0;
}
static struct net_device_stats *dp_dev_get_stats(struct net_device *dev)
{
struct datapath *dp = netdev_priv(dev);
return &dp->stats;
}
int dp_dev_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct datapath *dp = netdev_priv(dev);
printk("xxx dp_dev_xmit not implemented yet!\n");
return 0;
printk("xxx_xmit called send to dp_frame_hook\n");
rcu_read_lock(); /* xxx Only for 2.4 kernels? */
fwd_port_input(dp->chain, skb, OFPP_LOCAL);
rcu_read_unlock(); /* xxx Only for 2.4 kernels? */
return 0;
}
static int dp_dev_open(struct net_device *dev)
{
netif_start_queue(dev);
return 0;
}
static void dp_dev_set_multicast_list(struct net_device *dev)
{
printk("xxx_set_multi called\n");
}
static int dp_dev_stop(struct net_device *dev)
{
netif_stop_queue(dev);
return 0;
}
int dp_dev_setup(struct net_device *dev)
{
int err;
strncpy(dev->name, "of%d", IFNAMSIZ);
err = dev_alloc_name(dev, dev->name);
if (err < 0)
return err;
dev->do_ioctl = dp_dev_do_ioctl;
dev->get_stats = dp_dev_get_stats;
dev->hard_start_xmit = dp_dev_xmit;
dev->open = dp_dev_open;
dev->set_multicast_list = dp_dev_set_multicast_list;
dev->stop = dp_dev_stop;
dev->tx_queue_len = 0;
dev->set_mac_address = NULL;
dev->flags = IFF_BROADCAST | IFF_NOARP | IFF_MULTICAST;
random_ether_addr(dev->dev_addr);
ether_setup(dev);
return register_netdevice(dev);
}
+311
View File
@@ -0,0 +1,311 @@
/*
* Distributed under the terms of the GNU GPL version 2.
* Copyright (c) 2007 The Board of Trustees of The Leland Stanford Junior Univer
sity
*/
#include "flow.h"
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
#include <linux/if_arp.h>
#include <net/llc_pdu.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/kernel.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/in.h>
#include <linux/rcupdate.h>
#include "openflow.h"
#include "compat.h"
#include "snap.h"
struct kmem_cache *flow_cache;
/* Internal function used to compare fields in flow. */
static inline
int flow_fields_match(const struct sw_flow_key *a, const struct sw_flow_key *b,
uint16_t w)
{
return ((w & OFPFW_IN_PORT || a->in_port == b->in_port)
&& (w & OFPFW_DL_VLAN || a->dl_vlan == b->dl_vlan)
&& (w & OFPFW_DL_SRC || !memcmp(a->dl_src, b->dl_src, ETH_ALEN))
&& (w & OFPFW_DL_DST || !memcmp(a->dl_dst, b->dl_dst, ETH_ALEN))
&& (w & OFPFW_DL_TYPE || a->dl_type == b->dl_type)
&& (w & OFPFW_NW_SRC || a->nw_src == b->nw_src)
&& (w & OFPFW_NW_DST || a->nw_dst == b->nw_dst)
&& (w & OFPFW_NW_PROTO || a->nw_proto == b->nw_proto)
&& (w & OFPFW_TP_SRC || a->tp_src == b->tp_src)
&& (w & OFPFW_TP_DST || a->tp_dst == b->tp_dst));
}
/* Returns nonzero if 'a' and 'b' match, that is, if their fields are equal
* modulo wildcards, zero otherwise. */
inline
int flow_matches(const struct sw_flow_key *a, const struct sw_flow_key *b)
{
return flow_fields_match(a, b, (a->wildcards | b->wildcards));
}
/* Returns nonzero if 't' (the table entry's key) and 'd' (the key
* describing the deletion) match, that is, if their fields are
* equal modulo wildcards, zero otherwise. If 'strict' is nonzero, the
* wildcards must match in both 't_key' and 'd_key'. Note that the
* table's wildcards are ignored unless 'strict' is set. */
inline
int flow_del_matches(const struct sw_flow_key *t, const struct sw_flow_key *d, int strict)
{
if (strict && (t->wildcards != d->wildcards))
return 0;
return flow_fields_match(t, d, d->wildcards);
}
void flow_extract_match(struct sw_flow_key* to, const struct ofp_match* from)
{
to->wildcards = ntohs(from->wildcards) & OFPFW_ALL;
to->in_port = from->in_port;
to->dl_vlan = from->dl_vlan;
memcpy(to->dl_src, from->dl_src, ETH_ALEN);
memcpy(to->dl_dst, from->dl_dst, ETH_ALEN);
to->dl_type = from->dl_type;
to->nw_src = from->nw_src;
to->nw_dst = from->nw_dst;
to->nw_proto = from->nw_proto;
to->tp_src = from->tp_src;
to->tp_dst = from->tp_dst;
memset(to->pad, '\0', sizeof(to->pad));
}
void flow_fill_match(struct ofp_match* to, const struct sw_flow_key* from)
{
to->wildcards = htons(from->wildcards);
to->in_port = from->in_port;
to->dl_vlan = from->dl_vlan;
memcpy(to->dl_src, from->dl_src, ETH_ALEN);
memcpy(to->dl_dst, from->dl_dst, ETH_ALEN);
to->dl_type = from->dl_type;
to->nw_src = from->nw_src;
to->nw_dst = from->nw_dst;
to->nw_proto = from->nw_proto;
to->tp_src = from->tp_src;
to->tp_dst = from->tp_dst;
memset(to->pad, '\0', sizeof(to->pad));
}
/* Returns true if 'flow' can be deleted and set up for a deferred free, false
* if deletion has already been scheduled (by another thread).
*
* Caller must hold rcu_read_lock. */
int flow_del(struct sw_flow *flow)
{
return !atomic_cmpxchg(&flow->deleted, 0, 1);
}
/* Allocates and returns a new flow with 'n_actions' action, using allocation
* flags 'flags'. Returns the new flow or a null pointer on failure. */
struct sw_flow *flow_alloc(int n_actions, gfp_t flags)
{
struct sw_flow *flow = kmem_cache_alloc(flow_cache, flags);
if (unlikely(!flow))
return NULL;
flow->n_actions = n_actions;
flow->actions = kmalloc(n_actions * sizeof *flow->actions,
flags);
if (unlikely(!flow->actions) && n_actions > 0) {
kmem_cache_free(flow_cache, flow);
return NULL;
}
return flow;
}
/* Frees 'flow' immediately. */
void flow_free(struct sw_flow *flow)
{
if (unlikely(!flow))
return;
kfree(flow->actions);
kmem_cache_free(flow_cache, flow);
}
/* RCU callback used by flow_deferred_free. */
static void rcu_callback(struct rcu_head *rcu)
{
struct sw_flow *flow = container_of(rcu, struct sw_flow, rcu);
flow_free(flow);
}
/* Schedules 'flow' to be freed after the next RCU grace period.
* The caller must hold rcu_read_lock for this to be sensible. */
void flow_deferred_free(struct sw_flow *flow)
{
call_rcu(&flow->rcu, rcu_callback);
}
/* Prints a representation of 'key' to the kernel log. */
void print_flow(const struct sw_flow_key *key)
{
printk("wild%04x port%04x:vlan%04x mac%02x:%02x:%02x:%02x:%02x:%02x"
"->%02x:%02x:%02x:%02x:%02x:%02x "
"proto%04x ip%u.%u.%u.%u->%u.%u.%u.%u port%d->%d\n",
key->wildcards, ntohs(key->in_port), ntohs(key->dl_vlan),
key->dl_src[0], key->dl_src[1], key->dl_src[2],
key->dl_src[3], key->dl_src[4], key->dl_src[5],
key->dl_dst[0], key->dl_dst[1], key->dl_dst[2],
key->dl_dst[3], key->dl_dst[4], key->dl_dst[5],
ntohs(key->dl_type),
((unsigned char *)&key->nw_src)[0],
((unsigned char *)&key->nw_src)[1],
((unsigned char *)&key->nw_src)[2],
((unsigned char *)&key->nw_src)[3],
((unsigned char *)&key->nw_dst)[0],
((unsigned char *)&key->nw_dst)[1],
((unsigned char *)&key->nw_dst)[2],
((unsigned char *)&key->nw_dst)[3],
ntohs(key->tp_src), ntohs(key->tp_dst));
}
uint32_t hash_in6(const struct in6_addr *in)
{
return (in->s6_addr32[0] ^ in->s6_addr32[1]
^ in->s6_addr32[2] ^ in->s6_addr32[3]);
}
// with inspiration from linux/if_arp.h
struct arp_eth_hdr {
uint16_t ar_hrd; /* format of hardware address */
uint16_t ar_pro; /* format of protocol address */
uint8_t ar_hln; /* length of hardware address */
uint8_t ar_pln; /* length of protocol address */
uint16_t ar_op; /* ARP opcode (command) */
uint8_t ar_sha[ETH_ALEN]; /* source hardware addr */
uint32_t ar_sip; /* source protocol addr */
uint8_t ar_tha[ETH_ALEN]; /* dest hardware addr */
uint32_t ar_tip; /* dest protocol addr */
} __attribute__((packed));
/* Parses the Ethernet frame in 'skb', which was received on 'in_port',
* and initializes 'key' to match. */
void flow_extract(struct sk_buff *skb, uint16_t in_port,
struct sw_flow_key *key)
{
struct ethhdr *mac;
struct udphdr *th;
int nh_ofs, th_ofs;
key->in_port = htons(in_port);
key->wildcards = 0;
memset(key->pad, '\0', sizeof(key->pad));
/* This code doesn't check that skb->len is long enough to contain the
* MAC or network header. With a 46-byte minimum length frame this
* assumption is always correct. */
/* Doesn't verify checksums. Should it? */
/* Data link layer. We only support Ethernet. */
mac = eth_hdr(skb);
nh_ofs = sizeof(struct ethhdr);
if (likely(ntohs(mac->h_proto) >= OFP_DL_TYPE_ETH2_CUTOFF)) {
/* This is an Ethernet II frame */
key->dl_type = mac->h_proto;
} else {
/* This is an 802.2 frame */
if (snap_get_ethertype(skb, &key->dl_type) != -EINVAL) {
nh_ofs += sizeof(struct snap_hdr);
} else {
key->dl_type = OFP_DL_TYPE_NOT_ETH_TYPE;
nh_ofs += sizeof(struct llc_pdu_un);
}
}
/* Check for a VLAN tag */
if (likely(key->dl_type != __constant_htons(ETH_P_8021Q))) {
key->dl_vlan = __constant_htons(OFP_VLAN_NONE);
} else {
struct vlan_hdr *vh = (struct vlan_hdr *)(skb_mac_header(skb) + nh_ofs);
key->dl_type = vh->h_vlan_encapsulated_proto;
key->dl_vlan = vh->h_vlan_TCI & __constant_htons(VLAN_VID_MASK);
nh_ofs += sizeof(*vh);
}
memcpy(key->dl_src, mac->h_source, ETH_ALEN);
memcpy(key->dl_dst, mac->h_dest, ETH_ALEN);
skb_set_network_header(skb, nh_ofs);
/* Network layer. */
if (likely(key->dl_type == htons(ETH_P_IP))) {
struct iphdr *nh = ip_hdr(skb);
key->nw_src = nh->saddr;
key->nw_dst = nh->daddr;
key->nw_proto = nh->protocol;
th_ofs = nh_ofs + nh->ihl * 4;
skb_set_transport_header(skb, th_ofs);
/* Transport layer. */
if ((key->nw_proto != IPPROTO_TCP && key->nw_proto != IPPROTO_UDP)
|| skb->len < th_ofs + sizeof(struct udphdr)) {
goto no_th;
}
th = udp_hdr(skb);
key->tp_src = th->source;
key->tp_dst = th->dest;
return;
} else if (key->dl_type == htons(ETH_P_IPV6)) {
struct ipv6hdr *nh = ipv6_hdr(skb);
key->nw_src = hash_in6(&nh->saddr);
key->nw_dst = hash_in6(&nh->daddr);
/* FIXME: Need to traverse next-headers until we find the
* upper-layer header. */
key->nw_proto = 0;
goto no_th;
} else if (key->dl_type == htons(ETH_P_ARP)) {
/* just barely within 46-byte minimum packet */
struct arp_eth_hdr *ah = (struct arp_eth_hdr *)skb_network_header(skb);
if (ah->ar_hrd == htons(ARPHRD_ETHER)
&& ah->ar_pro == htons(ETH_P_IP)
&& ah->ar_hln == ETH_ALEN
&& ah->ar_pln == sizeof(key->nw_src))
{
/* check if sha/tha match dl_src/dl_dst? */
key->nw_src = ah->ar_sip;
key->nw_dst = ah->ar_tip;
key->nw_proto = 0;
goto no_th;
}
} else {
/* Fall through. */
}
key->nw_src = 0;
key->nw_dst = 0;
key->nw_proto = 0;
no_th:
key->tp_src = 0;
key->tp_dst = 0;
}
/* Initializes the flow module.
* Returns zero if successful or a negative error code. */
int flow_init(void)
{
flow_cache = kmem_cache_create("sw_flow", sizeof(struct sw_flow), 0,
0, NULL);
if (flow_cache == NULL)
return -ENOMEM;
return 0;
}
/* Uninitializes the flow module. */
void flow_exit(void)
{
kmem_cache_destroy(flow_cache);
}
+131
View File
@@ -0,0 +1,131 @@
#ifndef FLOW_H
#define FLOW_H 1
#include <linux/kernel.h>
#include <asm/atomic.h>
#include <linux/spinlock.h>
#include <linux/list.h>
#include <linux/types.h>
#include <linux/rcupdate.h>
#include <linux/gfp.h>
#include <linux/skbuff.h>
#include "openflow.h"
struct sk_buff;
struct ofp_flow_mod;
/* Identification data for a flow.
Network byte order except for the "wildcards" field.
In decreasing order by size, so that sw_flow_key structures can
be hashed or compared bytewise.
It might be useful to reorder members from (expected) greatest to least
inter-flow variability, so that failing bytewise comparisons with memcmp
terminate as quickly as possible on average. */
struct sw_flow_key {
uint32_t nw_src; /* IP source address. */
uint32_t nw_dst; /* IP destination address. */
uint16_t in_port; /* Input switch port */
uint16_t dl_vlan; /* Input VLAN. */
uint16_t dl_type; /* Ethernet frame type. */
uint16_t tp_src; /* TCP/UDP source port. */
uint16_t tp_dst; /* TCP/UDP destination port. */
uint16_t wildcards; /* Wildcard fields (host byte order). */
uint8_t dl_src[6]; /* Ethernet source address. */
uint8_t dl_dst[6]; /* Ethernet destination address. */
uint8_t nw_proto; /* IP protocol. */
uint8_t pad[3]; /* NB: Pad to make 32-bit aligned */
};
/* We need to manually make sure that the structure is 32-bit aligned,
* since we don't want garbage values in compiler-generated pads from
* messing up hash matches.
*/
static inline void check_key_align(void)
{
BUILD_BUG_ON(sizeof(struct sw_flow_key) != 36);
}
/* Maximum number of actions in a single flow entry. */
#define MAX_ACTIONS 16
/* Locking:
*
* - Readers must take rcu_read_lock and hold it the entire time that the flow
* must continue to exist. Readers need not take delete_lock. They *may*
* examine 'deleted' *if* it is important not to read stale data.
*
* - Deleters must take rcu_read_lock and call flow_del to verify that another
* thread has not already deleted the flow. If not, do a deferred free of
* the flow with call_rcu, then rcu_assign_pointer or [h]list_del_rcu the
* flow.
*
* - In-place update not yet contemplated.
*/
struct sw_flow {
struct sw_flow_key key;
uint32_t group_id; /* Flow group ID (for QoS). */
uint16_t max_idle; /* Idle time before discarding (seconds). */
unsigned long timeout; /* Expiration time (in jiffies). */
/* FIXME? Probably most flows have only a single action. */
unsigned int n_actions;
struct ofp_action *actions;
/* For use by table implementation. */
union {
struct list_head node;
struct hlist_node hnode;
} u;
spinlock_t lock; /* Lock this entry...mostly for stat updates */
unsigned long init_time; /* When the flow was created (in jiffies). */
uint64_t packet_count; /* Number of packets associated with this entry */
uint64_t byte_count; /* Number of bytes associated with this entry */
atomic_t deleted; /* 0 if not deleted, 1 if deleted. */
struct rcu_head rcu;
};
int flow_matches(const struct sw_flow_key *, const struct sw_flow_key *);
int flow_del_matches(const struct sw_flow_key *, const struct sw_flow_key *,
int);
struct sw_flow *flow_alloc(int n_actions, gfp_t flags);
void flow_free(struct sw_flow *);
void flow_deferred_free(struct sw_flow *);
void flow_extract(struct sk_buff *, uint16_t in_port, struct sw_flow_key *);
int flow_del(struct sw_flow *);
void flow_extract_match(struct sw_flow_key* to, const struct ofp_match* from);
void flow_fill_match(struct ofp_match* to, const struct sw_flow_key* from);
void print_flow(const struct sw_flow_key *);
#include <linux/jiffies.h>
static inline int flow_timeout(struct sw_flow *flow)
{
if (flow->max_idle == OFP_FLOW_PERMANENT)
return 0;
return time_after(jiffies, flow->timeout);
}
static inline void flow_used(struct sw_flow *flow, struct sk_buff *skb)
{
unsigned long flags;
if (flow->max_idle != OFP_FLOW_PERMANENT)
flow->timeout = jiffies + HZ * flow->max_idle;
spin_lock_irqsave(&flow->lock, flags);
flow->packet_count++;
flow->byte_count += skb->len;
spin_unlock_irqrestore(&flow->lock, flags);
}
extern struct kmem_cache *flow_cache;
int flow_init(void);
void flow_exit(void);
#endif /* flow.h */
+585
View File
@@ -0,0 +1,585 @@
/*
* Distributed under the terms of the GNU GPL version 2.
* Copyright (c) 2007 The Board of Trustees of The Leland Stanford Junior Univer
sity
*/
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/in6.h>
#include <asm/uaccess.h>
#include <linux/types.h>
#include <net/checksum.h>
#include "forward.h"
#include "datapath.h"
#include "chain.h"
#include "flow.h"
/* FIXME: do we need to use GFP_ATOMIC everywhere here? */
static void execute_actions(struct datapath *, struct sk_buff *,
const struct sw_flow_key *,
const struct ofp_action *, int n_actions);
static int make_writable(struct sk_buff **);
static struct sk_buff *retrieve_skb(uint32_t id);
static void discard_skb(uint32_t id);
/* 'skb' was received on 'in_port', a physical switch port between 0 and
* OFPP_MAX. Process it according to 'chain'. */
void fwd_port_input(struct sw_chain *chain, struct sk_buff *skb, int in_port)
{
struct sw_flow_key key;
struct sw_flow *flow;
flow_extract(skb, in_port, &key);
flow = chain_lookup(chain, &key);
if (likely(flow != NULL)) {
flow_used(flow, skb);
execute_actions(chain->dp, skb, &key,
flow->actions, flow->n_actions);
} else {
dp_output_control(chain->dp, skb, fwd_save_skb(skb),
chain->dp->miss_send_len, OFPR_NO_MATCH);
}
}
static int do_output(struct datapath *dp, struct sk_buff *skb, size_t max_len,
int out_port)
{
if (!skb)
return -ENOMEM;
return (likely(out_port != OFPP_CONTROLLER)
? dp_output_port(dp, skb, out_port)
: dp_output_control(dp, skb, fwd_save_skb(skb),
max_len, OFPR_ACTION));
}
static void execute_actions(struct datapath *dp, struct sk_buff *skb,
const struct sw_flow_key *key,
const struct ofp_action *actions, int n_actions)
{
/* Every output action needs a separate clone of 'skb', but the common
* case is just a single output action, so that doing a clone and
* then freeing the original skbuff is wasteful. So the following code
* is slightly obscure just to avoid that. */
int prev_port;
size_t max_len=0; /* Initialze to make compiler happy */
uint16_t eth_proto;
int i;
prev_port = -1;
eth_proto = ntohs(key->dl_type);
for (i = 0; i < n_actions; i++) {
const struct ofp_action *a = &actions[i];
if (prev_port != -1) {
do_output(dp, skb_clone(skb, GFP_ATOMIC),
max_len, prev_port);
prev_port = -1;
}
if (likely(a->type == ntohs(OFPAT_OUTPUT))) {
prev_port = ntohs(a->arg.output.port);
max_len = ntohs(a->arg.output.max_len);
} else {
if (!make_writable(&skb)) {
printk("make_writable failed\n");
break;
}
skb = execute_setter(skb, eth_proto, key, a);
}
}
if (prev_port != -1)
do_output(dp, skb, max_len, prev_port);
else
kfree_skb(skb);
}
/* Updates 'sum', which is a field in 'skb''s data, given that a 4-byte field
* covered by the sum has been changed from 'from' to 'to'. If set,
* 'pseudohdr' indicates that the field is in the TCP or UDP pseudo-header.
* Based on nf_proto_csum_replace4. */
static void update_csum(__sum16 *sum, struct sk_buff *skb,
__be32 from, __be32 to, int pseudohdr)
{
__be32 diff[] = { ~from, to };
if (skb->ip_summed != CHECKSUM_PARTIAL) {
*sum = csum_fold(csum_partial((char *)diff, sizeof(diff),
~csum_unfold(*sum)));
if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr)
skb->csum = ~csum_partial((char *)diff, sizeof(diff),
~skb->csum);
} else if (pseudohdr)
*sum = ~csum_fold(csum_partial((char *)diff, sizeof(diff),
csum_unfold(*sum)));
}
static void modify_nh(struct sk_buff *skb, uint16_t eth_proto,
uint8_t nw_proto, const struct ofp_action *a)
{
if (eth_proto == ETH_P_IP) {
struct iphdr *nh = ip_hdr(skb);
uint32_t new, *field;
new = a->arg.nw_addr;
if (a->type == OFPAT_SET_NW_SRC)
field = &nh->saddr;
else
field = &nh->daddr;
if (nw_proto == IPPROTO_TCP) {
struct tcphdr *th = tcp_hdr(skb);
update_csum(&th->check, skb, *field, new, 1);
} else if (nw_proto == IPPROTO_UDP) {
struct udphdr *th = udp_hdr(skb);
update_csum(&th->check, skb, *field, new, 1);
}
update_csum(&nh->check, skb, *field, new, 0);
*field = new;
}
}
static void modify_th(struct sk_buff *skb, uint16_t eth_proto,
uint8_t nw_proto, const struct ofp_action *a)
{
if (eth_proto == ETH_P_IP) {
uint16_t new, *field;
new = a->arg.tp;
if (nw_proto == IPPROTO_TCP) {
struct tcphdr *th = tcp_hdr(skb);
if (a->type == OFPAT_SET_TP_SRC)
field = &th->source;
else
field = &th->dest;
update_csum(&th->check, skb, *field, new, 1);
*field = new;
} else if (nw_proto == IPPROTO_UDP) {
struct udphdr *th = udp_hdr(skb);
if (a->type == OFPAT_SET_TP_SRC)
field = &th->source;
else
field = &th->dest;
update_csum(&th->check, skb, *field, new, 1);
*field = new;
}
}
}
static struct sk_buff *vlan_pull_tag(struct sk_buff *skb)
{
struct vlan_ethhdr *vh = vlan_eth_hdr(skb);
struct ethhdr *eh;
/* Verify we were given a vlan packet */
if (vh->h_vlan_proto != __constant_htons(ETH_P_8021Q))
return skb;
memmove(skb->data + VLAN_HLEN, skb->data, 2 * VLAN_ETH_ALEN);
eh = (struct ethhdr *)skb_pull(skb, VLAN_HLEN);
skb->protocol = eh->h_proto;
skb->mac_header += VLAN_HLEN;
return skb;
}
static struct sk_buff *modify_vlan(struct sk_buff *skb,
const struct sw_flow_key *key, const struct ofp_action *a)
{
uint16_t new_id = a->arg.vlan_id;
if (new_id != OFP_VLAN_NONE) {
if (key->dl_vlan != __constant_htons(OFP_VLAN_NONE)) {
/* Modify vlan id, but maintain other TCI values */
struct vlan_ethhdr *vh = vlan_eth_hdr(skb);
vh->h_vlan_TCI = (vh->h_vlan_TCI
& ~(__constant_htons(VLAN_VID_MASK))) | htons(new_id);
} else {
/* Add vlan header */
skb = vlan_put_tag(skb, new_id);
}
} else {
/* Remove an existing vlan header if it exists */
vlan_pull_tag(skb);
}
return skb;
}
struct sk_buff *execute_setter(struct sk_buff *skb, uint16_t eth_proto,
const struct sw_flow_key *key, const struct ofp_action *a)
{
switch (a->type) {
case OFPAT_SET_DL_VLAN:
skb = modify_vlan(skb, key, a);
break;
case OFPAT_SET_DL_SRC: {
struct ethhdr *eh = eth_hdr(skb);
memcpy(eh->h_source, a->arg.dl_addr, sizeof eh->h_source);
break;
}
case OFPAT_SET_DL_DST: {
struct ethhdr *eh = eth_hdr(skb);
memcpy(eh->h_dest, a->arg.dl_addr, sizeof eh->h_dest);
break;
}
case OFPAT_SET_NW_SRC:
case OFPAT_SET_NW_DST:
modify_nh(skb, eth_proto, key->nw_proto, a);
break;
case OFPAT_SET_TP_SRC:
case OFPAT_SET_TP_DST:
modify_th(skb, eth_proto, key->nw_proto, a);
break;
default:
BUG();
}
return skb;
}
static int
recv_control_hello(struct sw_chain *chain, const void *msg)
{
const struct ofp_control_hello *och = msg;
printk("control_hello(version=%d)\n", ntohl(och->version));
if (ntohs(och->miss_send_len) != OFP_MISS_SEND_LEN_UNCHANGED) {
chain->dp->miss_send_len = ntohs(och->miss_send_len);
}
chain->dp->hello_flags = ntohs(och->flags);
dp_send_hello(chain->dp);
return 0;
}
static int
recv_packet_out(struct sw_chain *chain, const void *msg)
{
const struct ofp_packet_out *opo = msg;
struct sk_buff *skb;
struct vlan_ethhdr *mac;
int nh_ofs;
if (ntohl(opo->buffer_id) == (uint32_t) -1) {
int data_len = ntohs(opo->header.length) - sizeof *opo;
/* FIXME: there is likely a way to reuse the data in msg. */
skb = alloc_skb(data_len, GFP_ATOMIC);
if (!skb)
return -ENOMEM;
/* FIXME? We don't reserve NET_IP_ALIGN or NET_SKB_PAD since
* we're just transmitting this raw without examining anything
* at those layers. */
memcpy(skb_put(skb, data_len), opo->u.data, data_len);
dp_set_origin(chain->dp, ntohs(opo->in_port), skb);
skb_set_mac_header(skb, 0);
mac = vlan_eth_hdr(skb);
if (likely(mac->h_vlan_proto != htons(ETH_P_8021Q)))
nh_ofs = sizeof(struct ethhdr);
else
nh_ofs = sizeof(struct vlan_ethhdr);
skb_set_network_header(skb, nh_ofs);
dp_output_port(chain->dp, skb, ntohs(opo->out_port));
} else {
struct sw_flow_key key;
int n_acts;
skb = retrieve_skb(ntohl(opo->buffer_id));
if (!skb)
return -ESRCH;
dp_set_origin(chain->dp, ntohs(opo->in_port), skb);
n_acts = (ntohs(opo->header.length) - sizeof *opo)
/ sizeof *opo->u.actions;
flow_extract(skb, ntohs(opo->in_port), &key);
execute_actions(chain->dp, skb, &key, opo->u.actions, n_acts);
}
return 0;
}
static int
recv_port_mod(struct sw_chain *chain, const void *msg)
{
const struct ofp_port_mod *opm = msg;
dp_update_port_flags(chain->dp, &opm->desc);
return 0;
}
static int
add_flow(struct sw_chain *chain, const struct ofp_flow_mod *ofm)
{
int error = -ENOMEM;
int n_acts;
struct sw_flow *flow;
/* Check number of actions. */
n_acts = (ntohs(ofm->header.length) - sizeof *ofm) / sizeof *ofm->actions;
if (n_acts > MAX_ACTIONS) {
error = -E2BIG;
goto error;
}
/* Allocate memory. */
flow = flow_alloc(n_acts, GFP_ATOMIC);
if (flow == NULL)
goto error;
/* Fill out flow. */
flow_extract_match(&flow->key, &ofm->match);
flow->group_id = ntohl(ofm->group_id);
flow->max_idle = ntohs(ofm->max_idle);
flow->timeout = jiffies + flow->max_idle * HZ;
flow->n_actions = n_acts;
flow->init_time = jiffies;
flow->byte_count = 0;
flow->packet_count = 0;
atomic_set(&flow->deleted, 0);
spin_lock_init(&flow->lock);
memcpy(flow->actions, ofm->actions, n_acts * sizeof *flow->actions);
/* Act. */
error = chain_insert(chain, flow);
if (error)
goto error_free_flow;
error = 0;
if (ntohl(ofm->buffer_id) != (uint32_t) -1) {
struct sk_buff *skb = retrieve_skb(ntohl(ofm->buffer_id));
if (skb) {
struct sw_flow_key key;
flow_used(flow, skb);
flow_extract(skb, ntohs(ofm->match.in_port), &key);
execute_actions(chain->dp, skb, &key,
ofm->actions, n_acts);
}
else
error = -ESRCH;
}
return error;
error_free_flow:
flow_free(flow);
error:
if (ntohl(ofm->buffer_id) != (uint32_t) -1)
discard_skb(ntohl(ofm->buffer_id));
return error;
}
static int
recv_flow(struct sw_chain *chain, const void *msg)
{
const struct ofp_flow_mod *ofm = msg;
uint16_t command = ntohs(ofm->command);
if (command == OFPFC_ADD) {
return add_flow(chain, ofm);
} else if (command == OFPFC_DELETE) {
struct sw_flow_key key;
flow_extract_match(&key, &ofm->match);
return chain_delete(chain, &key, 0) ? 0 : -ESRCH;
} else if (command == OFPFC_DELETE_STRICT) {
struct sw_flow_key key;
flow_extract_match(&key, &ofm->match);
return chain_delete(chain, &key, 1) ? 0 : -ESRCH;
} else {
return -ENOTSUPP;
}
}
/* 'msg', which is 'length' bytes long, was received from the control path.
* Apply it to 'chain'. */
int
fwd_control_input(struct sw_chain *chain, const void *msg, size_t length)
{
struct openflow_packet {
size_t min_size;
int (*handler)(struct sw_chain *, const void *);
};
static const struct openflow_packet packets[] = {
[OFPT_CONTROL_HELLO] = {
sizeof (struct ofp_control_hello),
recv_control_hello,
},
[OFPT_PACKET_OUT] = {
sizeof (struct ofp_packet_out),
recv_packet_out,
},
[OFPT_FLOW_MOD] = {
sizeof (struct ofp_flow_mod),
recv_flow,
},
[OFPT_PORT_MOD] = {
sizeof (struct ofp_port_mod),
recv_port_mod,
},
};
const struct openflow_packet *pkt;
struct ofp_header *oh;
if (length < sizeof(struct ofp_header))
return -EINVAL;
oh = (struct ofp_header *) msg;
if (oh->version != 1 || oh->type >= ARRAY_SIZE(packets)
|| ntohs(oh->length) > length)
return -EINVAL;
pkt = &packets[oh->type];
if (!pkt->handler)
return -ENOSYS;
if (length < pkt->min_size)
return -EFAULT;
return pkt->handler(chain, msg);
}
/* Packet buffering. */
#define OVERWRITE_SECS 1
#define OVERWRITE_JIFFIES (OVERWRITE_SECS * HZ)
struct packet_buffer {
struct sk_buff *skb;
uint32_t cookie;
unsigned long exp_jiffies;
};
static struct packet_buffer buffers[N_PKT_BUFFERS];
static unsigned int buffer_idx;
static DEFINE_SPINLOCK(buffer_lock);
uint32_t fwd_save_skb(struct sk_buff *skb)
{
struct packet_buffer *p;
unsigned long int flags;
uint32_t id;
spin_lock_irqsave(&buffer_lock, flags);
buffer_idx = (buffer_idx + 1) & PKT_BUFFER_MASK;
p = &buffers[buffer_idx];
if (p->skb) {
/* Don't buffer packet if existing entry is less than
* OVERWRITE_SECS old. */
if (time_before(jiffies, p->exp_jiffies)) {
spin_unlock_irqrestore(&buffer_lock, flags);
return -1;
} else
kfree_skb(p->skb);
}
/* Don't use maximum cookie value since the all-bits-1 id is
* special. */
if (++p->cookie >= (1u << PKT_COOKIE_BITS) - 1)
p->cookie = 0;
skb_get(skb);
p->skb = skb;
p->exp_jiffies = jiffies + OVERWRITE_JIFFIES;
id = buffer_idx | (p->cookie << PKT_BUFFER_BITS);
spin_unlock_irqrestore(&buffer_lock, flags);
return id;
}
static struct sk_buff *retrieve_skb(uint32_t id)
{
unsigned long int flags;
struct sk_buff *skb = NULL;
struct packet_buffer *p;
spin_lock_irqsave(&buffer_lock, flags);
p = &buffers[id & PKT_BUFFER_MASK];
if (p->cookie == id >> PKT_BUFFER_BITS) {
skb = p->skb;
p->skb = NULL;
} else {
printk("cookie mismatch: %x != %x\n",
id >> PKT_BUFFER_BITS, p->cookie);
}
spin_unlock_irqrestore(&buffer_lock, flags);
return skb;
}
static void discard_skb(uint32_t id)
{
unsigned long int flags;
struct packet_buffer *p;
spin_lock_irqsave(&buffer_lock, flags);
p = &buffers[id & PKT_BUFFER_MASK];
if (p->cookie == id >> PKT_BUFFER_BITS) {
kfree_skb(p->skb);
p->skb = NULL;
}
spin_unlock_irqrestore(&buffer_lock, flags);
}
void fwd_exit(void)
{
int i;
for (i = 0; i < N_PKT_BUFFERS; i++)
kfree_skb(buffers[i].skb);
}
/* Utility functions. */
/* Makes '*pskb' writable, possibly copying it and setting '*pskb' to point to
* the copy.
* Returns 1 if successful, 0 on failure. */
static int
make_writable(struct sk_buff **pskb)
{
/* Based on skb_make_writable() in net/netfilter/core.c. */
struct sk_buff *nskb;
/* Not exclusive use of packet? Must copy. */
if (skb_shared(*pskb) || skb_cloned(*pskb))
goto copy_skb;
return pskb_may_pull(*pskb, 64); /* FIXME? */
copy_skb:
nskb = skb_copy(*pskb, GFP_ATOMIC);
if (!nskb)
return 0;
BUG_ON(skb_is_nonlinear(nskb));
/* Rest of kernel will get very unhappy if we pass it a
suddenly-orphaned skbuff */
if ((*pskb)->sk)
skb_set_owner_w(nskb, (*pskb)->sk);
kfree_skb(*pskb);
*pskb = nskb;
return 1;
}
+33
View File
@@ -0,0 +1,33 @@
#ifndef FORWARD_H
#define FORWARD_H 1
#include <linux/types.h>
#include "flow.h"
struct sk_buff;
struct sw_chain;
struct ofp_action;
/* Buffers are identified to userspace by a 31-bit opaque ID. We divide the ID
* into a buffer number (low bits) and a cookie (high bits). The buffer number
* is an index into an array of buffers. The cookie distinguishes between
* different packets that have occupied a single buffer. Thus, the more
* buffers we have, the lower-quality the cookie... */
#define PKT_BUFFER_BITS 8
#define N_PKT_BUFFERS (1 << PKT_BUFFER_BITS)
#define PKT_BUFFER_MASK (N_PKT_BUFFERS - 1)
#define PKT_COOKIE_BITS (32 - PKT_BUFFER_BITS)
void fwd_port_input(struct sw_chain *, struct sk_buff *, int in_port);
int fwd_control_input(struct sw_chain *, const void *, size_t);
uint32_t fwd_save_skb(struct sk_buff *skb);
void fwd_exit(void);
struct sk_buff *execute_setter(struct sk_buff *, uint16_t,
const struct sw_flow_key *, const struct ofp_action *);
#endif /* forward.h */
+581
View File
@@ -0,0 +1,581 @@
/*
* Distributed under the terms of the GNU GPL version 2.
* Copyright (c) 2007 The Board of Trustees of The Leland Stanford Junior Univer
sity
*/
#include <linux/skbuff.h>
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/random.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include "forward.h"
#include "tests/forward_t.h"
#include "openflow.h"
#include "unit.h"
#include "flow.h"
/*
* Tests execute_settings() in forward.c to check that actions are
* appropriately taken on packets, meaning:
*
* 1. Checksums are correct.
* 2. Actions are only taken on compatible packets (IP action not taken on
* non-IP packet)
* 3. Other packet data remains untouched.
* forward_t.h contains static packet definitions. forward_t.h should be
* generated using gen_forward_t.c. This test is run on whatever packets are
* defined in forward_t.h.
*
* NOTE: Tests assume packets in forward_t.h are present in full and IP and
* transport checksums are correct. (Can prevent offloading of checksum
* computation using ethtool.
*/
/*
* Sets 'a->data'. If 'key' != NULL, sets 'data' to equal 'key's value for type
* specified by 'a->type'. If 'key' == NULL, sets data to a random value.
*/
static void
set_action_data(struct sk_buff *skb, struct sw_flow_key *key, struct ofp_action *a)
{
if (key != NULL) {
switch(a->type) {
case(OFPAT_SET_DL_SRC):
memcpy(a->arg.dl_addr, key->dl_src, sizeof key->dl_src);
break;
case(OFPAT_SET_DL_DST):
memcpy(a->arg.dl_addr, key->dl_dst, sizeof key->dl_dst);
break;
case(OFPAT_SET_NW_SRC):
if (key->dl_type == htons(ETH_P_IP))
a->arg.nw_addr = key->nw_src;
else
a->arg.nw_addr = random32();
break;
case(OFPAT_SET_NW_DST):
if (key->dl_type == htons(ETH_P_IP))
a->arg.nw_addr = key->nw_dst;
else
a->arg.nw_addr = random32();
break;
case(OFPAT_SET_TP_SRC):
if (key->nw_proto == IPPROTO_TCP || key->nw_proto == IPPROTO_UDP)
a->arg.tp = key->tp_src;
else
a->arg.tp = (uint16_t) random32();
break;
case(OFPAT_SET_TP_DST):
if (key->nw_proto == IPPROTO_TCP || key->nw_proto == IPPROTO_UDP)
a->arg.tp = key->tp_dst;
else
a->arg.tp = (uint16_t) random32();
break;
default:
BUG();
}
} else {
((uint32_t*)a->arg.dl_addr)[0] = random32();
((uint16_t*)a->arg.dl_addr)[2] = random32();
}
}
/*
* Checks the IP sum of an IP packet. Returns 0 if correct, else -1.
*/
static void
check_IP_csum(struct iphdr *ih)
{
uint16_t check, *data;
uint32_t n_bytes, sum;
check = ih->check;
ih->check = 0;
data = (uint16_t*) ih;
sum = 0;
n_bytes = ih->ihl * 4;
while (n_bytes > 1) {
sum += ntohs(*data);
sum = (sum >> 16) + (uint16_t)sum;
data++;
n_bytes -= 2;
}
if (n_bytes == 1) {
sum += *(uint8_t*)data;
sum = (sum >> 16) + (uint16_t)sum;
}
ih->check = htons((uint16_t)(~sum));
if (ih->check != check) {
unit_fail("IP checksum %hu does not match %hu",
ntohs(ih->check), ntohs(check));
}
}
/*
* Partially computes TCP checksum over 'n_bytes' pointed to by 'data'. Can be
* called multiple times if data csum is to be computed on is fragmented. If
* 'is_last' == 0, assumes will be called again on more data and returns the
* value that should be passed in as 'incr_sum' on the next call. Else if
* 'is_last' == 1, returns the final checksum. On the first call, 'incr_sum'
* should equal 0. If 'is_last' == 0, 'n_bytes' must be even. i.e. Should
* first be called on pseudo header fields that are multiples of two, and then
* on the TCP packet.
*/
static uint32_t
compute_transport_checksum(uint16_t *data, uint32_t n_bytes,
uint32_t incr_sum, uint8_t is_last)
{
uint8_t arr[2];
if (n_bytes % 2 != 0 && is_last == 0)
BUG();
while (n_bytes > 1) {
incr_sum += ntohs(*data);
incr_sum = (incr_sum >> 16) + (uint16_t)incr_sum;
data++;
n_bytes -= 2;
}
if (is_last == 0)
return incr_sum;
if(n_bytes == 1) {
arr[0] = *(uint8_t*)data;
arr[1] = 0;
incr_sum += ntohs(*((uint16_t*)arr));
incr_sum = (incr_sum >> 16) + (uint16_t)incr_sum;
}
return ~incr_sum;
}
/*
* Checks the transport layer's checksum of a packet. Returns '0' if correct,
* else '1'. 'ih' should point to the IP header of the packet, if TCP, 'th'
* should point the TCP header, and if UDP, 'uh' should point to the UDP
* header.
*/
static int
check_transport_csum(struct iphdr *ih, struct tcphdr *th,
struct udphdr *uh)
{
uint32_t tmp;
uint16_t len, check;
uint8_t arr[2];
tmp = compute_transport_checksum((uint16_t*)(&ih->saddr),
2 * sizeof ih->saddr, 0, 0);
arr[0] = 0;
arr[1] = ih->protocol;
tmp = compute_transport_checksum((uint16_t*)arr, 2, tmp, 0);
len = ntohs(ih->tot_len) - (ih->ihl * 4);
*((uint16_t*)arr) = htons(len);
tmp = compute_transport_checksum((uint16_t*)arr, 2, tmp, 0);
if (th != NULL) {
check = th->check;
th->check = 0;
th->check = htons((uint16_t)compute_transport_checksum((uint16_t*)th,
len, tmp, 1));
if (th->check != check) {
unit_fail("TCP checksum %hu does not match %hu",
ntohs(th->check), ntohs(check));
return -1;
}
} else if (uh != NULL) {
check = uh->check;
uh->check = 0;
uh->check = htons((uint16_t)compute_transport_checksum((uint16_t*)uh,
len, tmp, 1));
if (uh->check != check) {
unit_fail("UDP checksum %hu does not match %hu",
ntohs(uh->check), ntohs(check));
return -1;
}
}
return 0;
}
/*
* Compares 'pkt_len' bytes of 'data' to 'pkt'. excl_start and excl_end point
* together delineate areas of 'data' that are not supposed to match 'pkt'.
* 'num_excl' specify how many such areas exist. An 'excl_start' entry is
* ignored if it equals NULL. See 'check_packet()' for usage.
*/
static void
compare(uint8_t *data, uint8_t *pkt, uint32_t pkt_len,
uint8_t **excl_start, uint8_t **excl_end, uint32_t num_excl)
{
uint32_t i;
uint8_t *d, *p, *end;
int ret;
end = data + pkt_len;
d = data;
p = pkt;
ret = 0;
for (i = 0; i < num_excl; i++) {
if(*excl_start != NULL) {
if ((ret = memcmp(d, p, *excl_start - d)) != 0)
break;
p += (*excl_end - d);
d = *excl_end;
}
excl_start++;
excl_end++;
}
if (ret == 0)
ret = memcmp(d, p, end - d);
if (ret != 0) {
unit_fail("skb and packet comparison failed:");
for (i = 0; i < pkt_len; i++) {
if (data[i] != pkt[i]) {
unit_fail("skb[%u] = 0x%x != 0x%x",
i, data[i], pkt[i]);
}
}
}
}
/*
* Checks that a packet's data has remained consistent after an action has been
* applied. 'skb' is the modified packet, 'a' is the action that was taken on
* the packet, 'p' is a copy of the packet's data before action 'a' was taken.
* Checks that the action was in fact taken, that the checksums of the packet
* are correct, and that no other data in the packet was altered.
*/
static void
check_packet(struct sk_buff *skb, struct ofp_action *a, struct pkt *p)
{
struct ethhdr *eh;
struct iphdr *ih;
struct tcphdr *th;
struct udphdr *uh;
uint8_t *excl_start[5], *excl_end[5];
eh = eth_hdr(skb);
ih = NULL;
th = NULL;
uh = NULL;
memset(excl_start, 0, sizeof excl_start);
memset(excl_end, 0, sizeof excl_end);
if (eh->h_proto == htons(ETH_P_IP)) {
ih = ip_hdr(skb);
excl_start[1] = (uint8_t*)&ih->check;
excl_end[1] = (uint8_t*)(&ih->check + 1);
if (ih->protocol == IPPROTO_TCP) {
th = tcp_hdr(skb);
excl_start[4] = (uint8_t*)&th->check;
excl_end[4] = (uint8_t*)(&th->check + 1);
} else if (ih->protocol == IPPROTO_UDP) {
uh = udp_hdr(skb);
excl_start[4] = (uint8_t*)&uh->check;
excl_end[4] = (uint8_t*)(&uh->check + 1);
}
}
if (a != NULL) {
switch(a->type) {
case(OFPAT_SET_DL_SRC):
if (memcmp(a->arg.dl_addr, eh->h_source, sizeof eh->h_source) != 0) {
unit_fail("Source eth addr has not been set");
return;
}
excl_start[0] = (uint8_t*)(&eh->h_source);
excl_end[0] = (uint8_t*)(&eh->h_proto);
break;
case(OFPAT_SET_DL_DST):
if (memcmp(a->arg.dl_addr, eh->h_dest, sizeof eh->h_dest) != 0) {
unit_fail("Dest eth addr has not been set");
return;
}
excl_start[0] = (uint8_t*)(&eh->h_dest);
excl_end[0] = (uint8_t*)(&eh->h_source);
break;
case(OFPAT_SET_NW_SRC):
if (ih != NULL) {
if (a->arg.nw_addr != ih->saddr) {
unit_fail("Source IP addr has not been set");
return;
}
excl_start[2] = (uint8_t*)(&ih->saddr);
excl_end[2] = (uint8_t*)(&ih->saddr + 1);
}
break;
case(OFPAT_SET_NW_DST):
if (ih != NULL) {
if (a->arg.nw_addr != ih->daddr) {
unit_fail("Dest IP addr has not been set");
return;
}
excl_start[2] = (uint8_t*)(&ih->daddr);
excl_end[2] = (uint8_t*)(&ih->daddr + 1);
}
break;
case(OFPAT_SET_TP_SRC):
if (th != NULL) {
if (a->arg.tp != th->source) {
unit_fail("Source port has not been set");
return;
}
excl_start[3] = (uint8_t*)(&th->source);
excl_end[3] = (uint8_t*)(&th->source + 1);
} else if (uh != NULL) {
if (a->arg.tp != uh->source) {
unit_fail("Source port has not been set");
return;
}
excl_start[3] = (uint8_t*)(&uh->source);
excl_end[3] = (uint8_t*)(&uh->source + 1);
}
break;
case(OFPAT_SET_TP_DST):
if (th != NULL) {
if (a->arg.tp != th->dest) {
unit_fail("Dest port has not been set");
return;
}
excl_start[3] = (uint8_t*)(&th->dest);
excl_end[3] = (uint8_t*)(&th->dest + 1);
} else if (uh != NULL) {
if (a->arg.tp != uh->dest) {
unit_fail("Dest port has not been set");
return;
}
excl_start[3] = (uint8_t*)(&uh->dest);
excl_end[3] = (uint8_t*)(&uh->dest + 1);
}
break;
default:
BUG();
}
}
compare(skb->data, p->data, p->len, excl_start, excl_end, 5);
if (unit_failed())
return;
if (ih == NULL)
return;
check_IP_csum(ih);
if (unit_failed())
return;
if (th == NULL && uh == NULL)
return;
check_transport_csum(ih, th, uh);
}
/*
* Layers 3 & 4 Tests: Given packets in forward_t.h, executes all actions
* with random data, checking for consistency described in check_packet().
*/
void
test_l3_l4(void)
{
struct ofp_action action;
struct sk_buff *skb;
struct sw_flow_key key;
unsigned int i, j;
uint16_t eth_proto;
int ret = 0;
for (i = 0; i < num_packets; i++) {
skb = alloc_skb(packets[i].len, GFP_KERNEL);
if (!skb) {
unit_fail("Couldn't allocate %uth skb", i);
return;
}
memcpy(skb_put(skb, packets[i].len), packets[i].data,
packets[i].len);
skb_set_mac_header(skb, 0);
flow_extract(skb, 0, &key);
eth_proto = ntohs(key.dl_type);
check_packet(skb, NULL, packets+i);
if (unit_failed())
return;
for (action.type = OFPAT_SET_DL_SRC;
action.type <= OFPAT_SET_TP_DST;
action.type++)
{
set_action_data(skb, NULL, &action);
for(j = 0; j < 2; j++) {
skb = execute_setter(skb, eth_proto, &key, &action);
check_packet(skb, &action, packets+i);
if (unit_failed()) {
unit_fail("Packet %u inconsistent "
"after setter on action "
"type %d, iteration %u",
i, action.type, j);
return;
}
set_action_data(skb, &key, &action);
}
}
kfree_skb(skb);
if (ret != 0)
break;
}
}
int
test_vlan(void)
{
struct ofp_action action;
struct sk_buff *skb;
struct sw_flow_key key;
unsigned int i;
uint16_t eth_proto;
int ret = 0;
struct vlan_ethhdr *vh;
struct ethhdr *eh;
struct net_device dev;
uint16_t new_id, orig_id;
memset((char *)&dev, '\0', sizeof(dev));
printk("Testing vlan\n");
for (i = 0; i < num_packets; i++) {
skb = alloc_skb(packets[i].len, GFP_KERNEL);
if (!skb) {
unit_fail("Couldn't allocate %uth skb", i);
return -ENOMEM;
}
memcpy(skb_put(skb, packets[i].len), packets[i].data,
packets[i].len);
skb->dev = &dev;
skb_set_mac_header(skb, 0);
flow_extract(skb, 0, &key);
eth_proto = ntohs(key.dl_type);
#if 0
if ((ret = check_packet(skb, NULL, packets+i)) < 0) {
unit_fail("Packet %u has incorrect checksum unmodified",
i);
goto free_skb;
}
#endif
eh = eth_hdr(skb);
orig_id = eh->h_proto;
action.type = OFPAT_SET_DL_VLAN;
// Add a random vlan tag
new_id = (uint16_t) random32() & VLAN_VID_MASK;
action.arg.vlan_id = new_id;
skb = execute_setter(skb, eth_proto, &key, &action);
vh = vlan_eth_hdr(skb);
if (ntohs(vh->h_vlan_TCI) != new_id) {
unit_fail("add: vlan id doesn't match: %#x != %#x",
ntohs(vh->h_vlan_TCI), new_id);
return -1;
}
flow_extract(skb, 0, &key);
#if 0
if ((ret = check_packet(skb, NULL, packets+i)) < 0) {
unit_fail("Packet %u has incorrect checksum after adding vlan",
i);
goto free_skb;
}
#endif
// Modify the tag
new_id = (uint16_t) random32() & VLAN_VID_MASK;
action.arg.vlan_id = new_id;
skb = execute_setter(skb, eth_proto, &key, &action);
vh = vlan_eth_hdr(skb);
if (ntohs(vh->h_vlan_TCI) != new_id) {
unit_fail("mod: vlan id doesn't match: %#x != %#x",
ntohs(vh->h_vlan_TCI), new_id);
return -1;
}
flow_extract(skb, 0, &key);
#if 0
if ((ret = check_packet(skb, NULL, packets+i)) < 0) {
unit_fail("Packet %u has incorrect checksum after modifying vlan",
i);
goto free_skb;
}
#endif
// Remove the tag
action.arg.vlan_id = OFP_VLAN_NONE;
skb = execute_setter(skb, eth_proto, &key, &action);
eh = eth_hdr(skb);
if (eh->h_proto != orig_id) {
unit_fail("del: vlan id doesn't match: %#x != %#x",
ntohs(eh->h_proto), ntohs(orig_id));
return -1;
}
#if 0
if ((ret = check_packet(skb, NULL, packets+i)) < 0) {
unit_fail("Packet %u has incorrect checksum after removing vlan",
i);
goto free_skb;
}
free_skb:
#endif
kfree_skb(skb);
if (ret != 0)
break;
}
if (ret == 0)
printk("\nVLAN actions test passed.\n");
return ret;
}
/*
* Actual test: Given packets in forward_t.h, executes all actions with random
* data, checking for consistency described in check_packet().
*/
void
run_forward_t(void)
{
test_vlan();
test_l3_l4();
}
+19
View File
@@ -0,0 +1,19 @@
/Makefile
/datapath.c
/chain.c
/crc32.c
/crc_t.c
/dp_dev.c
/flow.c
/forward.c
/forward_t.c
/datapath_t.c
/kernel-src.inc
/table-hash.c
/table-linear.c
/table-mac.c
/table_t.c
/unit-exports.c
/unit.c
/kernel-src.inc
/tmp
+100
View File
@@ -0,0 +1,100 @@
export builddir = @abs_builddir@
export srcdir = @abs_srcdir@
export top_srcdir = @abs_top_srcdir@
export KSRC = @KSRC24@
export KVERSION = 2.4
export VMDIR = @VMDIR@
SHAREDFILES = ../chain.c ../crc32.c ../table-hash.c ../table-linear.c \
../table-mac.c ../forward.c ../flow.c ../unit-exports.c \
../dp_dev.c ../datapath_t.c
SIMLINKFILES = $(patsubst ../%,%, $(SHAREDFILES))
CFILES = datapath.c $(SIMLINKFILES)
# create local symlinks of shared files
%.c : ../%.c
ln -s $< $@
COMPAT24_CFILES = \
compat-2.4/random32.c \
compat-2.4/genetlink.c \
compat-2.4/netlink.c \
compat-2.4/attr.c \
compat-2.4/rcupdate.c \
compat-2.4/string.c \
compat-2.4/kernel.c \
compat-2.4/compat24.c
UNIT_CFILES = \
../table_t.c \
../unit.c
SHARED_T_FILES = \
../forward_t.c \
../table_t.c \
../crc_t.c \
../unit.c
UNIT_CFILES = $(patsubst ../%,%, $(SHARED_T_FILES))
kFILES = ../datapath.h \
../chain.h \
../crc32.h \
../flow.h \
../forward.h \
../table.h \
../datapath_t.h \
compat-2.4/include/linux/rcupdate.h \
compat-2.4/include/linux/jiffies.h \
compat-2.4/include/linux/ipv6.h \
compat-2.4/include/linux/timer.h \
compat-2.4/include/linux/if_vlan.h \
compat-2.4/include/linux/types.h \
compat-2.4/include/linux/skbuff.h \
compat-2.4/include/linux/etherdevice.h \
compat-2.4/include/linux/tcp.h \
compat-2.4/include/linux/genetlink.h \
compat-2.4/include/linux/sockios.h \
compat-2.4/include/linux/list.h \
compat-2.4/include/linux/udp.h \
compat-2.4/include/linux/slab.h \
compat-2.4/include/linux/random.h \
compat-2.4/include/linux/mutex.h \
compat-2.4/include/linux/ip.h \
compat-2.4/include/linux/string.h \
compat-2.4/include/linux/netlink.h \
compat-2.4/include/linux/compiler.h \
compat-2.4/include/linux/kernel.h \
compat-2.4/include/linux/if_ether.h \
compat-2.4/include/net/checksum.h \
compat-2.4/include/net/genetlink.h \
compat-2.4/include/net/netlink.h \
compat-2.4/include/asm/system.h \
compat-2.4/compat24.h
VERSION = @VERSION@
CFLAGS_EXTRA += -DVERSION=\"$(VERSION)\"
CFLAGS_EXTRA += -O2 -g
CFLAGS_EXTRA += -I $(srcdir)/.. -I $(top_srcdir)/include
# Conditional include so that make dist doesn't puke when
# this build isn't turned on by automake
ifneq (,$(KSRC))
include $(srcdir)/kbuild.inc
else
clean:
endif
distclean : clean
distdir : clean
install :
PWD := $(shell pwd)
all: default
check: all
+6
View File
@@ -0,0 +1,6 @@
Linux kernel 2.4 specific build:
- Backports: compat-2.4/genetlink.c is a back-port of the
Linux 2.6 Generic Netlink functionality. It must be loaded
as module genetlink_mod.o before openflow_mod.o may be
loaded.
+2
View File
@@ -0,0 +1,2 @@
* Properly port RCU to Linux 2.4. In particular we will need support
for call_rcu to properly do flow-table updating.
+436
View File
@@ -0,0 +1,436 @@
/*
* NETLINK Netlink attributes
*
* Authors: Thomas Graf <tgraf@suug.ch>
* Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/jiffies.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/string.h>
#include <linux/types.h>
#include <net/netlink.h>
static u16 nla_attr_minlen[NLA_TYPE_MAX+1] = {
[NLA_U8] = sizeof(u8),
[NLA_U16] = sizeof(u16),
[NLA_U32] = sizeof(u32),
[NLA_U64] = sizeof(u64),
[NLA_NESTED] = NLA_HDRLEN,
};
static int validate_nla(struct nlattr *nla, int maxtype,
const struct nla_policy *policy)
{
const struct nla_policy *pt;
int minlen = 0, attrlen = nla_len(nla);
if (nla->nla_type <= 0 || nla->nla_type > maxtype)
return 0;
pt = &policy[nla->nla_type];
BUG_ON(pt->type > NLA_TYPE_MAX);
switch (pt->type) {
case NLA_FLAG:
if (attrlen > 0)
return -ERANGE;
break;
case NLA_NUL_STRING:
if (pt->len)
minlen = min_t(int, attrlen, pt->len + 1);
else
minlen = attrlen;
if (!minlen || memchr(nla_data(nla), '\0', minlen) == NULL)
return -EINVAL;
/* fall through */
case NLA_STRING:
if (attrlen < 1)
return -ERANGE;
if (pt->len) {
char *buf = nla_data(nla);
if (buf[attrlen - 1] == '\0')
attrlen--;
if (attrlen > pt->len)
return -ERANGE;
}
break;
case NLA_BINARY:
if (pt->len && attrlen > pt->len)
return -ERANGE;
break;
default:
if (pt->len)
minlen = pt->len;
else if (pt->type != NLA_UNSPEC)
minlen = nla_attr_minlen[pt->type];
if (attrlen < minlen)
return -ERANGE;
}
return 0;
}
/**
* nla_validate - Validate a stream of attributes
* @head: head of attribute stream
* @len: length of attribute stream
* @maxtype: maximum attribute type to be expected
* @policy: validation policy
*
* Validates all attributes in the specified attribute stream against the
* specified policy. Attributes with a type exceeding maxtype will be
* ignored. See documenation of struct nla_policy for more details.
*
* Returns 0 on success or a negative error code.
*/
int nla_validate(struct nlattr *head, int len, int maxtype,
const struct nla_policy *policy)
{
struct nlattr *nla;
int rem, err;
nla_for_each_attr(nla, head, len, rem) {
err = validate_nla(nla, maxtype, policy);
if (err < 0)
goto errout;
}
err = 0;
errout:
return err;
}
/**
* nla_parse - Parse a stream of attributes into a tb buffer
* @tb: destination array with maxtype+1 elements
* @maxtype: maximum attribute type to be expected
* @head: head of attribute stream
* @len: length of attribute stream
*
* Parses a stream of attributes and stores a pointer to each attribute in
* the tb array accessable via the attribute type. Attributes with a type
* exceeding maxtype will be silently ignored for backwards compatibility
* reasons. policy may be set to NULL if no validation is required.
*
* Returns 0 on success or a negative error code.
*/
int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len,
const struct nla_policy *policy)
{
struct nlattr *nla;
int rem, err;
memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1));
nla_for_each_attr(nla, head, len, rem) {
u16 type = nla->nla_type;
if (type > 0 && type <= maxtype) {
if (policy) {
err = validate_nla(nla, maxtype, policy);
if (err < 0)
goto errout;
}
tb[type] = nla;
}
}
if (unlikely(rem > 0))
printk(KERN_WARNING "netlink: %d bytes leftover after parsing "
"attributes.\n", rem);
err = 0;
errout:
return err;
}
/**
* nla_find - Find a specific attribute in a stream of attributes
* @head: head of attribute stream
* @len: length of attribute stream
* @attrtype: type of attribute to look for
*
* Returns the first attribute in the stream matching the specified type.
*/
struct nlattr *nla_find(struct nlattr *head, int len, int attrtype)
{
struct nlattr *nla;
int rem;
nla_for_each_attr(nla, head, len, rem)
if (nla->nla_type == attrtype)
return nla;
return NULL;
}
/**
* nla_strlcpy - Copy string attribute payload into a sized buffer
* @dst: where to copy the string to
* @src: attribute to copy the string from
* @dstsize: size of destination buffer
*
* Copies at most dstsize - 1 bytes into the destination buffer.
* The result is always a valid NUL-terminated string. Unlike
* strlcpy the destination buffer is always padded out.
*
* Returns the length of the source buffer.
*/
size_t nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize)
{
size_t srclen = nla_len(nla);
char *src = nla_data(nla);
if (srclen > 0 && src[srclen - 1] == '\0')
srclen--;
if (dstsize > 0) {
size_t len = (srclen >= dstsize) ? dstsize - 1 : srclen;
memset(dst, 0, dstsize);
memcpy(dst, src, len);
}
return srclen;
}
/**
* nla_memcpy - Copy a netlink attribute into another memory area
* @dest: where to copy to memcpy
* @src: netlink attribute to copy from
* @count: size of the destination area
*
* Note: The number of bytes copied is limited by the length of
* attribute's payload. memcpy
*
* Returns the number of bytes copied.
*/
int nla_memcpy(void *dest, struct nlattr *src, int count)
{
int minlen = min_t(int, count, nla_len(src));
memcpy(dest, nla_data(src), minlen);
return minlen;
}
/**
* nla_memcmp - Compare an attribute with sized memory area
* @nla: netlink attribute
* @data: memory area
* @size: size of memory area
*/
int nla_memcmp(const struct nlattr *nla, const void *data,
size_t size)
{
int d = nla_len(nla) - size;
if (d == 0)
d = memcmp(nla_data(nla), data, size);
return d;
}
/**
* nla_strcmp - Compare a string attribute against a string
* @nla: netlink string attribute
* @str: another string
*/
int nla_strcmp(const struct nlattr *nla, const char *str)
{
int len = strlen(str) + 1;
int d = nla_len(nla) - len;
if (d == 0)
d = memcmp(nla_data(nla), str, len);
return d;
}
/**
* __nla_reserve - reserve room for attribute on the skb
* @skb: socket buffer to reserve room on
* @attrtype: attribute type
* @attrlen: length of attribute payload
*
* Adds a netlink attribute header to a socket buffer and reserves
* room for the payload but does not copy it.
*
* The caller is responsible to ensure that the skb provides enough
* tailroom for the attribute header and payload.
*/
struct nlattr *__nla_reserve(struct sk_buff *skb, int attrtype, int attrlen)
{
struct nlattr *nla;
nla = (struct nlattr *) skb_put(skb, nla_total_size(attrlen));
nla->nla_type = attrtype;
nla->nla_len = nla_attr_size(attrlen);
memset((unsigned char *) nla + nla->nla_len, 0, nla_padlen(attrlen));
return nla;
}
/**
* __nla_reserve_nohdr - reserve room for attribute without header
* @skb: socket buffer to reserve room on
* @attrlen: length of attribute payload
*
* Reserves room for attribute payload without a header.
*
* The caller is responsible to ensure that the skb provides enough
* tailroom for the payload.
*/
void *__nla_reserve_nohdr(struct sk_buff *skb, int attrlen)
{
void *start;
start = skb_put(skb, NLA_ALIGN(attrlen));
memset(start, 0, NLA_ALIGN(attrlen));
return start;
}
/**
* nla_reserve - reserve room for attribute on the skb
* @skb: socket buffer to reserve room on
* @attrtype: attribute type
* @attrlen: length of attribute payload
*
* Adds a netlink attribute header to a socket buffer and reserves
* room for the payload but does not copy it.
*
* Returns NULL if the tailroom of the skb is insufficient to store
* the attribute header and payload.
*/
struct nlattr *nla_reserve(struct sk_buff *skb, int attrtype, int attrlen)
{
if (unlikely(skb_tailroom(skb) < nla_total_size(attrlen)))
return NULL;
return __nla_reserve(skb, attrtype, attrlen);
}
/**
* nla_reserve - reserve room for attribute without header
* @skb: socket buffer to reserve room on
* @len: length of attribute payload
*
* Reserves room for attribute payload without a header.
*
* Returns NULL if the tailroom of the skb is insufficient to store
* the attribute payload.
*/
void *nla_reserve_nohdr(struct sk_buff *skb, int attrlen)
{
if (unlikely(skb_tailroom(skb) < NLA_ALIGN(attrlen)))
return NULL;
return __nla_reserve_nohdr(skb, attrlen);
}
/**
* __nla_put - Add a netlink attribute to a socket buffer
* @skb: socket buffer to add attribute to
* @attrtype: attribute type
* @attrlen: length of attribute payload
* @data: head of attribute payload
*
* The caller is responsible to ensure that the skb provides enough
* tailroom for the attribute header and payload.
*/
void __nla_put(struct sk_buff *skb, int attrtype, int attrlen,
const void *data)
{
struct nlattr *nla;
nla = __nla_reserve(skb, attrtype, attrlen);
memcpy(nla_data(nla), data, attrlen);
}
/**
* __nla_put_nohdr - Add a netlink attribute without header
* @skb: socket buffer to add attribute to
* @attrlen: length of attribute payload
* @data: head of attribute payload
*
* The caller is responsible to ensure that the skb provides enough
* tailroom for the attribute payload.
*/
void __nla_put_nohdr(struct sk_buff *skb, int attrlen, const void *data)
{
void *start;
start = __nla_reserve_nohdr(skb, attrlen);
memcpy(start, data, attrlen);
}
/**
* nla_put - Add a netlink attribute to a socket buffer
* @skb: socket buffer to add attribute to
* @attrtype: attribute type
* @attrlen: length of attribute payload
* @data: head of attribute payload
*
* Returns -1 if the tailroom of the skb is insufficient to store
* the attribute header and payload.
*/
int nla_put(struct sk_buff *skb, int attrtype, int attrlen, const void *data)
{
if (unlikely(skb_tailroom(skb) < nla_total_size(attrlen)))
return -1;
__nla_put(skb, attrtype, attrlen, data);
return 0;
}
/**
* nla_put_nohdr - Add a netlink attribute without header
* @skb: socket buffer to add attribute to
* @attrlen: length of attribute payload
* @data: head of attribute payload
*
* Returns -1 if the tailroom of the skb is insufficient to store
* the attribute payload.
*/
int nla_put_nohdr(struct sk_buff *skb, int attrlen, const void *data)
{
if (unlikely(skb_tailroom(skb) < NLA_ALIGN(attrlen)))
return -1;
__nla_put_nohdr(skb, attrlen, data);
return 0;
}
EXPORT_SYMBOL(nla_validate);
EXPORT_SYMBOL(nla_parse);
EXPORT_SYMBOL(nla_find);
EXPORT_SYMBOL(nla_strlcpy);
EXPORT_SYMBOL(__nla_reserve);
EXPORT_SYMBOL(__nla_reserve_nohdr);
EXPORT_SYMBOL(nla_reserve);
EXPORT_SYMBOL(nla_reserve_nohdr);
EXPORT_SYMBOL(__nla_put);
EXPORT_SYMBOL(__nla_put_nohdr);
EXPORT_SYMBOL(nla_put);
EXPORT_SYMBOL(nla_put_nohdr);
EXPORT_SYMBOL(nla_memcpy);
EXPORT_SYMBOL(nla_memcmp);
EXPORT_SYMBOL(nla_strcmp);
+27
View File
@@ -0,0 +1,27 @@
/*
* Distributed under the terms of the GNU GPL version 2.
*/
#include <linux/module.h>
#include "compat24.h"
int __init compat24_init(void)
{
int err;
rcu_init();
err = random32_init();
if (err)
return err;
return genl_init();
}
module_init(compat24_init);
void __exit compat24_exit(void)
{
genl_exit();
}
module_exit(compat24_exit);
+11
View File
@@ -0,0 +1,11 @@
#ifndef __COMPAT24_H
#define __COMPAT24_H 1
int genl_init(void);
void genl_exit(void);
int random32_init(void);
void rcu_init(void);
#endif /* compat24.h */
+810
View File
@@ -0,0 +1,810 @@
/*
* NETLINK Generic Netlink Family
*
* Authors: Jamal Hadi Salim
* Thomas Graf <tgraf@suug.ch>
* Johannes Berg <johannes@sipsolutions.net>
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/string.h>
#include <linux/skbuff.h>
#include <asm/semaphore.h>
#include <net/sock.h>
#include <net/genetlink.h>
#include "compat24.h"
struct sock *genl_sock = NULL;
static DECLARE_MUTEX(genl_mutex); /* serialization of message processing */
static void genl_lock(void)
{
down(&genl_mutex);
}
static int genl_trylock(void)
{
return down_trylock(&genl_mutex);
}
static void genl_unlock(void)
{
up(&genl_mutex);
if (genl_sock && genl_sock->receive_queue.qlen)
genl_sock->data_ready(genl_sock, 0);
}
#define GENL_FAM_TAB_SIZE 16
#define GENL_FAM_TAB_MASK (GENL_FAM_TAB_SIZE - 1)
static struct list_head family_ht[GENL_FAM_TAB_SIZE];
/*
* Bitmap of multicast groups that are currently in use.
*
* To avoid an allocation at boot of just one unsigned long,
* declare it global instead.
* Bit 0 is marked as already used since group 0 is invalid.
*/
static unsigned long mc_group_start = 0x1;
static unsigned long *mc_groups = &mc_group_start;
static unsigned long mc_groups_longs = 1;
static int genl_ctrl_event(int event, void *data);
static inline unsigned int genl_family_hash(unsigned int id)
{
return id & GENL_FAM_TAB_MASK;
}
static inline struct list_head *genl_family_chain(unsigned int id)
{
return &family_ht[genl_family_hash(id)];
}
static struct genl_family *genl_family_find_byid(unsigned int id)
{
struct genl_family *f;
list_for_each_entry(f, genl_family_chain(id), family_list)
if (f->id == id)
return f;
return NULL;
}
static struct genl_family *genl_family_find_byname(char *name)
{
struct genl_family *f;
int i;
for (i = 0; i < GENL_FAM_TAB_SIZE; i++)
list_for_each_entry(f, genl_family_chain(i), family_list)
if (strcmp(f->name, name) == 0)
return f;
return NULL;
}
static struct genl_ops *genl_get_cmd(u8 cmd, struct genl_family *family)
{
struct genl_ops *ops;
list_for_each_entry(ops, &family->ops_list, ops_list)
if (ops->cmd == cmd)
return ops;
return NULL;
}
/* Of course we are going to have problems once we hit
* 2^16 alive types, but that can only happen by year 2K
*/
static inline u16 genl_generate_id(void)
{
static u16 id_gen_idx;
int overflowed = 0;
do {
if (id_gen_idx == 0)
id_gen_idx = GENL_MIN_ID;
if (++id_gen_idx > GENL_MAX_ID) {
if (!overflowed) {
overflowed = 1;
id_gen_idx = 0;
continue;
} else
return 0;
}
} while (genl_family_find_byid(id_gen_idx));
return id_gen_idx;
}
static struct genl_multicast_group notify_grp;
/**
* genl_register_mc_group - register a multicast group
*
* Registers the specified multicast group and notifies userspace
* about the new group.
*
* Returns 0 on success or a negative error code.
*
* @family: The generic netlink family the group shall be registered for.
* @grp: The group to register, must have a name.
*/
int genl_register_mc_group(struct genl_family *family,
struct genl_multicast_group *grp)
{
int id;
BUG_ON(grp->name[0] == '\0');
genl_lock();
/* special-case our own group */
if (grp == &notify_grp)
id = GENL_ID_CTRL;
else
id = find_first_zero_bit(mc_groups,
mc_groups_longs * BITS_PER_LONG);
if (id >= mc_groups_longs * BITS_PER_LONG) {
genl_unlock();
return -ENOMEM;
}
grp->id = id;
set_bit(id, mc_groups);
list_add_tail(&grp->list, &family->mcast_groups);
grp->family = family;
genl_ctrl_event(CTRL_CMD_NEWMCAST_GRP, grp);
genl_unlock();
return 0;
}
EXPORT_SYMBOL(genl_register_mc_group);
static void __genl_unregister_mc_group(struct genl_family *family,
struct genl_multicast_group *grp)
{
BUG_ON(grp->family != family);
/* We should clear this multicast group from any subscribers, but 2.4
* doesn't have the proper interface to do it, and we'd need a patch to
* implement it. */
/*netlink_clear_multicast_users(genl_sock, grp->id);*/
clear_bit(grp->id, mc_groups);
list_del(&grp->list);
genl_ctrl_event(CTRL_CMD_DELMCAST_GRP, grp);
grp->id = 0;
grp->family = NULL;
}
/**
* genl_unregister_mc_group - unregister a multicast group
*
* Unregisters the specified multicast group and notifies userspace
* about it. All current listeners on the group are removed.
*
* Note: It is not necessary to unregister all multicast groups before
* unregistering the family, unregistering the family will cause
* all assigned multicast groups to be unregistered automatically.
*
* @family: Generic netlink family the group belongs to.
* @grp: The group to unregister, must have been registered successfully
* previously.
*/
void genl_unregister_mc_group(struct genl_family *family,
struct genl_multicast_group *grp)
{
genl_lock();
__genl_unregister_mc_group(family, grp);
genl_unlock();
}
EXPORT_SYMBOL(genl_unregister_mc_group);
static void genl_unregister_mc_groups(struct genl_family *family)
{
struct genl_multicast_group *grp, *tmp;
genl_lock();
list_for_each_entry_safe(grp, tmp, &family->mcast_groups, list)
__genl_unregister_mc_group(family, grp);
genl_unlock();
}
/**
* genl_register_ops - register generic netlink operations
* @family: generic netlink family
* @ops: operations to be registered
*
* Registers the specified operations and assigns them to the specified
* family. Either a doit or dumpit callback must be specified or the
* operation will fail. Only one operation structure per command
* identifier may be registered.
*
* See include/net/genetlink.h for more documenation on the operations
* structure.
*
* Returns 0 on success or a negative error code.
*/
int genl_register_ops(struct genl_family *family, struct genl_ops *ops)
{
int err = -EINVAL;
if (ops->dumpit == NULL && ops->doit == NULL)
goto errout;
if (genl_get_cmd(ops->cmd, family)) {
err = -EEXIST;
goto errout;
}
if (ops->dumpit)
ops->flags |= GENL_CMD_CAP_DUMP;
if (ops->doit)
ops->flags |= GENL_CMD_CAP_DO;
if (ops->policy)
ops->flags |= GENL_CMD_CAP_HASPOL;
genl_lock();
list_add_tail(&ops->ops_list, &family->ops_list);
genl_unlock();
genl_ctrl_event(CTRL_CMD_NEWOPS, ops);
err = 0;
errout:
return err;
}
/**
* genl_unregister_ops - unregister generic netlink operations
* @family: generic netlink family
* @ops: operations to be unregistered
*
* Unregisters the specified operations and unassigns them from the
* specified family. The operation blocks until the current message
* processing has finished and doesn't start again until the
* unregister process has finished.
*
* Note: It is not necessary to unregister all operations before
* unregistering the family, unregistering the family will cause
* all assigned operations to be unregistered automatically.
*
* Returns 0 on success or a negative error code.
*/
int genl_unregister_ops(struct genl_family *family, struct genl_ops *ops)
{
struct genl_ops *rc;
genl_lock();
list_for_each_entry(rc, &family->ops_list, ops_list) {
if (rc == ops) {
list_del(&ops->ops_list);
genl_unlock();
genl_ctrl_event(CTRL_CMD_DELOPS, ops);
return 0;
}
}
genl_unlock();
return -ENOENT;
}
/**
* genl_register_family - register a generic netlink family
* @family: generic netlink family
*
* Registers the specified family after validating it first. Only one
* family may be registered with the same family name or identifier.
* The family id may equal GENL_ID_GENERATE causing an unique id to
* be automatically generated and assigned.
*
* Return 0 on success or a negative error code.
*/
int genl_register_family(struct genl_family *family)
{
int err = -EINVAL;
if (family->id && family->id < GENL_MIN_ID)
goto errout;
if (family->id > GENL_MAX_ID)
goto errout;
INIT_LIST_HEAD(&family->ops_list);
INIT_LIST_HEAD(&family->mcast_groups);
genl_lock();
if (genl_family_find_byname(family->name)) {
err = -EEXIST;
goto errout_locked;
}
if (genl_family_find_byid(family->id)) {
err = -EEXIST;
goto errout_locked;
}
if (family->id == GENL_ID_GENERATE) {
u16 newid = genl_generate_id();
if (!newid) {
err = -ENOMEM;
goto errout_locked;
}
family->id = newid;
}
if (family->maxattr) {
family->attrbuf = kmalloc((family->maxattr+1) *
sizeof(struct nlattr *), GFP_KERNEL);
if (family->attrbuf == NULL) {
err = -ENOMEM;
goto errout_locked;
}
} else
family->attrbuf = NULL;
list_add_tail(&family->family_list, genl_family_chain(family->id));
MOD_INC_USE_COUNT;
genl_unlock();
genl_ctrl_event(CTRL_CMD_NEWFAMILY, family);
return 0;
errout_locked:
genl_unlock();
errout:
return err;
}
/**
* genl_unregister_family - unregister generic netlink family
* @family: generic netlink family
*
* Unregisters the specified family.
*
* Returns 0 on success or a negative error code.
*/
int genl_unregister_family(struct genl_family *family)
{
struct genl_family *rc;
genl_unregister_mc_groups(family);
genl_lock();
list_for_each_entry(rc, genl_family_chain(family->id), family_list) {
if (family->id != rc->id || strcmp(rc->name, family->name))
continue;
list_del(&rc->family_list);
INIT_LIST_HEAD(&family->ops_list);
genl_unlock();
kfree(family->attrbuf);
genl_ctrl_event(CTRL_CMD_DELFAMILY, family);
return 0;
}
MOD_DEC_USE_COUNT;
genl_unlock();
return -ENOENT;
}
static int null_done_func(struct netlink_callback *cb)
{
return 0;
}
static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct genl_ops *ops;
struct genl_family *family;
struct genl_info info;
struct genlmsghdr *hdr = nlmsg_data(nlh);
int hdrlen, err;
family = genl_family_find_byid(nlh->nlmsg_type);
if (family == NULL)
return -ENOENT;
hdrlen = GENL_HDRLEN + family->hdrsize;
if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
return -EINVAL;
ops = genl_get_cmd(hdr->cmd, family);
if (ops == NULL)
return -EOPNOTSUPP;
if ((ops->flags & GENL_ADMIN_PERM) && !capable(CAP_NET_ADMIN))
return -EPERM;
if (nlh->nlmsg_flags & NLM_F_DUMP) {
if (ops->dumpit == NULL)
return -EOPNOTSUPP;
return netlink_dump_start(genl_sock, skb, nlh,
ops->dumpit,
ops->done ?: null_done_func);
}
if (ops->doit == NULL)
return -EOPNOTSUPP;
if (family->attrbuf) {
err = nlmsg_parse(nlh, hdrlen, family->attrbuf, family->maxattr,
ops->policy);
if (err < 0)
return err;
}
info.snd_seq = nlh->nlmsg_seq;
info.snd_pid = NETLINK_CB(skb).pid;
info.nlhdr = nlh;
info.genlhdr = nlmsg_data(nlh);
info.userhdr = nlmsg_data(nlh) + GENL_HDRLEN;
info.attrs = family->attrbuf;
return ops->doit(skb, &info);
}
static void genl_rcv(struct sock *sk, int len)
{
unsigned int qlen = 0;
do {
if (genl_trylock())
return;
netlink_run_queue(sk, &qlen, genl_rcv_msg);
genl_unlock();
} while (qlen && genl_sock && genl_sock->receive_queue.qlen);
}
/**************************************************************************
* Controller
**************************************************************************/
static struct genl_family genl_ctrl = {
.id = GENL_ID_CTRL,
.name = "nlctrl",
.version = 0x2,
.maxattr = CTRL_ATTR_MAX,
};
static int ctrl_fill_info(struct genl_family *family, u32 pid, u32 seq,
u32 flags, struct sk_buff *skb, u8 cmd)
{
void *hdr;
hdr = genlmsg_put(skb, pid, seq, &genl_ctrl, flags, cmd);
if (hdr == NULL)
return -1;
NLA_PUT_STRING(skb, CTRL_ATTR_FAMILY_NAME, family->name);
NLA_PUT_U16(skb, CTRL_ATTR_FAMILY_ID, family->id);
NLA_PUT_U32(skb, CTRL_ATTR_VERSION, family->version);
NLA_PUT_U32(skb, CTRL_ATTR_HDRSIZE, family->hdrsize);
NLA_PUT_U32(skb, CTRL_ATTR_MAXATTR, family->maxattr);
if (!list_empty(&family->ops_list)) {
struct nlattr *nla_ops;
struct genl_ops *ops;
int idx = 1;
nla_ops = nla_nest_start(skb, CTRL_ATTR_OPS);
if (nla_ops == NULL)
goto nla_put_failure;
list_for_each_entry(ops, &family->ops_list, ops_list) {
struct nlattr *nest;
nest = nla_nest_start(skb, idx++);
if (nest == NULL)
goto nla_put_failure;
NLA_PUT_U32(skb, CTRL_ATTR_OP_ID, ops->cmd);
NLA_PUT_U32(skb, CTRL_ATTR_OP_FLAGS, ops->flags);
nla_nest_end(skb, nest);
}
nla_nest_end(skb, nla_ops);
}
if (!list_empty(&family->mcast_groups)) {
struct genl_multicast_group *grp;
struct nlattr *nla_grps;
int idx = 1;
nla_grps = nla_nest_start(skb, CTRL_ATTR_MCAST_GROUPS);
if (nla_grps == NULL)
goto nla_put_failure;
list_for_each_entry(grp, &family->mcast_groups, list) {
struct nlattr *nest;
nest = nla_nest_start(skb, idx++);
if (nest == NULL)
goto nla_put_failure;
NLA_PUT_U32(skb, CTRL_ATTR_MCAST_GRP_ID, grp->id);
NLA_PUT_STRING(skb, CTRL_ATTR_MCAST_GRP_NAME,
grp->name);
nla_nest_end(skb, nest);
}
nla_nest_end(skb, nla_grps);
}
return genlmsg_end(skb, hdr);
nla_put_failure:
return genlmsg_cancel(skb, hdr);
}
static int ctrl_fill_mcgrp_info(struct genl_multicast_group *grp, u32 pid,
u32 seq, u32 flags, struct sk_buff *skb,
u8 cmd)
{
void *hdr;
struct nlattr *nla_grps;
struct nlattr *nest;
hdr = genlmsg_put(skb, pid, seq, &genl_ctrl, flags, cmd);
if (hdr == NULL)
return -1;
NLA_PUT_STRING(skb, CTRL_ATTR_FAMILY_NAME, grp->family->name);
NLA_PUT_U16(skb, CTRL_ATTR_FAMILY_ID, grp->family->id);
nla_grps = nla_nest_start(skb, CTRL_ATTR_MCAST_GROUPS);
if (nla_grps == NULL)
goto nla_put_failure;
nest = nla_nest_start(skb, 1);
if (nest == NULL)
goto nla_put_failure;
NLA_PUT_U32(skb, CTRL_ATTR_MCAST_GRP_ID, grp->id);
NLA_PUT_STRING(skb, CTRL_ATTR_MCAST_GRP_NAME,
grp->name);
nla_nest_end(skb, nest);
nla_nest_end(skb, nla_grps);
return genlmsg_end(skb, hdr);
nla_put_failure:
return genlmsg_cancel(skb, hdr);
}
static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb)
{
int i, n = 0;
struct genl_family *rt;
int chains_to_skip = cb->args[0];
int fams_to_skip = cb->args[1];
if (chains_to_skip != 0)
genl_lock();
for (i = 0; i < GENL_FAM_TAB_SIZE; i++) {
if (i < chains_to_skip)
continue;
n = 0;
list_for_each_entry(rt, genl_family_chain(i), family_list) {
if (++n < fams_to_skip)
continue;
if (ctrl_fill_info(rt, NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq, NLM_F_MULTI,
skb, CTRL_CMD_NEWFAMILY) < 0)
goto errout;
}
fams_to_skip = 0;
}
errout:
if (chains_to_skip != 0)
genl_unlock();
cb->args[0] = i;
cb->args[1] = n;
return skb->len;
}
static struct sk_buff *ctrl_build_family_msg(struct genl_family *family,
u32 pid, int seq, u8 cmd)
{
struct sk_buff *skb;
int err;
skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (skb == NULL)
return ERR_PTR(-ENOBUFS);
err = ctrl_fill_info(family, pid, seq, 0, skb, cmd);
if (err < 0) {
nlmsg_free(skb);
return ERR_PTR(err);
}
return skb;
}
static struct sk_buff *ctrl_build_mcgrp_msg(struct genl_multicast_group *grp,
u32 pid, int seq, u8 cmd)
{
struct sk_buff *skb;
int err;
skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (skb == NULL)
return ERR_PTR(-ENOBUFS);
err = ctrl_fill_mcgrp_info(grp, pid, seq, 0, skb, cmd);
if (err < 0) {
nlmsg_free(skb);
return ERR_PTR(err);
}
return skb;
}
static const struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] = {
[CTRL_ATTR_FAMILY_ID] = { .type = NLA_U16 },
[CTRL_ATTR_FAMILY_NAME] = { .type = NLA_NUL_STRING,
.len = GENL_NAMSIZ - 1 },
};
static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info)
{
struct sk_buff *msg;
struct genl_family *res = NULL;
int err = -EINVAL;
if (info->attrs[CTRL_ATTR_FAMILY_ID]) {
u16 id = nla_get_u16(info->attrs[CTRL_ATTR_FAMILY_ID]);
res = genl_family_find_byid(id);
}
if (info->attrs[CTRL_ATTR_FAMILY_NAME]) {
char *name;
name = nla_data(info->attrs[CTRL_ATTR_FAMILY_NAME]);
res = genl_family_find_byname(name);
}
if (res == NULL) {
err = -ENOENT;
goto errout;
}
msg = ctrl_build_family_msg(res, info->snd_pid, info->snd_seq,
CTRL_CMD_NEWFAMILY);
if (IS_ERR(msg)) {
err = PTR_ERR(msg);
goto errout;
}
err = genlmsg_reply(msg, info);
errout:
return err;
}
static int genl_ctrl_event(int event, void *data)
{
struct sk_buff *msg;
if (genl_sock == NULL)
return 0;
switch (event) {
case CTRL_CMD_NEWFAMILY:
case CTRL_CMD_DELFAMILY:
msg = ctrl_build_family_msg(data, 0, 0, event);
if (IS_ERR(msg))
return PTR_ERR(msg);
genlmsg_multicast(msg, 0, GENL_ID_CTRL, GFP_KERNEL);
break;
case CTRL_CMD_NEWMCAST_GRP:
case CTRL_CMD_DELMCAST_GRP:
msg = ctrl_build_mcgrp_msg(data, 0, 0, event);
if (IS_ERR(msg))
return PTR_ERR(msg);
genlmsg_multicast(msg, 0, GENL_ID_CTRL, GFP_KERNEL);
break;
}
return 0;
}
static struct genl_ops genl_ctrl_ops = {
.cmd = CTRL_CMD_GETFAMILY,
.doit = ctrl_getfamily,
.dumpit = ctrl_dumpfamily,
.policy = ctrl_policy,
};
static struct genl_multicast_group notify_grp = {
.name = "notify",
};
int __init genl_init(void)
{
int i, err;
for (i = 0; i < GENL_FAM_TAB_SIZE; i++)
INIT_LIST_HEAD(&family_ht[i]);
err = genl_register_family(&genl_ctrl);
if (err < 0)
goto errout;
err = genl_register_ops(&genl_ctrl, &genl_ctrl_ops);
if (err < 0)
goto errout_register;
netlink_set_nonroot(NETLINK_GENERIC, NL_NONROOT_RECV);
genl_sock = netlink_kernel_create(NETLINK_GENERIC, genl_rcv);
if (genl_sock == NULL)
panic("GENL: Cannot initialize generic netlink\n");
err = genl_register_mc_group(&genl_ctrl, &notify_grp);
if (err < 0)
goto errout_register;
return 0;
errout_register:
genl_unregister_family(&genl_ctrl);
errout:
panic("GENL: Cannot register controller: %d\n", err);
}
void __exit genl_exit(void)
{
int err;
err = genl_unregister_ops(&genl_ctrl, &genl_ctrl_ops);
if (err) {
printk("GENL: cannot unregister ops (%d)\n", err);
return;
}
err = genl_unregister_family(&genl_ctrl);
if (err) {
printk("GENL: cannot unregister family (%d)\n", err);
return;
}
}
EXPORT_SYMBOL(genl_sock);
EXPORT_SYMBOL(genl_register_ops);
EXPORT_SYMBOL(genl_unregister_ops);
EXPORT_SYMBOL(genl_register_family);
EXPORT_SYMBOL(genl_unregister_family);
MODULE_LICENSE("GPL");
@@ -0,0 +1,56 @@
#ifndef __ASM_ARM_ATOMIC_H_WRAPPER
#define __ASM_ARM_ATOMIC_H_WRAPPER 1
#include_next <asm/atomic.h>
#error "Cribbed from linux-2.6/include/asm-arm/atomic.h but untested"
#ifdef __KERNEL__
#if __LINUX_ARM_ARCH__ >= 6
static inline int atomic_cmpxchg(atomic_t *ptr, int old, int new)
{
unsigned long oldval, res;
do {
__asm__ __volatile__("@ atomic_cmpxchg\n"
"ldrex %1, [%2]\n"
"mov %0, #0\n"
"teq %1, %3\n"
"strexeq %0, %4, [%2]\n"
: "=&r" (res), "=&r" (oldval)
: "r" (&ptr->counter), "Ir" (old), "r" (new)
: "cc");
} while (res);
return oldval;
}
#else /* ARM_ARCH_6 */
#include <asm/system.h>
#ifdef CONFIG_SMP
#error SMP not supported on pre-ARMv6 CPUs
#endif
static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
{
int ret;
unsigned long flags;
raw_local_irq_save(flags);
ret = v->counter;
if (likely(ret == old))
v->counter = new;
raw_local_irq_restore(flags);
return ret;
}
#endif /* __LINUX_ARM_ARCH__ */
#endif /* __KERNEL__ */
#endif /* asm/atomic.h */
@@ -0,0 +1,10 @@
#ifndef __ASM_I386_ATOMIC_WRAPPER_H
#define __ASM_I386_ATOMIC_WRAPPER_H 1
#include_next <asm/atomic.h>
#include <asm/system.h>
#define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), (old), (new)))
#endif /* atomic.h */
@@ -0,0 +1,11 @@
#ifndef __ASM_MIPS_ATOMIC_H_WRAPPER
#define __ASM_MIPS_ATOMIC_H_WRAPPER 1
#include_next <asm/atomic.h>
#include <asm/system.h>
#error "Cribbed from linux-2.6/include/asm-mips but not tested."
#define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n)))
#endif /* asm/atomic.h */
@@ -0,0 +1,29 @@
#ifndef __ASM_MIPS_BARRIER_H_WRAPPER
#define __ASM_MIPS_BARRIER_H_WRAPPER 1
#include <asm/system.h>
#error "Cribbed from linux-2.6/include/asm-mips/barrier.h but untested."
/* Not sure whether these really need to be defined, but the conservative
* choice seems to be to define them. */
#define CONFIG_WEAK_ORDERING 1
#define CONFIG_WEAK_REORDERING_BEYOND_LLSC 1
#if defined(CONFIG_WEAK_ORDERING) && defined(CONFIG_SMP)
#define __WEAK_ORDERING_MB " sync \n"
#else
#define __WEAK_ORDERING_MB " \n"
#endif
#if defined(CONFIG_WEAK_REORDERING_BEYOND_LLSC) && defined(CONFIG_SMP)
#define __WEAK_LLSC_MB " sync \n"
#else
#define __WEAK_LLSC_MB " \n"
#endif
#define smp_mb() __asm__ __volatile__(__WEAK_ORDERING_MB : : :"memory")
#define smp_rmb() __asm__ __volatile__(__WEAK_ORDERING_MB : : :"memory")
#define smp_wmb() __asm__ __volatile__(__WEAK_ORDERING_MB : : :"memory")
#endif /* asm/barrier.h */
@@ -0,0 +1,268 @@
#ifndef __ASM_MIPS_SYSTEM_H_WRAPPER
#define __ASM_MIPS_SYSTEM_H_WRAPPER 1
#include_next <asm/system.h>
#error "Cribbed from linux-2.6/include/asm-mips/system.h but untested."
#define __HAVE_ARCH_CMPXCHG 1
static inline unsigned long __cmpxchg_u32(volatile int * m, unsigned long old,
unsigned long new)
{
__u32 retval;
if (cpu_has_llsc && R10000_LLSC_WAR) {
__asm__ __volatile__(
" .set push \n"
" .set noat \n"
" .set mips3 \n"
"1: ll %0, %2 # __cmpxchg_u32 \n"
" bne %0, %z3, 2f \n"
" .set mips0 \n"
" move $1, %z4 \n"
" .set mips3 \n"
" sc $1, %1 \n"
" beqzl $1, 1b \n"
"2: \n"
" .set pop \n"
: "=&r" (retval), "=R" (*m)
: "R" (*m), "Jr" (old), "Jr" (new)
: "memory");
} else if (cpu_has_llsc) {
__asm__ __volatile__(
" .set push \n"
" .set noat \n"
" .set mips3 \n"
"1: ll %0, %2 # __cmpxchg_u32 \n"
" bne %0, %z3, 2f \n"
" .set mips0 \n"
" move $1, %z4 \n"
" .set mips3 \n"
" sc $1, %1 \n"
" beqz $1, 3f \n"
"2: \n"
" .subsection 2 \n"
"3: b 1b \n"
" .previous \n"
" .set pop \n"
: "=&r" (retval), "=R" (*m)
: "R" (*m), "Jr" (old), "Jr" (new)
: "memory");
} else {
unsigned long flags;
raw_local_irq_save(flags);
retval = *m;
if (retval == old)
*m = new;
raw_local_irq_restore(flags); /* implies memory barrier */
}
smp_llsc_mb();
return retval;
}
static inline unsigned long __cmpxchg_u32_local(volatile int * m,
unsigned long old, unsigned long new)
{
__u32 retval;
if (cpu_has_llsc && R10000_LLSC_WAR) {
__asm__ __volatile__(
" .set push \n"
" .set noat \n"
" .set mips3 \n"
"1: ll %0, %2 # __cmpxchg_u32 \n"
" bne %0, %z3, 2f \n"
" .set mips0 \n"
" move $1, %z4 \n"
" .set mips3 \n"
" sc $1, %1 \n"
" beqzl $1, 1b \n"
"2: \n"
" .set pop \n"
: "=&r" (retval), "=R" (*m)
: "R" (*m), "Jr" (old), "Jr" (new)
: "memory");
} else if (cpu_has_llsc) {
__asm__ __volatile__(
" .set push \n"
" .set noat \n"
" .set mips3 \n"
"1: ll %0, %2 # __cmpxchg_u32 \n"
" bne %0, %z3, 2f \n"
" .set mips0 \n"
" move $1, %z4 \n"
" .set mips3 \n"
" sc $1, %1 \n"
" beqz $1, 1b \n"
"2: \n"
" .set pop \n"
: "=&r" (retval), "=R" (*m)
: "R" (*m), "Jr" (old), "Jr" (new)
: "memory");
} else {
unsigned long flags;
local_irq_save(flags);
retval = *m;
if (retval == old)
*m = new;
local_irq_restore(flags); /* implies memory barrier */
}
return retval;
}
#ifdef CONFIG_64BIT
static inline unsigned long __cmpxchg_u64(volatile int * m, unsigned long old,
unsigned long new)
{
__u64 retval;
if (cpu_has_llsc && R10000_LLSC_WAR) {
__asm__ __volatile__(
" .set push \n"
" .set noat \n"
" .set mips3 \n"
"1: lld %0, %2 # __cmpxchg_u64 \n"
" bne %0, %z3, 2f \n"
" move $1, %z4 \n"
" scd $1, %1 \n"
" beqzl $1, 1b \n"
"2: \n"
" .set pop \n"
: "=&r" (retval), "=R" (*m)
: "R" (*m), "Jr" (old), "Jr" (new)
: "memory");
} else if (cpu_has_llsc) {
__asm__ __volatile__(
" .set push \n"
" .set noat \n"
" .set mips3 \n"
"1: lld %0, %2 # __cmpxchg_u64 \n"
" bne %0, %z3, 2f \n"
" move $1, %z4 \n"
" scd $1, %1 \n"
" beqz $1, 3f \n"
"2: \n"
" .subsection 2 \n"
"3: b 1b \n"
" .previous \n"
" .set pop \n"
: "=&r" (retval), "=R" (*m)
: "R" (*m), "Jr" (old), "Jr" (new)
: "memory");
} else {
unsigned long flags;
raw_local_irq_save(flags);
retval = *m;
if (retval == old)
*m = new;
raw_local_irq_restore(flags); /* implies memory barrier */
}
smp_llsc_mb();
return retval;
}
static inline unsigned long __cmpxchg_u64_local(volatile int * m,
unsigned long old, unsigned long new)
{
__u64 retval;
if (cpu_has_llsc && R10000_LLSC_WAR) {
__asm__ __volatile__(
" .set push \n"
" .set noat \n"
" .set mips3 \n"
"1: lld %0, %2 # __cmpxchg_u64 \n"
" bne %0, %z3, 2f \n"
" move $1, %z4 \n"
" scd $1, %1 \n"
" beqzl $1, 1b \n"
"2: \n"
" .set pop \n"
: "=&r" (retval), "=R" (*m)
: "R" (*m), "Jr" (old), "Jr" (new)
: "memory");
} else if (cpu_has_llsc) {
__asm__ __volatile__(
" .set push \n"
" .set noat \n"
" .set mips3 \n"
"1: lld %0, %2 # __cmpxchg_u64 \n"
" bne %0, %z3, 2f \n"
" move $1, %z4 \n"
" scd $1, %1 \n"
" beqz $1, 1b \n"
"2: \n"
" .set pop \n"
: "=&r" (retval), "=R" (*m)
: "R" (*m), "Jr" (old), "Jr" (new)
: "memory");
} else {
unsigned long flags;
local_irq_save(flags);
retval = *m;
if (retval == old)
*m = new;
local_irq_restore(flags); /* implies memory barrier */
}
return retval;
}
#else
extern unsigned long __cmpxchg_u64_unsupported_on_32bit_kernels(
volatile int * m, unsigned long old, unsigned long new);
#define __cmpxchg_u64 __cmpxchg_u64_unsupported_on_32bit_kernels
extern unsigned long __cmpxchg_u64_local_unsupported_on_32bit_kernels(
volatile int * m, unsigned long old, unsigned long new);
#define __cmpxchg_u64_local __cmpxchg_u64_local_unsupported_on_32bit_kernels
#endif
/* This function doesn't exist, so you'll get a linker error
if something tries to do an invalid cmpxchg(). */
extern void __cmpxchg_called_with_bad_pointer(void);
static inline unsigned long __cmpxchg(volatile void * ptr, unsigned long old,
unsigned long new, int size)
{
switch (size) {
case 4:
return __cmpxchg_u32(ptr, old, new);
case 8:
return __cmpxchg_u64(ptr, old, new);
}
__cmpxchg_called_with_bad_pointer();
return old;
}
static inline unsigned long __cmpxchg_local(volatile void * ptr,
unsigned long old, unsigned long new, int size)
{
switch (size) {
case 4:
return __cmpxchg_u32_local(ptr, old, new);
case 8:
return __cmpxchg_u64_local(ptr, old, new);
}
__cmpxchg_called_with_bad_pointer();
return old;
}
#define cmpxchg(ptr,old,new) \
((__typeof__(*(ptr)))__cmpxchg((ptr), \
(unsigned long)(old), (unsigned long)(new),sizeof(*(ptr))))
#define cmpxchg_local(ptr,old,new) \
((__typeof__(*(ptr)))__cmpxchg_local((ptr), \
(unsigned long)(old), (unsigned long)(new),sizeof(*(ptr))))
#endif /* asm/system.h */
@@ -0,0 +1,18 @@
#ifndef __ASM_SYSTEM_WRAPPER_H
#define __ASM_SYSTEM_WRAPPER_H 1
#include_next <asm/system.h>
#ifdef CONFIG_ALPHA
#define read_barrier_depends __asm__ __volatile__("mb": : :"memory")
#else
#define read_barrier_depends() do { } while(0)
#endif
#ifdef CONFIG_SMP
#define smp_read_barrier_depends() read_barrier_depends()
#else
#define smp_read_barrier_depends() do { } while(0)
#endif
#endif
@@ -0,0 +1,8 @@
#ifndef __LINUX_COMPILER_WRAPPER_H
#define __LINUX_COMPILER_WRAPPER_H
#include_next <linux/compiler.h>
# define __force
#endif
@@ -0,0 +1,59 @@
#ifndef __LINUX_DELAY_WRAPPER_H
#define __LINUX_DELAY_WRAPPER_H 1
#include_next <linux/delay.h>
#include <linux/version.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,29)
#include <linux/time.h>
#include <asm/param.h>
/*
* We define MAX_MSEC_OFFSET as the maximal value that can be accepted by
* msecs_to_jiffies() without risking a multiply overflow. This function
* returns MAX_JIFFY_OFFSET for arguments above those values.
*/
#if HZ <= 1000 && !(1000 % HZ)
# define MAX_MSEC_OFFSET \
(ULONG_MAX - (1000 / HZ) + 1)
#elif HZ > 1000 && !(HZ % 1000)
# define MAX_MSEC_OFFSET \
(ULONG_MAX / (HZ / 1000))
#else
# define MAX_MSEC_OFFSET \
((ULONG_MAX - 999) / HZ)
#endif
/*
* Convert jiffies to milliseconds and back.
*
* Avoid unnecessary multiplications/divisions in the
* two most common HZ cases:
*/
static inline unsigned int jiffies_to_msecs(const unsigned long j)
{
#if HZ <= 1000 && !(1000 % HZ)
return (1000 / HZ) * j;
#elif HZ > 1000 && !(HZ % 1000)
return (j + (HZ / 1000) - 1)/(HZ / 1000);
#else
return (j * 1000) / HZ;
#endif
}
static inline unsigned long msecs_to_jiffies(const unsigned int m)
{
if (MAX_MSEC_OFFSET < UINT_MAX && m > (unsigned int)MAX_MSEC_OFFSET)
return MAX_JIFFY_OFFSET;
#if HZ <= 1000 && !(1000 % HZ)
return ((unsigned long)m + (1000 / HZ) - 1) / (1000 / HZ);
#elif HZ > 1000 && !(HZ % 1000)
return (unsigned long)m * (HZ / 1000);
#else
return ((unsigned long)m * HZ + 999) / 1000;
#endif
}
#endif /* linux kernel < 2.6.29 */
#endif
@@ -0,0 +1,71 @@
#ifndef __LINUX_ETHERDEVICE_WRAPPER_H
#define __LINUX_ETHERDEVICE_WRAPPER_H 1
#include_next <linux/etherdevice.h>
#include <linux/random.h>
/**
* is_multicast_ether_addr - Determine if the Ethernet address is a multicast.
* @addr: Pointer to a six-byte array containing the Ethernet address
*
* Return true if the address is a multicast address.
* By definition the broadcast address is also a multicast address.
*/
static inline int is_multicast_ether_addr(const u8 *addr)
{
return (0x01 & addr[0]);
}
/**
* is_local_ether_addr - Determine if the Ethernet address is locally-assigned
* one (IEEE 802).
* @addr: Pointer to a six-byte array containing the Ethernet address
*
* Return true if the address is a local address.
*/
static inline int is_local_ether_addr(const u8 *addr)
{
return (0x02 & addr[0]);
}
/**
* is_broadcast_ether_addr - Determine if the Ethernet address is broadcast
* @addr: Pointer to a six-byte array containing the Ethernet address
*
* Return true if the address is the broadcast address.
*/
static inline int is_broadcast_ether_addr(const u8 *addr)
{
return (addr[0] & addr[1] & addr[2] & addr[3] & addr[4] & addr[5]) == 0xff;
}
/**
* random_ether_addr - Generate software assigned random Ethernet address
* @addr: Pointer to a six-byte array containing the Ethernet address
*
* Generate a random Ethernet address (MAC) that is not multicast
* and has the local assigned bit set.
*/
static inline void random_ether_addr(u8 *addr)
{
get_random_bytes (addr, ETH_ALEN);
addr [0] &= 0xfe; /* clear multicast bit */
addr [0] |= 0x02; /* set local assignment bit (IEEE802) */
}
/**
* compare_ether_addr - Compare two Ethernet addresses
* @addr1: Pointer to a six-byte array containing the Ethernet address
* @addr2: Pointer other six-byte array containing the Ethernet address
*
* Compare two ethernet addresses, returns 0 if equal
*/
static inline unsigned compare_ether_addr(const u8 *addr1, const u8 *addr2)
{
const u16 *a = (const u16 *) addr1;
const u16 *b = (const u16 *) addr2;
return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) != 0;
}
#endif
@@ -0,0 +1,82 @@
#ifndef __LINUX_GENERIC_NETLINK_H
#define __LINUX_GENERIC_NETLINK_H
#include <linux/netlink.h>
#define GENL_NAMSIZ 16 /* length of family name */
#define GENL_MIN_ID NLMSG_MIN_TYPE
#define GENL_MAX_ID 1023
struct genlmsghdr {
__u8 cmd;
__u8 version;
__u16 reserved;
};
#define GENL_HDRLEN NLMSG_ALIGN(sizeof(struct genlmsghdr))
#define GENL_ADMIN_PERM 0x01
#define GENL_CMD_CAP_DO 0x02
#define GENL_CMD_CAP_DUMP 0x04
#define GENL_CMD_CAP_HASPOL 0x08
/*
* List of reserved static generic netlink identifiers:
*/
#define GENL_ID_GENERATE 0
#define GENL_ID_CTRL NLMSG_MIN_TYPE
/**************************************************************************
* Controller
**************************************************************************/
enum {
CTRL_CMD_UNSPEC,
CTRL_CMD_NEWFAMILY,
CTRL_CMD_DELFAMILY,
CTRL_CMD_GETFAMILY,
CTRL_CMD_NEWOPS,
CTRL_CMD_DELOPS,
CTRL_CMD_GETOPS,
CTRL_CMD_NEWMCAST_GRP,
CTRL_CMD_DELMCAST_GRP,
CTRL_CMD_GETMCAST_GRP, /* unused */
__CTRL_CMD_MAX,
};
#define CTRL_CMD_MAX (__CTRL_CMD_MAX - 1)
enum {
CTRL_ATTR_UNSPEC,
CTRL_ATTR_FAMILY_ID,
CTRL_ATTR_FAMILY_NAME,
CTRL_ATTR_VERSION,
CTRL_ATTR_HDRSIZE,
CTRL_ATTR_MAXATTR,
CTRL_ATTR_OPS,
CTRL_ATTR_MCAST_GROUPS,
__CTRL_ATTR_MAX,
};
#define CTRL_ATTR_MAX (__CTRL_ATTR_MAX - 1)
enum {
CTRL_ATTR_OP_UNSPEC,
CTRL_ATTR_OP_ID,
CTRL_ATTR_OP_FLAGS,
__CTRL_ATTR_OP_MAX,
};
#define CTRL_ATTR_OP_MAX (__CTRL_ATTR_OP_MAX - 1)
enum {
CTRL_ATTR_MCAST_GRP_UNSPEC,
CTRL_ATTR_MCAST_GRP_NAME,
CTRL_ATTR_MCAST_GRP_ID,
__CTRL_ATTR_MCAST_GRP_MAX,
};
#define CTRL_ATTR_MCAST_GRP_MAX (__CTRL_ATTR_MCAST_GRP_MAX - 1)
#endif /* __LINUX_GENERIC_NETLINK_H */
@@ -0,0 +1,6 @@
#ifndef __LINUX_GFP_WRAPPER_H
#define __LINUX_GFP_WRAPPER_H 1
#include <linux/mm.h>
#endif /* linux/gfp.h */
@@ -0,0 +1,15 @@
#ifndef __LINUX_IF_ETHER_WRAPPER_H
#define __LINUX_IF_ETHER_WRAPPER_H 1
#include_next <linux/if_ether.h>
#ifdef __KERNEL__
#include <linux/skbuff.h>
static inline struct ethhdr *eth_hdr(const struct sk_buff *skb)
{
return (struct ethhdr *)skb_mac_header(skb);
}
#endif
#endif
@@ -0,0 +1,71 @@
#ifndef __LINUX_IF_VLAN_WRAPPER_H
#define __LINUX_IF_VLAN_WRAPPER_H 1
#include_next <linux/if_vlan.h>
#ifdef __KERNEL__
#include <linux/skbuff.h>
#include <linux/if_vlan.h>
#include <linux/version.h>
static inline struct vlan_ethhdr *vlan_eth_hdr(const struct sk_buff *skb)
{
return (struct vlan_ethhdr *)skb_mac_header(skb);
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,26)
static inline struct sk_buff *vlan_put_tag(struct sk_buff *skb, unsigned short tag)
{
struct vlan_ethhdr *veth;
if (skb_headroom(skb) < VLAN_HLEN) {
struct sk_buff *sk_tmp = skb;
skb = skb_realloc_headroom(sk_tmp, VLAN_HLEN);
kfree_skb(sk_tmp);
if (!skb) {
printk(KERN_ERR "vlan: failed to realloc headroom\n");
return NULL;
}
} else {
skb = skb_unshare(skb, GFP_ATOMIC);
if (!skb) {
printk(KERN_ERR "vlan: failed to unshare skbuff\n");
return NULL;
}
}
veth = (struct vlan_ethhdr *)skb_push(skb, VLAN_HLEN);
/* Move the mac addresses to the beginning of the new header. */
memmove(skb->data, skb->data + VLAN_HLEN, 2 * VLAN_ETH_ALEN);
/* first, the ethernet type */
veth->h_vlan_proto = __constant_htons(ETH_P_8021Q);
/* now, the tag */
veth->h_vlan_TCI = htons(tag);
skb_reset_mac_header(skb);
return skb;
}
#else
#define vlan_put_tag(x,y) fix_vlan_put_tag((x),(y));
/* For some reason, older versions of vlan_put_tag do not adjust the
* pointer to the beginning of the MAC header. We get around that by
* this hack. Ugh. */
static inline struct sk_buff *fix_vlan_put_tag(struct sk_buff *skb, unsigned short tag)
{
skb = (vlan_put_tag)(skb, tag);
skb_reset_mac_header(skb);
return skb;
}
#endif
#endif
#endif
@@ -0,0 +1,15 @@
#ifndef __LINUX_IP_WRAPPER_H
#define __LINUX_IP_WRAPPER_H 1
#include_next <linux/ip.h>
#ifdef __KERNEL__
#include <linux/skbuff.h>
static inline struct iphdr *ip_hdr(const struct sk_buff *skb)
{
return (struct iphdr *)skb_network_header(skb);
}
#endif
#endif
@@ -0,0 +1,11 @@
#ifndef __LINUX_IPV6_WRAPPER_H
#define __LINUX_IPV6_WRAPPER_H 1
#include_next <linux/ipv6.h>
static inline struct ipv6hdr *ipv6_hdr(const struct sk_buff *skb)
{
return (struct ipv6hdr *)skb_network_header(skb);
}
#endif
@@ -0,0 +1,10 @@
#ifndef __LINUX_JIFFIES_WRAPPER_H
#define __LINUX_JIFFIES_WRAPPER_H 1
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/timer.h>
extern unsigned long volatile jiffies;
#endif
@@ -0,0 +1,43 @@
#ifndef __LINUX_KERNEL_WRAPPER_H
#define __LINUX_KERNEL_WRAPPER_H 1
#include_next <linux/kernel.h>
/**
* container_of - cast a member of a structure out to the containing structure
* @ptr: the pointer to the member.
* @type: the type of the container struct this is embedded in.
* @member: the name of the member within the struct.
*
*/
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
/*
* Check at compile time that something is of a particular type.
* Always evaluates to 1 so you may use it easily in comparisons.
*/
#define typecheck(type,x) \
({ type __dummy; \
typeof(x) __dummy2; \
(void)(&__dummy == &__dummy2); \
1; \
})
/*
* Check at compile time that 'function' is a certain type, or is a pointer
* to that type (needs to use typedef for the function type.)
*/
#define typecheck_fn(type,function) \
({ typeof(type) __tmp = function; \
(void)__tmp; \
})
int vprintk(const char *msg, ...)
__attribute__((format(printf, 1, 0)));
/* Force a compilation error if condition is true */
#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
#endif
@@ -0,0 +1,510 @@
#ifndef __LINUX_LIST_WRAPPER_H
#define __LINUX_LIST_WRAPPER_H
#ifdef __KERNEL__
#include_next <linux/list.h>
#include <asm/system.h>
#define LIST_POISON1 ((void *) 0x00100100)
#define LIST_POISON2 ((void *) 0x00200200)
/*
* Insert a new entry between two known consecutive entries.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_add_rcu(struct list_head * new,
struct list_head * prev, struct list_head * next)
{
new->next = next;
new->prev = prev;
smp_wmb();
next->prev = new;
prev->next = new;
}
/**
* list_add_rcu - add a new entry to rcu-protected list
* @new: new entry to be added
* @head: list head to add it after
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*
* The caller must take whatever precautions are necessary
* (such as holding appropriate locks) to avoid racing
* with another list-mutation primitive, such as list_add_rcu()
* or list_del_rcu(), running on this same list.
* However, it is perfectly legal to run concurrently with
* the _rcu list-traversal primitives, such as
* list_for_each_entry_rcu().
*/
static inline void list_add_rcu(struct list_head *new, struct list_head *head)
{
__list_add_rcu(new, head, head->next);
}
/**
* list_add_tail_rcu - add a new entry to rcu-protected list
* @new: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*
* The caller must take whatever precautions are necessary
* (such as holding appropriate locks) to avoid racing
* with another list-mutation primitive, such as list_add_tail_rcu()
* or list_del_rcu(), running on this same list.
* However, it is perfectly legal to run concurrently with
* the _rcu list-traversal primitives, such as
* list_for_each_entry_rcu().
*/
static inline void list_add_tail_rcu(struct list_head *new,
struct list_head *head)
{
__list_add_rcu(new, head->prev, head);
}
/**
* list_del_rcu - deletes entry from list without re-initialization
* @entry: the element to delete from the list.
*
* Note: list_empty() on entry does not return true after this,
* the entry is in an undefined state. It is useful for RCU based
* lockfree traversal.
*
* In particular, it means that we can not poison the forward
* pointers that may still be used for walking the list.
*
* The caller must take whatever precautions are necessary
* (such as holding appropriate locks) to avoid racing
* with another list-mutation primitive, such as list_del_rcu()
* or list_add_rcu(), running on this same list.
* However, it is perfectly legal to run concurrently with
* the _rcu list-traversal primitives, such as
* list_for_each_entry_rcu().
*
* Note that the caller is not permitted to immediately free
* the newly deleted entry. Instead, either synchronize_rcu()
* or call_rcu() must be used to defer freeing until an RCU
* grace period has elapsed.
*/
static inline void list_del_rcu(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
entry->prev = LIST_POISON2;
}
/**
* list_replace_rcu - replace old entry by new one
* @old : the element to be replaced
* @new : the new element to insert
*
* The @old entry will be replaced with the @new entry atomically.
* Note: @old should not be empty.
*/
static inline void list_replace_rcu(struct list_head *old,
struct list_head *new)
{
new->next = old->next;
new->prev = old->prev;
smp_wmb();
new->next->prev = new;
new->prev->next = new;
old->prev = LIST_POISON2;
}
/**
* list_for_each_rcu - iterate over an rcu-protected list
* @pos: the &struct list_head to use as a loop cursor.
* @head: the head for your list.
*
* This list-traversal primitive may safely run concurrently with
* the _rcu list-mutation primitives such as list_add_rcu()
* as long as the traversal is guarded by rcu_read_lock().
*/
#define list_for_each_rcu(pos, head) \
for (pos = (head)->next; \
prefetch(rcu_dereference(pos)->next), pos != (head); \
pos = pos->next)
#define __list_for_each_rcu(pos, head) \
for (pos = (head)->next; \
rcu_dereference(pos) != (head); \
pos = pos->next)
/**
* list_for_each_safe_rcu
* @pos: the &struct list_head to use as a loop cursor.
* @n: another &struct list_head to use as temporary storage
* @head: the head for your list.
*
* Iterate over an rcu-protected list, safe against removal of list entry.
*
* This list-traversal primitive may safely run concurrently with
* the _rcu list-mutation primitives such as list_add_rcu()
* as long as the traversal is guarded by rcu_read_lock().
*/
#define list_for_each_safe_rcu(pos, n, head) \
for (pos = (head)->next; \
n = rcu_dereference(pos)->next, pos != (head); \
pos = n)
/**
* list_for_each_entry_rcu - iterate over rcu list of given type
* @pos: the type * to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*
* This list-traversal primitive may safely run concurrently with
* the _rcu list-mutation primitives such as list_add_rcu()
* as long as the traversal is guarded by rcu_read_lock().
*/
#define list_for_each_entry_rcu(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
prefetch(rcu_dereference(pos)->member.next), \
&pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
/**
* list_for_each_continue_rcu
* @pos: the &struct list_head to use as a loop cursor.
* @head: the head for your list.
*
* Iterate over an rcu-protected list, continuing after current point.
*
* This list-traversal primitive may safely run concurrently with
* the _rcu list-mutation primitives such as list_add_rcu()
* as long as the traversal is guarded by rcu_read_lock().
*/
#define list_for_each_continue_rcu(pos, head) \
for ((pos) = (pos)->next; \
prefetch(rcu_dereference((pos))->next), (pos) != (head); \
(pos) = (pos)->next)
/*
* Double linked lists with a single pointer list head.
* Mostly useful for hash tables where the two pointer list head is
* too wasteful.
* You lose the ability to access the tail in O(1).
*/
struct hlist_head {
struct hlist_node *first;
};
struct hlist_node {
struct hlist_node *next, **pprev;
};
#define HLIST_HEAD_INIT { .first = NULL }
#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
static inline void INIT_HLIST_NODE(struct hlist_node *h)
{
h->next = NULL;
h->pprev = NULL;
}
static inline int hlist_unhashed(const struct hlist_node *h)
{
return !h->pprev;
}
static inline int hlist_empty(const struct hlist_head *h)
{
return !h->first;
}
static inline void __hlist_del(struct hlist_node *n)
{
struct hlist_node *next = n->next;
struct hlist_node **pprev = n->pprev;
*pprev = next;
if (next)
next->pprev = pprev;
}
static inline void hlist_del(struct hlist_node *n)
{
__hlist_del(n);
n->next = LIST_POISON1;
n->pprev = LIST_POISON2;
}
/**
* hlist_del_rcu - deletes entry from hash list without re-initialization
* @n: the element to delete from the hash list.
*
* Note: list_unhashed() on entry does not return true after this,
* the entry is in an undefined state. It is useful for RCU based
* lockfree traversal.
*
* In particular, it means that we can not poison the forward
* pointers that may still be used for walking the hash list.
*
* The caller must take whatever precautions are necessary
* (such as holding appropriate locks) to avoid racing
* with another list-mutation primitive, such as hlist_add_head_rcu()
* or hlist_del_rcu(), running on this same list.
* However, it is perfectly legal to run concurrently with
* the _rcu list-traversal primitives, such as
* hlist_for_each_entry().
*/
static inline void hlist_del_rcu(struct hlist_node *n)
{
__hlist_del(n);
n->pprev = LIST_POISON2;
}
static inline void hlist_del_init(struct hlist_node *n)
{
if (!hlist_unhashed(n)) {
__hlist_del(n);
INIT_HLIST_NODE(n);
}
}
/**
* hlist_replace_rcu - replace old entry by new one
* @old : the element to be replaced
* @new : the new element to insert
*
* The @old entry will be replaced with the @new entry atomically.
*/
static inline void hlist_replace_rcu(struct hlist_node *old,
struct hlist_node *new)
{
struct hlist_node *next = old->next;
new->next = next;
new->pprev = old->pprev;
smp_wmb();
if (next)
new->next->pprev = &new->next;
*new->pprev = new;
old->pprev = LIST_POISON2;
}
static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
{
struct hlist_node *first = h->first;
n->next = first;
if (first)
first->pprev = &n->next;
h->first = n;
n->pprev = &h->first;
}
/**
* hlist_add_head_rcu
* @n: the element to add to the hash list.
* @h: the list to add to.
*
* Description:
* Adds the specified element to the specified hlist,
* while permitting racing traversals.
*
* The caller must take whatever precautions are necessary
* (such as holding appropriate locks) to avoid racing
* with another list-mutation primitive, such as hlist_add_head_rcu()
* or hlist_del_rcu(), running on this same list.
* However, it is perfectly legal to run concurrently with
* the _rcu list-traversal primitives, such as
* hlist_for_each_entry_rcu(), used to prevent memory-consistency
* problems on Alpha CPUs. Regardless of the type of CPU, the
* list-traversal primitive must be guarded by rcu_read_lock().
*/
static inline void hlist_add_head_rcu(struct hlist_node *n,
struct hlist_head *h)
{
struct hlist_node *first = h->first;
n->next = first;
n->pprev = &h->first;
smp_wmb();
if (first)
first->pprev = &n->next;
h->first = n;
}
/* next must be != NULL */
static inline void hlist_add_before(struct hlist_node *n,
struct hlist_node *next)
{
n->pprev = next->pprev;
n->next = next;
next->pprev = &n->next;
*(n->pprev) = n;
}
static inline void hlist_add_after(struct hlist_node *n,
struct hlist_node *next)
{
next->next = n->next;
n->next = next;
next->pprev = &n->next;
if(next->next)
next->next->pprev = &next->next;
}
/**
* hlist_add_before_rcu
* @n: the new element to add to the hash list.
* @next: the existing element to add the new element before.
*
* Description:
* Adds the specified element to the specified hlist
* before the specified node while permitting racing traversals.
*
* The caller must take whatever precautions are necessary
* (such as holding appropriate locks) to avoid racing
* with another list-mutation primitive, such as hlist_add_head_rcu()
* or hlist_del_rcu(), running on this same list.
* However, it is perfectly legal to run concurrently with
* the _rcu list-traversal primitives, such as
* hlist_for_each_entry_rcu(), used to prevent memory-consistency
* problems on Alpha CPUs.
*/
static inline void hlist_add_before_rcu(struct hlist_node *n,
struct hlist_node *next)
{
n->pprev = next->pprev;
n->next = next;
smp_wmb();
next->pprev = &n->next;
*(n->pprev) = n;
}
/**
* hlist_add_after_rcu
* @prev: the existing element to add the new element after.
* @n: the new element to add to the hash list.
*
* Description:
* Adds the specified element to the specified hlist
* after the specified node while permitting racing traversals.
*
* The caller must take whatever precautions are necessary
* (such as holding appropriate locks) to avoid racing
* with another list-mutation primitive, such as hlist_add_head_rcu()
* or hlist_del_rcu(), running on this same list.
* However, it is perfectly legal to run concurrently with
* the _rcu list-traversal primitives, such as
* hlist_for_each_entry_rcu(), used to prevent memory-consistency
* problems on Alpha CPUs.
*/
static inline void hlist_add_after_rcu(struct hlist_node *prev,
struct hlist_node *n)
{
n->next = prev->next;
n->pprev = &prev->next;
smp_wmb();
prev->next = n;
if (n->next)
n->next->pprev = &n->next;
}
#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
#define hlist_for_each(pos, head) \
for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \
pos = pos->next)
#define hlist_for_each_safe(pos, n, head) \
for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
pos = n)
/**
* hlist_for_each_entry - iterate over list of given type
* @tpos: the type * to use as a loop cursor.
* @pos: the &struct hlist_node to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the hlist_node within the struct.
*/
#define hlist_for_each_entry(tpos, pos, head, member) \
for (pos = (head)->first; \
pos && ({ prefetch(pos->next); 1;}) && \
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
pos = pos->next)
/**
* hlist_for_each_entry_continue - iterate over a hlist continuing after current point
* @tpos: the type * to use as a loop cursor.
* @pos: the &struct hlist_node to use as a loop cursor.
* @member: the name of the hlist_node within the struct.
*/
#define hlist_for_each_entry_continue(tpos, pos, member) \
for (pos = (pos)->next; \
pos && ({ prefetch(pos->next); 1;}) && \
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
pos = pos->next)
/**
* hlist_for_each_entry_from - iterate over a hlist continuing from current point
* @tpos: the type * to use as a loop cursor.
* @pos: the &struct hlist_node to use as a loop cursor.
* @member: the name of the hlist_node within the struct.
*/
#define hlist_for_each_entry_from(tpos, pos, member) \
for (; pos && ({ prefetch(pos->next); 1;}) && \
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
pos = pos->next)
/**
* hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
* @tpos: the type * to use as a loop cursor.
* @pos: the &struct hlist_node to use as a loop cursor.
* @n: another &struct hlist_node to use as temporary storage
* @head: the head for your list.
* @member: the name of the hlist_node within the struct.
*/
#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \
for (pos = (head)->first; \
pos && ({ n = pos->next; 1; }) && \
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
pos = n)
/**
* hlist_for_each_entry_rcu - iterate over rcu list of given type
* @tpos: the type * to use as a loop cursor.
* @pos: the &struct hlist_node to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the hlist_node within the struct.
*
* This list-traversal primitive may safely run concurrently with
* the _rcu list-mutation primitives such as hlist_add_head_rcu()
* as long as the traversal is guarded by rcu_read_lock().
*/
#define hlist_for_each_entry_rcu(tpos, pos, head, member) \
for (pos = (head)->first; \
rcu_dereference(pos) && ({ prefetch(pos->next); 1;}) && \
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
pos = pos->next)
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,23)
/**
* list_for_each_entry_safe - iterate over list of given type safe against remov
al of list entry
* @pos: the type * to use as a loop counter.
* @n: another type * to use as temporary storage
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry_safe(pos, n, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member), \
n = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
#endif /* linux kernel < 2.4.23 */
#else
#warning "don't include kernel headers in userspace"
#endif /* __KERNEL__ */
#endif
@@ -0,0 +1,19 @@
#ifndef __LINUX_MODULE_WRAPPER_H
#define __LINUX_MODULE_WRAPPER_H 1
#include_next <linux/module.h>
static inline int try_module_get(struct module *module)
{
BUG_ON(module != THIS_MODULE);
MOD_INC_USE_COUNT;
return 1;
}
static inline void module_put(struct module *module)
{
BUG_ON(module != THIS_MODULE);
MOD_DEC_USE_COUNT;
}
#endif /* module.h */
@@ -0,0 +1,58 @@
#ifndef __LINUX_MUTEX_H
#define __LINUX_MUTEX_H
#include <asm/semaphore.h>
struct mutex {
struct semaphore sema;
};
#define mutex_init(mutex) init_MUTEX(&mutex->sema)
#define mutex_destroy(mutex) do { } while (0)
#define DEFINE_MUTEX(mutexname) \
struct mutex mutexname = { __MUTEX_INITIALIZER(mutexname.sema) }
/**
* mutex_is_locked - is the mutex locked
* @lock: the mutex to be queried
*
* Returns 1 if the mutex is locked, 0 if unlocked.
*/
static inline int mutex_is_locked(struct mutex *lock)
{
return sem_getcount(&lock->sema) == 0;
}
/*
* See kernel/mutex.c for detailed documentation of these APIs.
* Also see Documentation/mutex-design.txt.
*/
static inline void mutex_lock(struct mutex *lock)
{
down(&lock->sema);
}
static inline int mutex_lock_interruptible(struct mutex *lock)
{
return down_interruptible(&lock->sema);
}
#define mutex_lock_nested(lock, subclass) mutex_lock(lock)
#define mutex_lock_interruptible_nested(lock, subclass) mutex_lock_interruptible(lock)
/*
* NOTE: mutex_trylock() follows the spin_trylock() convention,
* not the down_trylock() convention!
*/
static inline int mutex_trylock(struct mutex *lock)
{
return !down_trylock(&lock->sema);
}
static inline void mutex_unlock(struct mutex *lock)
{
up(&lock->sema);
}
#endif
@@ -0,0 +1,31 @@
#ifndef __LINUX_NETDEVICE_WRAPPER_H
#define __LINUX_NETDEVICE_WRAPPER_H 1
#include_next <linux/netdevice.h>
/*----------------------------------------------------------------------------
* In 2.6.24, a namespace argument became required for dev_get_by_name.
*/
#define net_init NULL
#ifdef dev_get_by_name
#undef dev_get_by_name
#define dev_get_by_name(net, name) \
compat_dev_get_by_name((name))
static inline struct net_device *compat_dev_get_by_name(const char *name)
{
return (_set_ver(dev_get_by_name))(name);
}
#else
#define dev_get_by_name(net, name) \
dev_get_by_name((name))
#endif /* dev_get_by_name */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,27)
static inline void *netdev_priv(struct net_device *dev)
{
return dev->priv;
}
#endif
#endif
@@ -0,0 +1,78 @@
#ifndef __LINUX_NETLINK_WRAPPER_H
#define __LINUX_NETLINK_WRAPPER_H 1
#include_next <linux/netlink.h>
#define NETLINK_GENERIC 16
#undef NLMSG_LENGTH
#define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
#define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(NLMSG_HDRLEN))
#define NLMSG_MIN_TYPE 0x10 /* < 0x10: reserved control messages */
enum {
NETLINK_UNCONNECTED = 0,
NETLINK_CONNECTED,
};
/*
* <------- NLA_HDRLEN ------> <-- NLA_ALIGN(payload)-->
* +---------------------+- - -+- - - - - - - - - -+- - -+
* | Header | Pad | Payload | Pad |
* | (struct nlattr) | ing | | ing |
* +---------------------+- - -+- - - - - - - - - -+- - -+
* <-------------- nlattr->nla_len -------------->
*/
struct nlattr
{
__u16 nla_len;
__u16 nla_type;
};
#define NLA_ALIGNTO 4
#define NLA_ALIGN(len) (((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1))
#define NLA_HDRLEN ((int) NLA_ALIGN(sizeof(struct nlattr)))
#ifdef __KERNEL__
#include <linux/capability.h>
#include <linux/skbuff.h>
static inline struct nlmsghdr *nlmsg_hdr(const struct sk_buff *skb)
{
return (struct nlmsghdr *)skb->data;
}
#define __nlmsg_put __rpl_nlmsg_put
static __inline__ struct nlmsghdr *
__nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, int type, int len, int flags)
{
struct nlmsghdr *nlh;
int size = NLMSG_LENGTH(len);
nlh = (struct nlmsghdr*)skb_put(skb, NLMSG_ALIGN(size));
nlh->nlmsg_type = type;
nlh->nlmsg_len = size;
nlh->nlmsg_flags = flags;
nlh->nlmsg_pid = pid;
nlh->nlmsg_seq = seq;
memset(NLMSG_DATA(nlh) + len, 0, NLMSG_ALIGN(size) - size);
return nlh;
}
#define NLMSG_DEFAULT_SIZE (NLMSG_GOODSIZE - NLMSG_HDRLEN)
#undef NLMSG_NEW
#define NLMSG_NEW(skb, pid, seq, type, len, flags) \
({ if (skb_tailroom(skb) < (int)NLMSG_SPACE(len)) \
goto nlmsg_failure; \
__nlmsg_put(skb, pid, seq, type, len, flags); })
#endif
#undef NLMSG_PUT
#define NLMSG_PUT(skb, pid, seq, type, len) \
NLMSG_NEW(skb, pid, seq, type, len, 0)
#endif
@@ -0,0 +1,11 @@
#ifndef __LINUX_RANDOM_WRAPPER_H
#define __LINUX_RANDOM_WRAPPER_H 1
#include_next <linux/random.h>
#ifdef __KERNEL__
u32 random32(void);
void srandom32(u32 seed);
#endif
#endif
@@ -0,0 +1,205 @@
/*
* Read-Copy Update mechanism for mutual exclusion
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Copyright (C) IBM Corporation, 2001
*
* Author: Dipankar Sarma <dipankar@in.ibm.com>
*
* Based on the original work by Paul McKenney <paulmck@us.ibm.com>
* and inputs from Rusty Russell, Andrea Arcangeli and Andi Kleen.
* Papers:
* http://www.rdrop.com/users/paulmck/paper/rclockpdcsproof.pdf
* http://lse.sourceforge.net/locking/rclock_OLS.2001.05.01c.sc.pdf (OLS2001)
*
* For detailed explanation of Read-Copy Update mechanism see -
* http://lse.sourceforge.net/locking/rcupdate.html
*
*/
#ifndef __LINUX_RCUPDATE_H
#define __LINUX_RCUPDATE_H
#ifdef __KERNEL__
#include <linux/config.h>
#include <linux/cache.h>
#include <linux/spinlock.h>
#include <linux/threads.h>
#ifdef CONFIG_SMP
#error "SMP configurations not supported for RCU backport."
#endif
/**
* struct rcu_head - callback structure for use with RCU
* @next: next update requests in a list
* @func: actual update function to call after the grace period.
*/
struct rcu_head {
struct rcu_head *next;
void (*func)(struct rcu_head *head);
};
#define RCU_HEAD_INIT { }
#define RCU_HEAD(head) struct rcu_head head = RCU_HEAD_INIT
#define INIT_RCU_HEAD(ptr) do { } while (0)
/**
* rcu_read_lock - mark the beginning of an RCU read-side critical section.
*
* When synchronize_rcu() is invoked on one CPU while other CPUs
* are within RCU read-side critical sections, then the
* synchronize_rcu() is guaranteed to block until after all the other
* CPUs exit their critical sections. Similarly, if call_rcu() is invoked
* on one CPU while other CPUs are within RCU read-side critical
* sections, invocation of the corresponding RCU callback is deferred
* until after the all the other CPUs exit their critical sections.
*
* Note, however, that RCU callbacks are permitted to run concurrently
* with RCU read-side critical sections. One way that this can happen
* is via the following sequence of events: (1) CPU 0 enters an RCU
* read-side critical section, (2) CPU 1 invokes call_rcu() to register
* an RCU callback, (3) CPU 0 exits the RCU read-side critical section,
* (4) CPU 2 enters a RCU read-side critical section, (5) the RCU
* callback is invoked. This is legal, because the RCU read-side critical
* section that was running concurrently with the call_rcu() (and which
* therefore might be referencing something that the corresponding RCU
* callback would free up) has completed before the corresponding
* RCU callback is invoked.
*
* RCU read-side critical sections may be nested. Any deferred actions
* will be deferred until the outermost RCU read-side critical section
* completes.
*
* It is illegal to block while in an RCU read-side critical section.
*/
#define rcu_read_lock() \
do { } while(0)
/**
* rcu_read_unlock - marks the end of an RCU read-side critical section.
*
* See rcu_read_lock() for more information.
*/
#define rcu_read_unlock() \
do { } while(0)
/*
* So where is rcu_write_lock()? It does not exist, as there is no
* way for writers to lock out RCU readers. This is a feature, not
* a bug -- this property is what provides RCU's performance benefits.
* Of course, writers must coordinate with each other. The normal
* spinlock primitives work well for this, but any other technique may be
* used as well. RCU does not care how the writers keep out of each
* others' way, as long as they do so.
*/
/**
* rcu_read_lock_bh - mark the beginning of a softirq-only RCU critical section
*
* This is equivalent of rcu_read_lock(), but to be used when updates
* are being done using call_rcu_bh(). Since call_rcu_bh() callbacks
* consider completion of a softirq handler to be a quiescent state,
* a process in RCU read-side critical section must be protected by
* disabling softirqs. Read-side critical sections in interrupt context
* can use just rcu_read_lock().
*
*/
#define rcu_read_lock_bh() \
do { \
local_bh_disable(); \
} while(0)
/*
* rcu_read_unlock_bh - marks the end of a softirq-only RCU critical section
*
* See rcu_read_lock_bh() for more information.
*/
#define rcu_read_unlock_bh() \
do { \
local_bh_enable(); \
} while(0)
/**
* rcu_dereference - fetch an RCU-protected pointer in an
* RCU read-side critical section. This pointer may later
* be safely dereferenced.
*
* Inserts memory barriers on architectures that require them
* (currently only the Alpha), and, more importantly, documents
* exactly which pointers are protected by RCU.
*/
#define rcu_dereference(p) ({ \
typeof(p) _________p1 = p; \
smp_read_barrier_depends(); \
(_________p1); \
})
/**
* rcu_assign_pointer - assign (publicize) a pointer to a newly
* initialized structure that will be dereferenced by RCU read-side
* critical sections. Returns the value assigned.
*
* Inserts memory barriers on architectures that require them
* (pretty much all of them other than x86), and also prevents
* the compiler from reordering the code that initializes the
* structure after the pointer assignment. More importantly, this
* call documents which pointers will be dereferenced by RCU read-side
* code.
*/
#define rcu_assign_pointer(p, v) ({ \
smp_wmb(); \
(p) = (v); \
})
/**
* synchronize_sched - block until all CPUs have exited any non-preemptive
* kernel code sequences.
*
* This means that all preempt_disable code sequences, including NMI and
* hardware-interrupt handlers, in progress on entry will have completed
* before this primitive returns. However, this does not guarantee that
* softirq handlers will have completed, since in some kernels, these
* handlers can run in process context, and can block.
*
* This primitive provides the guarantees made by the (now removed)
* synchronize_kernel() API. In contrast, synchronize_rcu() only
* guarantees that rcu_read_lock() sections will have completed.
* In "classic RCU", these two guarantees happen to be one and
* the same, but can differ in realtime RCU implementations.
*/
#define synchronize_sched() synchronize_rcu()
/* Exported interfaces */
void synchronize_rcu(void);
void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *head));
static inline void call_rcu_bh(struct rcu_head *head,
void (*func)(struct rcu_head *head))
{
synchronize_rcu();
func(head);
}
void synchronize_idle(void);
extern void rcu_barrier(void);
#endif /* __KERNEL__ */
#endif /* __LINUX_RCUPDATE_H */
@@ -0,0 +1,130 @@
#ifndef __LINUX_SKBUFF_WRAPPER_H
#define __LINUX_SKBUFF_WRAPPER_H 1
#include_next <linux/skbuff.h>
#define mac_header mac.raw
#define network_header nh.raw
/* Emulate Linux 2.6 behavior, in which kfree_skb silently ignores null pointer
* arguments. */
#define kfree_skb(skb) kfree_skb_maybe_null(skb)
static inline void kfree_skb_maybe_null(struct sk_buff *skb)
{
if (likely(skb != NULL))
(kfree_skb)(skb);
}
/* Note that CHECKSUM_PARTIAL is not implemented, but this allows us to at
* least test against it: see update_csum() in forward.c. */
#define CHECKSUM_PARTIAL 3
#define CHECKSUM_COMPLETE CHECKSUM_HW
static inline unsigned char *skb_transport_header(const struct sk_buff *skb)
{
return skb->h.raw;
}
static inline void skb_reset_transport_header(struct sk_buff *skb)
{
skb->h.raw = skb->data;
}
static inline void skb_set_transport_header(struct sk_buff *skb,
const int offset)
{
skb->h.raw = skb->data + offset;
}
static inline unsigned char *skb_network_header(const struct sk_buff *skb)
{
return skb->nh.raw;
}
static inline void skb_reset_network_header(struct sk_buff *skb)
{
skb->nh.raw = skb->data;
}
static inline void skb_set_network_header(struct sk_buff *skb, const int offset)
{
skb->nh.raw = skb->data + offset;
}
static inline unsigned char *skb_mac_header(const struct sk_buff *skb)
{
return skb->mac.raw;
}
static inline int skb_mac_header_was_set(const struct sk_buff *skb)
{
return skb->mac.raw != NULL;
}
static inline void skb_reset_mac_header(struct sk_buff *skb)
{
skb->mac.raw = skb->data;
}
static inline void skb_set_mac_header(struct sk_buff *skb, const int offset)
{
skb->mac.raw = skb->data + offset;
}
static inline int skb_transport_offset(const struct sk_buff *skb)
{
return skb_transport_header(skb) - skb->data;
}
static inline u32 skb_network_header_len(const struct sk_buff *skb)
{
return skb->h.raw - skb->nh.raw;
}
static inline int skb_network_offset(const struct sk_buff *skb)
{
return skb_network_header(skb) - skb->data;
}
static inline unsigned char *skb_tail_pointer(const struct sk_buff *skb)
{
return skb->tail;
}
static inline void skb_reset_tail_pointer(struct sk_buff *skb)
{
skb->tail = skb->data;
}
static inline void skb_set_tail_pointer(struct sk_buff *skb, const int offset)
{
skb->tail = skb->data + offset;
}
/*
* CPUs often take a performance hit when accessing unaligned memory
* locations. The actual performance hit varies, it can be small if the
* hardware handles it or large if we have to take an exception and fix it
* in software.
*
* Since an ethernet header is 14 bytes network drivers often end up with
* the IP header at an unaligned offset. The IP header can be aligned by
* shifting the start of the packet by 2 bytes. Drivers should do this
* with:
*
* skb_reserve(NET_IP_ALIGN);
*
* The downside to this alignment of the IP header is that the DMA is now
* unaligned. On some architectures the cost of an unaligned DMA is high
* and this cost outweighs the gains made by aligning the IP header.
*
* Since this trade off varies between architectures, we allow NET_IP_ALIGN
* to be overridden.
*/
#ifndef NET_IP_ALIGN
#define NET_IP_ALIGN 2
#endif
#endif
@@ -0,0 +1,44 @@
#ifndef __LINUX_SLAB_WRAPPER_H
#define __LINUX_SLAB_WRAPPER_H 1
/* Kluge to let "struct kmem_cache" work in both 2.4 and 2.6. */
#define kmem_cache_s kmem_cache
#include_next <linux/slab.h>
static inline void *kzalloc(size_t size, gfp_t flags)
{
void *p = kmalloc(size, flags);
if (p)
memset(p, 0, size);
return p;
}
/* Mega-kluge to wrap 2.4 kmem_cache_create for compatibility with 2.6. */
#ifdef kmem_cache_create
#undef kmem_cache_create
#define kmem_cache_create(name, size, align, flags, ctor) \
compat_kmem_cache_create(name, size, align, flags, ctor)
static inline struct kmem_cache *
compat_kmem_cache_create(const char *name, size_t size,
size_t align, unsigned long flags,
void (*ctor)(void *, struct kmem_cache *,
unsigned long))
{
return (_set_ver(kmem_cache_create))(name, size, align, flags, ctor,
NULL);
}
#else
#define kmem_cache_create(name, size, align, flags, ctor) \
kmem_cache_create(name, size, align, flags, ctor, NULL)
#endif /* kmem_cache_create */
static inline void *kmem_cache_zalloc(struct kmem_cache *k, gfp_t flags)
{
void *p = kmem_cache_alloc(k, flags);
if (p)
memset(p, 0, kmem_cache_size(k));
return p;
}
#endif
@@ -0,0 +1,12 @@
#ifndef __LINUX_SOCKIOS_WRAPPER_H
#define __LINUX_SOCKIOS_WRAPPER_H 1
#include_next <linux/sockios.h>
/* bridge calls */
#define SIOCBRADDBR 0x89a0 /* create new bridge device */
#define SIOCBRDELBR 0x89a1 /* remove bridge device */
#define SIOCBRADDIF 0x89a2 /* add interface to bridge */
#define SIOCBRDELIF 0x89a3 /* remove interface from bridge */
#endif
@@ -0,0 +1,8 @@
#ifndef __LINUX_SPINLOCK_WRAPPER_H
#define __LINUX_SPINLOCK_WRAPPER_H 1
#include_next <linux/spinlock.h>
#define DEFINE_SPINLOCK(x) spinlock_t x = SPIN_LOCK_UNLOCKED
#endif /* linux/spinlock.h */
@@ -0,0 +1,10 @@
#ifndef __LINUX_STRING_WRAPPER_H
#define __LINUX_STRING_WRAPPER_H 1
#include_next <linux/string.h>
#ifndef __HAVE_ARCH_STRCSPN
size_t strcspn(const char *s, const char *reject);
#endif
#endif /* linux/string.h */
@@ -0,0 +1,25 @@
#ifndef __LINUX_TCP_WRAPPER_H
#define __LINUX_TCP_WRAPPER_H 1
#include_next <linux/tcp.h>
#ifdef __KERNEL__
#include <linux/skbuff.h>
static inline struct tcphdr *tcp_hdr(const struct sk_buff *skb)
{
return (struct tcphdr *)skb_transport_header(skb);
}
static inline unsigned int tcp_hdrlen(const struct sk_buff *skb)
{
return tcp_hdr(skb)->doff * 4;
}
static inline unsigned int tcp_optlen(const struct sk_buff *skb)
{
return (tcp_hdr(skb)->doff - 5) * 4;
}
#endif
#endif
@@ -0,0 +1,96 @@
#ifndef __LINUX_TIMER_WRAPPER_H
#define __LINUX_TIMER_WRAPPER_H 1
#include_next <linux/timer.h>
#include <asm/param.h>
#include <linux/smp.h>
extern unsigned long volatile jiffies;
static inline void setup_timer(struct timer_list * timer,
void (*function)(unsigned long),
unsigned long data)
{
timer->function = function;
timer->data = data;
init_timer(timer);
}
/**
* __round_jiffies - function to round jiffies to a full second
* @j: the time in (absolute) jiffies that should be rounded
* @cpu: the processor number on which the timeout will happen
*
* __round_jiffies() rounds an absolute time in the future (in jiffies)
* up or down to (approximately) full seconds. This is useful for timers
* for which the exact time they fire does not matter too much, as long as
* they fire approximately every X seconds.
*
* By rounding these timers to whole seconds, all such timers will fire
* at the same time, rather than at various times spread out. The goal
* of this is to have the CPU wake up less, which saves power.
*
* The exact rounding is skewed for each processor to avoid all
* processors firing at the exact same time, which could lead
* to lock contention or spurious cache line bouncing.
*
* The return value is the rounded version of the @j parameter.
*/
static inline unsigned long __round_jiffies(unsigned long j, int cpu)
{
int rem;
unsigned long original = j;
/*
* We don't want all cpus firing their timers at once hitting the
* same lock or cachelines, so we skew each extra cpu with an extra
* 3 jiffies. This 3 jiffies came originally from the mm/ code which
* already did this.
* The skew is done by adding 3*cpunr, then round, then subtract this
* extra offset again.
*/
j += cpu * 3;
rem = j % HZ;
/*
* If the target jiffie is just after a whole second (which can happen
* due to delays of the timer irq, long irq off times etc etc) then
* we should round down to the whole second, not up. Use 1/4th second
* as cutoff for this rounding as an extreme upper bound for this.
*/
if (rem < HZ/4) /* round down */
j = j - rem;
else /* round up */
j = j - rem + HZ;
/* now that we have rounded, subtract the extra skew again */
j -= cpu * 3;
if (j <= jiffies) /* rounding ate our timeout entirely; */
return original;
return j;
}
/**
* round_jiffies - function to round jiffies to a full second
* @j: the time in (absolute) jiffies that should be rounded
*
* round_jiffies() rounds an absolute time in the future (in jiffies)
* up or down to (approximately) full seconds. This is useful for timers
* for which the exact time they fire does not matter too much, as long as
* they fire approximately every X seconds.
*
* By rounding these timers to whole seconds, all such timers will fire
* at the same time, rather than at various times spread out. The goal
* of this is to have the CPU wake up less, which saves power.
*
* The return value is the rounded version of the @j parameter.
*/
static inline unsigned long round_jiffies(unsigned long j)
{
return __round_jiffies(j, 0); // FIXME
}
#endif
@@ -0,0 +1,49 @@
#ifndef __LINUX_TYPES_WRAPPER_H
#define __LINUX_TYPES_WRAPPER_H 1
#include <linux/version.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
#error These replacement header files are for use with Linux 2.4.x only.
#endif
#include_next <linux/types.h>
/*
* Below are truly Linux-specific types that should never collide with
* any application/library that wants linux/types.h.
*/
#ifdef __CHECKER__
#define __bitwise__ __attribute__((bitwise))
#else
#define __bitwise__
#endif
#ifdef __CHECK_ENDIAN__
#define __bitwise __bitwise__
#else
#define __bitwise
#endif
typedef __u16 __bitwise __le16;
typedef __u16 __bitwise __be16;
typedef __u32 __bitwise __le32;
typedef __u32 __bitwise __be32;
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
typedef __u64 __bitwise __le64;
typedef __u64 __bitwise __be64;
#endif
typedef __u16 __bitwise __sum16;
typedef __u32 __bitwise __wsum;
#ifdef __KERNEL__
typedef unsigned __bitwise__ gfp_t;
#ifdef CONFIG_RESOURCES_64BIT
typedef u64 resource_size_t;
#else
typedef u32 resource_size_t;
#endif
#endif /* __KERNEL__ */
#endif
@@ -0,0 +1,15 @@
#ifndef __LINUX_UDP_WRAPPER_H
#define __LINUX_UDP_WRAPPER_H 1
#include_next <linux/udp.h>
#ifdef __KERNEL__
#include <linux/skbuff.h>
static inline struct udphdr *udp_hdr(const struct sk_buff *skb)
{
return (struct udphdr *)skb_transport_header(skb);
}
#endif
#endif
@@ -0,0 +1,11 @@
#ifndef __NET_CHECKSUM_WRAPPER_H
#define __NET_CHECKSUM_WRAPPER_H 1
#include_next <net/checksum.h>
static inline __wsum csum_unfold(__sum16 n)
{
return (__force __wsum)n;
}
#endif
@@ -0,0 +1,252 @@
#ifndef __NET_GENERIC_NETLINK_H
#define __NET_GENERIC_NETLINK_H
#include <linux/genetlink.h>
#include <net/netlink.h>
/**
* struct genl_multicast_group - generic netlink multicast group
* @name: name of the multicast group, names are per-family
* @id: multicast group ID, assigned by the core, to use with
* genlmsg_multicast().
* @list: list entry for linking
* @family: pointer to family, need not be set before registering
*/
struct genl_multicast_group
{
struct genl_family *family; /* private */
struct list_head list; /* private */
char name[GENL_NAMSIZ];
u32 id;
};
/**
* struct genl_family - generic netlink family
* @id: protocol family idenfitier
* @hdrsize: length of user specific header in bytes
* @name: name of family
* @version: protocol version
* @maxattr: maximum number of attributes supported
* @attrbuf: buffer to store parsed attributes
* @ops_list: list of all assigned operations
* @family_list: family list
* @mcast_groups: multicast groups list
*/
struct genl_family
{
unsigned int id;
unsigned int hdrsize;
char name[GENL_NAMSIZ];
unsigned int version;
unsigned int maxattr;
struct nlattr ** attrbuf; /* private */
struct list_head ops_list; /* private */
struct list_head family_list; /* private */
struct list_head mcast_groups; /* private */
};
/**
* struct genl_info - receiving information
* @snd_seq: sending sequence number
* @snd_pid: netlink pid of sender
* @nlhdr: netlink message header
* @genlhdr: generic netlink message header
* @userhdr: user specific header
* @attrs: netlink attributes
*/
struct genl_info
{
u32 snd_seq;
u32 snd_pid;
struct nlmsghdr * nlhdr;
struct genlmsghdr * genlhdr;
void * userhdr;
struct nlattr ** attrs;
};
/**
* struct genl_ops - generic netlink operations
* @cmd: command identifier
* @flags: flags
* @policy: attribute validation policy
* @doit: standard command callback
* @dumpit: callback for dumpers
* @done: completion callback for dumps
* @ops_list: operations list
*/
struct genl_ops
{
u8 cmd;
unsigned int flags;
const struct nla_policy *policy;
int (*doit)(struct sk_buff *skb,
struct genl_info *info);
int (*dumpit)(struct sk_buff *skb,
struct netlink_callback *cb);
int (*done)(struct netlink_callback *cb);
struct list_head ops_list;
};
extern int genl_register_family(struct genl_family *family);
extern int genl_unregister_family(struct genl_family *family);
extern int genl_register_ops(struct genl_family *, struct genl_ops *ops);
extern int genl_unregister_ops(struct genl_family *, struct genl_ops *ops);
extern int genl_register_mc_group(struct genl_family *family,
struct genl_multicast_group *grp);
extern void genl_unregister_mc_group(struct genl_family *family,
struct genl_multicast_group *grp);
extern struct sock *genl_sock;
/**
* genlmsg_put - Add generic netlink header to netlink message
* @skb: socket buffer holding the message
* @pid: netlink pid the message is addressed to
* @seq: sequence number (usually the one of the sender)
* @family: generic netlink family
* @flags netlink message flags
* @cmd: generic netlink command
*
* Returns pointer to user specific header
*/
static inline void *genlmsg_put(struct sk_buff *skb, u32 pid, u32 seq,
struct genl_family *family, int flags, u8 cmd)
{
struct nlmsghdr *nlh;
struct genlmsghdr *hdr;
nlh = nlmsg_put(skb, pid, seq, family->id, GENL_HDRLEN +
family->hdrsize, flags);
if (nlh == NULL)
return NULL;
hdr = nlmsg_data(nlh);
hdr->cmd = cmd;
hdr->version = family->version;
hdr->reserved = 0;
return (char *) hdr + GENL_HDRLEN;
}
/**
* genlmsg_put_reply - Add generic netlink header to a reply message
* @skb: socket buffer holding the message
* @info: receiver info
* @family: generic netlink family
* @flags: netlink message flags
* @cmd: generic netlink command
*
* Returns pointer to user specific header
*/
static inline void *genlmsg_put_reply(struct sk_buff *skb,
struct genl_info *info,
struct genl_family *family,
int flags, u8 cmd)
{
return genlmsg_put(skb, info->snd_pid, info->snd_seq, family,
flags, cmd);
}
/**
* genlmsg_end - Finalize a generic netlink message
* @skb: socket buffer the message is stored in
* @hdr: user specific header
*/
static inline int genlmsg_end(struct sk_buff *skb, void *hdr)
{
return nlmsg_end(skb, hdr - GENL_HDRLEN - NLMSG_HDRLEN);
}
/**
* genlmsg_cancel - Cancel construction of a generic netlink message
* @skb: socket buffer the message is stored in
* @hdr: generic netlink message header
*/
static inline int genlmsg_cancel(struct sk_buff *skb, void *hdr)
{
return nlmsg_cancel(skb, hdr - GENL_HDRLEN - NLMSG_HDRLEN);
}
/**
* genlmsg_multicast - multicast a netlink message
* @skb: netlink message as socket buffer
* @pid: own netlink pid to avoid sending to yourself
* @group: multicast group id
* @flags: allocation flags
*/
static inline int genlmsg_multicast(struct sk_buff *skb, u32 pid,
unsigned int group, gfp_t flags)
{
return nlmsg_multicast(genl_sock, skb, pid, group, flags);
}
/**
* genlmsg_unicast - unicast a netlink message
* @skb: netlink message as socket buffer
* @pid: netlink pid of the destination socket
*/
static inline int genlmsg_unicast(struct sk_buff *skb, u32 pid)
{
return nlmsg_unicast(genl_sock, skb, pid);
}
/**
* genlmsg_reply - reply to a request
* @skb: netlink message to be sent back
* @info: receiver information
*/
static inline int genlmsg_reply(struct sk_buff *skb, struct genl_info *info)
{
return genlmsg_unicast(skb, info->snd_pid);
}
/**
* gennlmsg_data - head of message payload
* @gnlh: genetlink messsage header
*/
static inline void *genlmsg_data(const struct genlmsghdr *gnlh)
{
return ((unsigned char *) gnlh + GENL_HDRLEN);
}
/**
* genlmsg_len - length of message payload
* @gnlh: genetlink message header
*/
static inline int genlmsg_len(const struct genlmsghdr *gnlh)
{
struct nlmsghdr *nlh = (struct nlmsghdr *)((unsigned char *)gnlh -
NLMSG_HDRLEN);
return (nlh->nlmsg_len - GENL_HDRLEN - NLMSG_HDRLEN);
}
/**
* genlmsg_msg_size - length of genetlink message not including padding
* @payload: length of message payload
*/
static inline int genlmsg_msg_size(int payload)
{
return GENL_HDRLEN + payload;
}
/**
* genlmsg_total_size - length of genetlink message including padding
* @payload: length of message payload
*/
static inline int genlmsg_total_size(int payload)
{
return NLMSG_ALIGN(genlmsg_msg_size(payload));
}
/**
* genlmsg_new - Allocate a new generic netlink message
* @payload: size of the message payload
* @flags: the type of memory to allocate.
*/
static inline struct sk_buff *genlmsg_new(size_t payload, gfp_t flags)
{
return nlmsg_new(genlmsg_total_size(payload), flags);
}
#endif /* __NET_GENERIC_NETLINK_H */
@@ -0,0 +1,11 @@
#ifndef __NET_LLC_PDU_H
#define __NET_LLC_PDU_H 1
/* Un-numbered PDU format (3 bytes in length) */
struct llc_pdu_un {
u8 dsap;
u8 ssap;
u8 ctrl_1;
};
#endif
File diff suppressed because it is too large. Load diff
+27
View File
@@ -0,0 +1,27 @@
/*
* Distributed under the terms of the GNU GPL version 2.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
int vprintk(const char *msg, ...)
{
#define BUFFER_SIZE 1024
char *buffer = kmalloc(BUFFER_SIZE, GFP_ATOMIC);
int retval;
if (buffer) {
va_list args;
va_start(args, msg);
vsnprintf(buffer, BUFFER_SIZE, msg, args);
va_end(args);
retval = printk("%s", buffer);
kfree(buffer);
} else {
retval = printk("<<vprintk allocation failure>> %s", msg);
}
return retval;
}
EXPORT_SYMBOL(vprintk);
+116
View File
@@ -0,0 +1,116 @@
/*
* NETLINK Netlink attributes
*
* Authors: Thomas Graf <tgraf@suug.ch>
* Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/jiffies.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/string.h>
#include <linux/types.h>
#include <net/netlink.h>
#include <net/sock.h>
/**
* netlink_queue_skip - Skip netlink message while processing queue.
* @nlh: Netlink message to be skipped
* @skb: Socket buffer containing the netlink messages.
*
* Pulls the given netlink message off the socket buffer so the next
* call to netlink_queue_run() will not reconsider the message.
*/
static void netlink_queue_skip(struct nlmsghdr *nlh, struct sk_buff *skb)
{
int msglen = NLMSG_ALIGN(nlh->nlmsg_len);
if (msglen > skb->len)
msglen = skb->len;
skb_pull(skb, msglen);
}
static int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *,
struct nlmsghdr *))
{
struct nlmsghdr *nlh;
int err;
while (skb->len >= nlmsg_total_size(0)) {
nlh = nlmsg_hdr(skb);
err = 0;
if (nlh->nlmsg_len < NLMSG_HDRLEN || skb->len < nlh->nlmsg_len)
return 0;
/* Only requests are handled by the kernel */
if (!(nlh->nlmsg_flags & NLM_F_REQUEST))
goto skip;
/* Skip control messages */
if (nlh->nlmsg_type < NLMSG_MIN_TYPE)
goto skip;
err = cb(skb, nlh);
if (err == -EINTR) {
/* Not an error, but we interrupt processing */
netlink_queue_skip(nlh, skb);
return err;
}
skip:
if (nlh->nlmsg_flags & NLM_F_ACK || err)
netlink_ack(skb, nlh, err);
netlink_queue_skip(nlh, skb);
}
return 0;
}
/**
* netlink_run_queue - Process netlink receive queue.
* @sk: Netlink socket containing the queue
* @qlen: Place to store queue length upon entry
* @cb: Callback function invoked for each netlink message found
*
* Processes as much as there was in the queue upon entry and invokes
* a callback function for each netlink message found. The callback
* function may refuse a message by returning a negative error code
* but setting the error pointer to 0 in which case this function
* returns with a qlen != 0.
*
* qlen must be initialized to 0 before the initial entry, afterwards
* the function may be called repeatedly until qlen reaches 0.
*
* The callback function may return -EINTR to signal that processing
* of netlink messages shall be interrupted. In this case the message
* currently being processed will NOT be requeued onto the receive
* queue.
*/
void netlink_run_queue(struct sock *sk, unsigned int *qlen,
int (*cb)(struct sk_buff *, struct nlmsghdr *))
{
struct sk_buff *skb;
if (!*qlen || *qlen > skb_queue_len(&sk->receive_queue))
*qlen = skb_queue_len(&sk->receive_queue);
for (; *qlen; (*qlen)--) {
skb = skb_dequeue(&sk->receive_queue);
if (netlink_rcv_skb(skb, cb)) {
if (skb->len)
skb_queue_head(&sk->receive_queue, skb);
else {
kfree_skb(skb);
(*qlen)--;
}
break;
}
kfree_skb(skb);
}
}
+142
View File
@@ -0,0 +1,142 @@
/*
This is a maximally equidistributed combined Tausworthe generator
based on code from GNU Scientific Library 1.5 (30 Jun 2004)
x_n = (s1_n ^ s2_n ^ s3_n)
s1_{n+1} = (((s1_n & 4294967294) <<12) ^ (((s1_n <<13) ^ s1_n) >>19))
s2_{n+1} = (((s2_n & 4294967288) << 4) ^ (((s2_n << 2) ^ s2_n) >>25))
s3_{n+1} = (((s3_n & 4294967280) <<17) ^ (((s3_n << 3) ^ s3_n) >>11))
The period of this generator is about 2^88.
From: P. L'Ecuyer, "Maximally Equidistributed Combined Tausworthe
Generators", Mathematics of Computation, 65, 213 (1996), 203--213.
This is available on the net from L'Ecuyer's home page,
http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme.ps
ftp://ftp.iro.umontreal.ca/pub/simulation/lecuyer/papers/tausme.ps
There is an erratum in the paper "Tables of Maximally
Equidistributed Combined LFSR Generators", Mathematics of
Computation, 68, 225 (1999), 261--269:
http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme2.ps
... the k_j most significant bits of z_j must be non-
zero, for each j. (Note: this restriction also applies to the
computer code given in [4], but was mistakenly not mentioned in
that paper.)
This affects the seeding procedure by imposing the requirement
s1 > 1, s2 > 7, s3 > 15.
*/
#include <linux/types.h>
#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/random.h>
#include <linux/threads.h>
#include <linux/smp.h>
#include "compat24.h"
struct rnd_state {
u32 s1, s2, s3;
};
static struct rnd_state net_rand_state[NR_CPUS];
static u32 __random32(struct rnd_state *state)
{
#define TAUSWORTHE(s,a,b,c,d) ((s&c)<<d) ^ (((s <<a) ^ s)>>b)
state->s1 = TAUSWORTHE(state->s1, 13, 19, 4294967294UL, 12);
state->s2 = TAUSWORTHE(state->s2, 2, 25, 4294967288UL, 4);
state->s3 = TAUSWORTHE(state->s3, 3, 11, 4294967280UL, 17);
return (state->s1 ^ state->s2 ^ state->s3);
}
static void __set_random32(struct rnd_state *state, unsigned long s)
{
if (s == 0)
s = 1; /* default seed is 1 */
#define LCG(n) (69069 * n)
state->s1 = LCG(s);
state->s2 = LCG(state->s1);
state->s3 = LCG(state->s2);
/* "warm it up" */
__random32(state);
__random32(state);
__random32(state);
__random32(state);
__random32(state);
__random32(state);
}
/**
* random32 - pseudo random number generator
*
* A 32 bit pseudo-random number is generated using a fast
* algorithm suitable for simulation. This algorithm is NOT
* considered safe for cryptographic use.
*/
u32 random32(void)
{
return __random32(&net_rand_state[smp_processor_id()]);
}
EXPORT_SYMBOL(random32);
/**
* srandom32 - add entropy to pseudo random number generator
* @seed: seed value
*
* Add some additional seeding to the random32() pool.
* Note: this pool is per cpu so it only affects current CPU.
*/
void srandom32(u32 entropy)
{
struct rnd_state *state = &net_rand_state[smp_processor_id()];
__set_random32(state, state->s1 ^ entropy);
}
EXPORT_SYMBOL(srandom32);
static int __init random32_reseed(void);
/*
* Generate some initially weak seeding values to allow
* to start the random32() engine.
*/
int __init random32_init(void)
{
int i;
for (i = 0; i < NR_CPUS; i++) {
struct rnd_state *state = &net_rand_state[i];
__set_random32(state, i + jiffies);
}
random32_reseed();
return 0;
}
/*
* Generate better values after random number generator
* is fully initalized.
*/
static int __init random32_reseed(void)
{
int i;
unsigned long seed;
for (i = 0; i < NR_CPUS; i++) {
struct rnd_state *state = &net_rand_state[i];
get_random_bytes(&seed, sizeof(seed));
__set_random32(state, seed);
}
return 0;
}
+145
View File
@@ -0,0 +1,145 @@
/*
* Distributed under the terms of the GNU GPL version 2.
*/
#include <linux/module.h>
#include <linux/rcupdate.h>
#include <linux/sched.h>
#include <linux/tqueue.h>
#include <linux/smp.h>
#include <linux/completion.h>
#include "compat24.h"
#ifdef CONFIG_SMP
#error "SMP configurations not supported for RCU backport."
#endif
static int default_blimit = 10;
static int blimit;
static int qhimark = 10000;
static int qlowmark = 100;
static struct rcu_head *head, **tail;
static int qlen = 0;
static struct tq_struct rcu_task;
/*
* Invoke the completed RCU callbacks. They are expected to be in
* a per-cpu list.
*/
static void rcu_task_routine(void *unused)
{
struct rcu_head *list, *next;
int count = 0;
local_irq_disable();
list = head;
head = NULL;
tail = &head;
local_irq_enable();
while (list) {
next = list->next;
prefetch(next);
list->func(list);
list = next;
if (++count >= blimit)
break;
}
local_irq_disable();
qlen -= count;
local_irq_enable();
if (blimit == INT_MAX && qlen <= qlowmark)
blimit = default_blimit;
if (head)
schedule_task(&rcu_task);
}
static inline void force_quiescent_state(void)
{
current->need_resched = 1;
}
/**
* call_rcu - Queue an RCU callback for invocation after a grace period.
* @rcu: structure to be used for queueing the RCU updates.
* @func: actual update function to be invoked after the grace period
*
* The update function will be invoked some time after a full grace
* period elapses, in other words after all currently executing RCU
* read-side critical sections have completed. RCU read-side critical
* sections are delimited by rcu_read_lock() and rcu_read_unlock(),
* and may be nested.
*/
void call_rcu(struct rcu_head *rcu, void (*func)(struct rcu_head *rcu))
{
unsigned long flags;
/* FIXME? Following may be mildly expensive, may be worthwhile to
optimize common case. */
schedule_task(&rcu_task);
rcu->func = func;
rcu->next = NULL;
local_irq_save(flags);
*tail = rcu;
tail = &rcu->next;
if (unlikely(++qlen > qhimark)) {
blimit = INT_MAX;
force_quiescent_state();
}
local_irq_restore(flags);
}
EXPORT_SYMBOL(call_rcu);
void rcu_init(void)
{
head = NULL;
tail = &head;
blimit = default_blimit;
rcu_task.routine = rcu_task_routine;
}
struct rcu_synchronize {
struct rcu_head head;
struct completion completion;
};
/* Because of FASTCALL declaration of complete, we use this wrapper */
static void wakeme_after_rcu(struct rcu_head *head)
{
struct rcu_synchronize *rcu;
rcu = container_of(head, struct rcu_synchronize, head);
complete(&rcu->completion);
}
/**
* synchronize_rcu - wait until a grace period has elapsed.
*
* Control will return to the caller some time after a full grace
* period has elapsed, in other words after all currently executing RCU
* read-side critical sections have completed. RCU read-side critical
* sections are delimited by rcu_read_lock() and rcu_read_unlock(),
* and may be nested.
*
* If your read-side code is not protected by rcu_read_lock(), do -not-
* use synchronize_rcu().
*/
void synchronize_rcu(void)
{
struct rcu_synchronize rcu;
init_completion(&rcu.completion);
/* Will wake me after RCU finished */
call_rcu(&rcu.head, wakeme_after_rcu);
/* Wait for it */
wait_for_completion(&rcu.completion);
}
EXPORT_SYMBOL(synchronize_rcu);
+30
View File
@@ -0,0 +1,30 @@
/*
* Distributed under the terms of the GNU GPL version 2.
*/
#include <linux/module.h>
#include <linux/string.h>
#ifndef __HAVE_ARCH_STRCSPN
/**
* strcspn - Calculate the length of the initial substring of @s which does not contain letters in @reject
* @s: The string to be searched
* @reject: The string to avoid
*/
size_t strcspn(const char *s, const char *reject)
{
const char *p;
const char *r;
size_t count = 0;
for (p = s; *p != '\0'; ++p) {
for (r = reject; *r != '\0'; ++r) {
if (*p == *r)
return count;
}
++count;
}
return count;
}
EXPORT_SYMBOL(strcspn);
#endif
@@ -0,0 +1,600 @@
#
# Automatically generated make config: don't edit
#
CONFIG_X86=y
# CONFIG_SBUS is not set
CONFIG_UID16=y
#
# Code maturity level options
#
# CONFIG_EXPERIMENTAL is not set
#
# Loadable module support
#
CONFIG_MODULES=y
CONFIG_MODVERSIONS=y
CONFIG_KMOD=y
#
# Processor type and features
#
# CONFIG_M386 is not set
# CONFIG_M486 is not set
# CONFIG_M586 is not set
# CONFIG_M586TSC is not set
# CONFIG_M586MMX is not set
# CONFIG_M686 is not set
CONFIG_MPENTIUMIII=y
# CONFIG_MPENTIUM4 is not set
# CONFIG_MK6 is not set
# CONFIG_MK7 is not set
# CONFIG_MK8 is not set
# CONFIG_MELAN is not set
# CONFIG_MCRUSOE is not set
# CONFIG_MWINCHIPC6 is not set
# CONFIG_MWINCHIP2 is not set
# CONFIG_MWINCHIP3D is not set
# CONFIG_MCYRIXIII is not set
# CONFIG_MVIAC3_2 is not set
CONFIG_X86_WP_WORKS_OK=y
CONFIG_X86_INVLPG=y
CONFIG_X86_CMPXCHG=y
CONFIG_X86_XADD=y
CONFIG_X86_BSWAP=y
CONFIG_X86_POPAD_OK=y
# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
# CONFIG_X86_TSC is not set
CONFIG_X86_L1_CACHE_SHIFT=5
CONFIG_X86_HAS_TSC=y
CONFIG_X86_GOOD_APIC=y
CONFIG_X86_PGE=y
CONFIG_X86_USE_PPRO_CHECKSUM=y
CONFIG_X86_F00F_WORKS_OK=y
# CONFIG_X86_MCE is not set
# CONFIG_TOSHIBA is not set
# CONFIG_I8K is not set
# CONFIG_MICROCODE is not set
# CONFIG_X86_MSR is not set
# CONFIG_X86_CPUID is not set
CONFIG_NOHIGHMEM=y
# CONFIG_HIGHMEM4G is not set
# CONFIG_HIGHMEM64G is not set
# CONFIG_HIGHMEM is not set
# CONFIG_MATH_EMULATION is not set
# CONFIG_MTRR is not set
# CONFIG_SMP is not set
# CONFIG_X86_UP_APIC is not set
# CONFIG_X86_TSC_DISABLE is not set
CONFIG_X86_TSC=y
#
# General setup
#
CONFIG_NET=y
CONFIG_PCI=y
# CONFIG_PCI_GOBIOS is not set
# CONFIG_PCI_GODIRECT is not set
CONFIG_PCI_GOANY=y
CONFIG_PCI_BIOS=y
CONFIG_PCI_DIRECT=y
CONFIG_ISA=y
CONFIG_PCI_NAMES=y
# CONFIG_EISA is not set
# CONFIG_MCA is not set
# CONFIG_HOTPLUG is not set
# CONFIG_PCMCIA is not set
# CONFIG_HOTPLUG_PCI is not set
CONFIG_SYSVIPC=y
# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_SYSCTL=y
CONFIG_KCORE_ELF=y
# CONFIG_KCORE_AOUT is not set
CONFIG_BINFMT_AOUT=y
CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_MISC=y
# CONFIG_OOM_KILLER is not set
CONFIG_PM=y
# CONFIG_APM is not set
#
# ACPI Support
#
# CONFIG_ACPI is not set
#
# Memory Technology Devices (MTD)
#
# CONFIG_MTD is not set
#
# Parallel port support
#
# CONFIG_PARPORT is not set
#
# Plug and Play configuration
#
# CONFIG_PNP is not set
#
# Block devices
#
# CONFIG_BLK_DEV_FD is not set
# CONFIG_BLK_DEV_XD is not set
# CONFIG_BLK_CPQ_DA is not set
# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
# CONFIG_BLK_DEV_SX8 is not set
# CONFIG_BLK_DEV_LOOP is not set
# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_RAM is not set
# CONFIG_BLK_STATS is not set
#
# Multi-device support (RAID and LVM)
#
# CONFIG_MD is not set
#
# Networking options
#
CONFIG_PACKET=y
# CONFIG_PACKET_MMAP is not set
# CONFIG_NETLINK_DEV is not set
# CONFIG_NETFILTER is not set
CONFIG_FILTER=y
CONFIG_UNIX=y
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
# CONFIG_IP_ADVANCED_ROUTER is not set
# CONFIG_IP_PNP is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
# CONFIG_IP_MROUTE is not set
# CONFIG_INET_ECN is not set
# CONFIG_SYN_COOKIES is not set
# CONFIG_VLAN_8021Q is not set
#
#
#
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
# CONFIG_DECNET is not set
CONFIG_BRIDGE=y
#
# QoS and/or fair queueing
#
# CONFIG_NET_SCHED is not set
#
# Network testing
#
# CONFIG_NET_PKTGEN is not set
#
# Telephony Support
#
# CONFIG_PHONE is not set
#
# ATA/IDE/MFM/RLL support
#
CONFIG_IDE=y
#
# IDE, ATA and ATAPI Block devices
#
CONFIG_BLK_DEV_IDE=y
#
# Please see Documentation/ide.txt for help/info on IDE drives
#
# CONFIG_BLK_DEV_HD_IDE is not set
# CONFIG_BLK_DEV_HD is not set
# CONFIG_BLK_DEV_IDE_SATA is not set
CONFIG_BLK_DEV_IDEDISK=y
CONFIG_IDEDISK_MULTI_MODE=y
# CONFIG_IDEDISK_STROKE is not set
CONFIG_BLK_DEV_IDECD=y
# CONFIG_BLK_DEV_IDETAPE is not set
# CONFIG_BLK_DEV_IDEFLOPPY is not set
# CONFIG_IDE_TASK_IOCTL is not set
#
# IDE chipset support/bugfixes
#
# CONFIG_BLK_DEV_CMD640 is not set
CONFIG_BLK_DEV_IDEPCI=y
# CONFIG_BLK_DEV_GENERIC is not set
CONFIG_IDEPCI_SHARE_IRQ=y
CONFIG_BLK_DEV_IDEDMA_PCI=y
# CONFIG_BLK_DEV_OFFBOARD is not set
# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
CONFIG_IDEDMA_PCI_AUTO=y
# CONFIG_IDEDMA_ONLYDISK is not set
CONFIG_BLK_DEV_IDEDMA=y
# CONFIG_BLK_DEV_ADMA100 is not set
# CONFIG_BLK_DEV_AEC62XX is not set
# CONFIG_BLK_DEV_ALI15X3 is not set
# CONFIG_BLK_DEV_AMD74XX is not set
# CONFIG_BLK_DEV_ATIIXP is not set
# CONFIG_BLK_DEV_CMD64X is not set
# CONFIG_BLK_DEV_TRIFLEX is not set
# CONFIG_BLK_DEV_CY82C693 is not set
# CONFIG_BLK_DEV_CS5530 is not set
# CONFIG_BLK_DEV_HPT34X is not set
# CONFIG_BLK_DEV_HPT366 is not set
CONFIG_BLK_DEV_PIIX=y
# CONFIG_BLK_DEV_NS87415 is not set
# CONFIG_BLK_DEV_PDC202XX_OLD is not set
# CONFIG_BLK_DEV_PDC202XX_NEW is not set
CONFIG_BLK_DEV_RZ1000=y
# CONFIG_BLK_DEV_SC1200 is not set
# CONFIG_BLK_DEV_SVWKS is not set
# CONFIG_BLK_DEV_SIIMAGE is not set
# CONFIG_BLK_DEV_SIS5513 is not set
# CONFIG_BLK_DEV_SLC90E66 is not set
# CONFIG_BLK_DEV_TRM290 is not set
# CONFIG_BLK_DEV_VIA82CXXX is not set
# CONFIG_IDE_CHIPSETS is not set
CONFIG_IDEDMA_AUTO=y
# CONFIG_IDEDMA_IVB is not set
# CONFIG_DMA_NONPCI is not set
#
# SCSI support
#
# CONFIG_SCSI is not set
#
# Fusion MPT device support
#
# CONFIG_FUSION_BOOT is not set
# CONFIG_FUSION_ISENSE is not set
# CONFIG_FUSION_CTL is not set
# CONFIG_FUSION_LAN is not set
#
# I2O device support
#
# CONFIG_I2O is not set
#
# Network device support
#
CONFIG_NETDEVICES=y
#
# ARCnet devices
#
# CONFIG_ARCNET is not set
CONFIG_DUMMY=m
# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
# CONFIG_TUN is not set
#
# Ethernet (10 or 100Mbit)
#
CONFIG_NET_ETHERNET=y
# CONFIG_HAPPYMEAL is not set
# CONFIG_SUNGEM is not set
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_LANCE is not set
# CONFIG_NET_VENDOR_SMC is not set
# CONFIG_NET_VENDOR_RACAL is not set
# CONFIG_DEPCA is not set
# CONFIG_HP100 is not set
# CONFIG_NET_ISA is not set
CONFIG_NET_PCI=y
# CONFIG_PCNET32 is not set
# CONFIG_AMD8111_ETH is not set
# CONFIG_ADAPTEC_STARFIRE is not set
# CONFIG_APRICOT is not set
# CONFIG_CS89x0 is not set
# CONFIG_TULIP is not set
# CONFIG_DE4X5 is not set
# CONFIG_DGRS is not set
# CONFIG_DM9102 is not set
CONFIG_EEPRO100=y
# CONFIG_EEPRO100_PIO is not set
# CONFIG_E100 is not set
# CONFIG_FEALNX is not set
# CONFIG_NATSEMI is not set
CONFIG_NE2K_PCI=y
CONFIG_8139TOO=y
# CONFIG_8139TOO_PIO is not set
# CONFIG_8139TOO_TUNE_TWISTER is not set
# CONFIG_8139TOO_8129 is not set
# CONFIG_8139_OLD_RX_RESET is not set
# CONFIG_SIS900 is not set
# CONFIG_EPIC100 is not set
# CONFIG_SUNDANCE is not set
# CONFIG_TLAN is not set
# CONFIG_VIA_RHINE is not set
# CONFIG_WINBOND_840 is not set
# CONFIG_NET_POCKET is not set
#
# Ethernet (1000 Mbit)
#
# CONFIG_ACENIC is not set
# CONFIG_DL2K is not set
# CONFIG_E1000 is not set
# CONFIG_NS83820 is not set
# CONFIG_HAMACHI is not set
# CONFIG_R8169 is not set
# CONFIG_SKGE is not set
# CONFIG_SKY2 is not set
# CONFIG_SK98LIN is not set
# CONFIG_TIGON3 is not set
# CONFIG_FDDI is not set
# CONFIG_PPP is not set
# CONFIG_SLIP is not set
#
# Wireless LAN (non-hamradio)
#
# CONFIG_NET_RADIO is not set
#
# Token Ring devices
#
# CONFIG_TR is not set
# CONFIG_NET_FC is not set
#
# Wan interfaces
#
# CONFIG_WAN is not set
#
# Amateur Radio support
#
# CONFIG_HAMRADIO is not set
#
# IrDA (infrared) support
#
# CONFIG_IRDA is not set
#
# ISDN subsystem
#
# CONFIG_ISDN is not set
#
# Old CD-ROM drivers (not SCSI, not IDE)
#
# CONFIG_CD_NO_IDESCSI is not set
#
# Input core support
#
# CONFIG_INPUT is not set
CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
#
# Character devices
#
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
CONFIG_SERIAL=y
CONFIG_SERIAL_CONSOLE=y
# CONFIG_SERIAL_EXTENDED is not set
# CONFIG_SERIAL_NONSTANDARD is not set
CONFIG_UNIX98_PTYS=y
CONFIG_UNIX98_PTY_COUNT=256
#
# I2C support
#
# CONFIG_I2C is not set
#
# Mice
#
# CONFIG_BUSMOUSE is not set
CONFIG_MOUSE=y
CONFIG_PSMOUSE=y
# CONFIG_82C710_MOUSE is not set
# CONFIG_PC110_PAD is not set
# CONFIG_MK712_MOUSE is not set
#
# Joysticks
#
# CONFIG_INPUT_GAMEPORT is not set
#
# Input core support is needed for gameports
#
#
# Input core support is needed for joysticks
#
# CONFIG_QIC02_TAPE is not set
# CONFIG_IPMI_HANDLER is not set
#
# Watchdog Cards
#
# CONFIG_WATCHDOG is not set
# CONFIG_SCx200 is not set
# CONFIG_AMD_RNG is not set
# CONFIG_INTEL_RNG is not set
# CONFIG_HW_RANDOM is not set
# CONFIG_AMD_PM768 is not set
# CONFIG_NVRAM is not set
# CONFIG_RTC is not set
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
#
# Ftape, the floppy tape device driver
#
# CONFIG_FTAPE is not set
# CONFIG_AGP is not set
#
# Direct Rendering Manager (XFree86 DRI support)
#
# CONFIG_DRM is not set
# CONFIG_MWAVE is not set
#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
#
# File systems
#
# CONFIG_QUOTA is not set
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
# CONFIG_REISERFS_FS is not set
CONFIG_EXT3_FS=y
CONFIG_JBD=y
# CONFIG_JBD_DEBUG is not set
# CONFIG_FAT_FS is not set
# CONFIG_CRAMFS is not set
CONFIG_TMPFS=y
CONFIG_RAMFS=y
CONFIG_ISO9660_FS=y
# CONFIG_JOLIET is not set
# CONFIG_ZISOFS is not set
# CONFIG_JFS_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_VXFS_FS is not set
# CONFIG_NTFS_FS is not set
# CONFIG_HPFS_FS is not set
CONFIG_PROC_FS=y
CONFIG_DEVPTS_FS=y
# CONFIG_QNX4FS_FS is not set
# CONFIG_ROMFS_FS is not set
# CONFIG_EXT2_FS is not set
# CONFIG_SYSV_FS is not set
# CONFIG_UDF_FS is not set
# CONFIG_UFS_FS is not set
# CONFIG_XFS_FS is not set
#
# Network File Systems
#
# CONFIG_CODA_FS is not set
# CONFIG_NFS_FS is not set
# CONFIG_NFSD is not set
# CONFIG_SUNRPC is not set
# CONFIG_LOCKD is not set
# CONFIG_SMB_FS is not set
# CONFIG_NCP_FS is not set
# CONFIG_ZISOFS_FS is not set
#
# Partition Types
#
# CONFIG_PARTITION_ADVANCED is not set
CONFIG_MSDOS_PARTITION=y
# CONFIG_SMB_NLS is not set
CONFIG_NLS=y
#
# Native Language Support
#
CONFIG_NLS_DEFAULT="iso8859-1"
# CONFIG_NLS_CODEPAGE_437 is not set
# CONFIG_NLS_CODEPAGE_737 is not set
# CONFIG_NLS_CODEPAGE_775 is not set
# CONFIG_NLS_CODEPAGE_850 is not set
# CONFIG_NLS_CODEPAGE_852 is not set
# CONFIG_NLS_CODEPAGE_855 is not set
# CONFIG_NLS_CODEPAGE_857 is not set
# CONFIG_NLS_CODEPAGE_860 is not set
# CONFIG_NLS_CODEPAGE_861 is not set
# CONFIG_NLS_CODEPAGE_862 is not set
# CONFIG_NLS_CODEPAGE_863 is not set
# CONFIG_NLS_CODEPAGE_864 is not set
# CONFIG_NLS_CODEPAGE_865 is not set
# CONFIG_NLS_CODEPAGE_866 is not set
# CONFIG_NLS_CODEPAGE_869 is not set
# CONFIG_NLS_CODEPAGE_936 is not set
# CONFIG_NLS_CODEPAGE_950 is not set
# CONFIG_NLS_CODEPAGE_932 is not set
# CONFIG_NLS_CODEPAGE_949 is not set
# CONFIG_NLS_CODEPAGE_874 is not set
# CONFIG_NLS_ISO8859_8 is not set
# CONFIG_NLS_CODEPAGE_1250 is not set
# CONFIG_NLS_CODEPAGE_1251 is not set
# CONFIG_NLS_ISO8859_1 is not set
# CONFIG_NLS_ISO8859_2 is not set
# CONFIG_NLS_ISO8859_3 is not set
# CONFIG_NLS_ISO8859_4 is not set
# CONFIG_NLS_ISO8859_5 is not set
# CONFIG_NLS_ISO8859_6 is not set
# CONFIG_NLS_ISO8859_7 is not set
# CONFIG_NLS_ISO8859_9 is not set
# CONFIG_NLS_ISO8859_13 is not set
# CONFIG_NLS_ISO8859_14 is not set
# CONFIG_NLS_ISO8859_15 is not set
# CONFIG_NLS_KOI8_R is not set
# CONFIG_NLS_KOI8_U is not set
# CONFIG_NLS_UTF8 is not set
#
# Console drivers
#
CONFIG_VGA_CONSOLE=y
# CONFIG_VIDEO_SELECT is not set
#
# Sound
#
# CONFIG_SOUND is not set
#
# USB support
#
# CONFIG_USB is not set
#
# Support for USB gadgets
#
# CONFIG_USB_GADGET is not set
#
# Bluetooth support
#
# CONFIG_BLUEZ is not set
#
# Kernel hacking
#
CONFIG_DEBUG_KERNEL=y
# CONFIG_DEBUG_STACKOVERFLOW is not set
# CONFIG_DEBUG_HIGHMEM is not set
# CONFIG_DEBUG_SLAB is not set
# CONFIG_DEBUG_IOVIRT is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_DEBUG_SPINLOCK is not set
CONFIG_FRAME_POINTER=y
CONFIG_LOG_BUF_SHIFT=0
#
# Cryptographic options
#
# CONFIG_CRYPTO is not set
#
# Library routines
#
CONFIG_CRC32=y
# CONFIG_ZLIB_INFLATE is not set
# CONFIG_ZLIB_DEFLATE is not set
+246
View File
@@ -0,0 +1,246 @@
# The remainder of this file is from Intel's e1000 distribution,
# with the following license:
################################################################################
#
# Intel PRO/1000 Linux driver
# Copyright(c) 1999 - 2007 Intel Corporation.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms and conditions of the GNU General Public License,
# version 2, as published by the Free Software Foundation.
#
# This program is distributed in the hope it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
#
# The full GNU General Public License is included in this distribution in
# the file called "COPYING".
#
# Contact Information:
# Linux NICS <linux.nics@intel.com>
# e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
# Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
#
################################################################################
ifeq (,$(BUILD_KERNEL))
BUILD_KERNEL=$(shell uname -r)
endif
###########################################################################
# Environment tests
# Kernel Search Path
# All the places we look for kernel source
KSP := /lib/modules/$(BUILD_KERNEL)/build \
/lib/modules/$(BUILD_KERNEL)/source \
/usr/src/linux-$(BUILD_KERNEL) \
/usr/src/linux-$($(BUILD_KERNEL) | sed 's/-.*//') \
/usr/src/kernel-headers-$(BUILD_KERNEL) \
/usr/src/kernel-source-$(BUILD_KERNEL) \
/usr/src/linux-$($(BUILD_KERNEL) | sed 's/\([0-9]*\.[0-9]*\)\..*/\1/') \
/usr/src/linux
# prune the list down to only values that exist
# and have an include/linux sub-directory
test_dir = $(shell [ -e $(dir)/include/linux ] && echo $(dir))
KSP := $(foreach dir, $(KSP), $(test_dir))
# we will use this first valid entry in the search path
ifeq (,$(KSRC))
KSRC := $(firstword $(KSP))
endif
CFLAGS += $(CFLAGS_EXTRA)
ifeq (,$(KSRC))
$(error Linux kernel source not found)
else
ifeq (/lib/modules/$(shell uname -r)/source, $(KSRC))
KOBJ := /lib/modules/$(shell uname -r)/build
else
KOBJ := $(KSRC)
endif
endif
# version 2.4 or 2.6?
K_VERSION:=$(shell if grep -q 'PATCHLEVEL = 4' $(KSRC)/Makefile; then echo 2.4; else echo 2.6; fi)
ifneq ($(K_VERSION),2.4)
$(error Linux kernel source in $(KSRC) not 2.4)
endif
# check for version.h and autoconf.h for running kernel in /boot (SUSE)
ifneq (,$(wildcard /boot/vmlinuz.version.h))
VERSION_FILE := /boot/vmlinuz.version.h
CONFIG_FILE := /boot/vmlinuz.autoconf.h
KVER := $(shell $(CC) $(CFLAGS) -E -dM $(VERSION_FILE) | \
grep UTS_RELEASE | awk '{ print $$3 }' | sed 's/\"//g')
ifeq ($(KVER),$(shell uname -r))
# set up include path to override headers from kernel source
x:=$(shell rm -rf include)
x:=$(shell mkdir -p include/linux)
x:=$(shell cp /boot/vmlinuz.version.h include/linux/version.h)
x:=$(shell cp /boot/vmlinuz.autoconf.h include/linux/autoconf.h)
CFLAGS += -I./include
else
ifneq (,$(wildcard $(KOBJ)/include/linux/utsrelease.h))
VERSION_FILE := $(KOBJ)/include/linux/utsrelease.h
else
VERSION_FILE := $(KOBJ)/include/linux/version.h
endif
CONFIG_FILE := $(KSRC)/include/linux/autoconf.h
endif
else
ifneq (,$(wildcard $(KOBJ)/include/linux/utsrelease.h))
VERSION_FILE := $(KOBJ)/include/linux/utsrelease.h
else
VERSION_FILE := $(KOBJ)/include/linux/version.h
endif
CONFIG_FILE := $(KSRC)/include/linux/autoconf.h
endif
ifeq (,$(wildcard $(VERSION_FILE)))
$(error Linux kernel source not configured - missing version.h)
endif
ifeq (,$(wildcard $(CONFIG_FILE)))
$(error Linux kernel source not configured - missing autoconf.h)
endif
# pick a compiler
ifeq ($(K_VERSION),2.6)
CC := gcc cc
else
# Older kernels require GCC 2.95
K_SUBLEVEL:=$(shell sed -n 's/SUBLEVEL = // p' $(KSRC)/Makefile)
ifeq ($(K_SUBLEVEL),20)
CC := gcc-2.95
else
CC := gcc-3.4 gcc-3.3 gcc-2.95
endif
endif
test_cc = $(shell $(cc) --version > /dev/null 2>&1 && echo $(cc))
CC := $(foreach cc, $(CC), $(test_cc))
CC := $(firstword $(CC))
ifeq (,$(CC))
$(error Compiler not found)
endif
# we need to know what platform the driver is being built on
# some additional features are only built on Intel platforms
ifeq ($(ARCH),)
# Set the architecture if it hasn't been already set for cross-compilation
ARCH := $(shell uname -m | sed 's/i.86/i386/')
endif
ifeq ($(ARCH),alpha)
CFLAGS += -ffixed-8 -mno-fp-regs
endif
ifeq ($(ARCH),x86_64)
CFLAGS += -mcmodel=kernel -mno-red-zone
endif
ifeq ($(ARCH),ppc)
CFLAGS += -msoft-float
endif
ifeq ($(ARCH),ppc64)
CFLAGS += -m64 -msoft-float
LDFLAGS += -melf64ppc
endif
# standard flags for module builds
CFLAGS += -DLINUX -D__KERNEL__ -DMODULE -O2 -pipe -Wall
CFLAGS += -I$(KSRC)/include -I.
CFLAGS += -I$(srcdir)/compat-2.4 -I$(srcdir)/compat-2.4/include
CFLAGS += $(shell [ -f $(KSRC)/include/linux/modversions.h ] && \
echo "-DMODVERSIONS -DEXPORT_SYMTAB \
-include $(KSRC)/include/linux/modversions.h")
RHC := $(KSRC)/include/linux/rhconfig.h
ifneq (,$(wildcard $(RHC)))
# 7.3 typo in rhconfig.h
ifneq (,$(shell $(CC) $(CFLAGS) -E -dM $(RHC) | grep __module__bigmem))
CFLAGS += -D__module_bigmem
endif
endif
# get the kernel version - we use this to find the correct install path
KVER := $(shell $(CC) $(CFLAGS) -E -dM $(VERSION_FILE) | grep UTS_RELEASE | \
awk '{ print $$3 }' | sed 's/\"//g')
# assume source symlink is the same as build, otherwise adjust KOBJ
ifneq (,$(wildcard /lib/modules/$(KVER)/build))
ifneq ($(KSRC),$(shell cd /lib/modules/$(KVER)/build ; pwd -P))
KOBJ=/lib/modules/$(KVER)/build
endif
endif
KKVER := $(shell echo $(KVER) | \
awk '{ if ($$0 ~ /2\.[4-9]\./) print "1"; else print "0"}')
ifeq ($(KKVER), 0)
$(error *** Aborting the build. \
*** This driver is not supported on kernel versions older than 2.4.0)
endif
# look for SMP in config.h
SMP := $(shell $(CC) $(CFLAGS) -E -dM $(CONFIG_FILE) | \
grep -w CONFIG_SMP | awk '{ print $$3 }')
ifneq ($(SMP),1)
SMP := 0
endif
#ifneq ($(SMP),$(shell uname -a | grep SMP > /dev/null 2>&1 && echo 1 || echo 0))
# $(warning ***)
# ifeq ($(SMP),1)
# $(warning *** Warning: kernel source configuration (SMP))
# $(warning *** does not match running kernel (UP))
# else
# $(warning *** Warning: kernel source configuration (UP))
# $(warning *** does not match running kernel (SMP))
# endif
# $(warning *** Continuing with build,)
# $(warning *** resulting driver may not be what you want)
# $(warning ***)
#endif
ifeq ($(SMP),1)
CFLAGS += -D__SMP__
endif
###########################################################################
# 2.4.x
# Makefile for 2.4.x kernel
TARGET = openflow_mod.o unit_mod.o compat24_mod.o
CFLAGS += -Wno-sign-compare -fno-strict-aliasing
CFLAGS := -I $(srcdir)/compat-2.4/include $(CFLAGS)
CFLAGS := -I $(srcdir)/compat-2.4/include-$(ARCH) $(CFLAGS)
default: $(TARGET)
openflow_mod.o: $(filter-out $(TARGET), $(CFILES:.c=.o))
$(LD) $(LDFLAGS) -r $^ -o $@
unit_mod.o: $(UNIT_CFILES:.c=.o)
$(LD) $(LDFLAGS) -r $^ -o $@
compat24_mod.o: $(COMPAT24_CFILES:.c=.o)
$(LD) $(LDFLAGS) -r $^ -o $@
ALL_CFILES = $(FILES) $(UNIT_CFILES) $(COMPAT24_CFILES)
$(ALL_CFILES:.c=.o): $(HFILES) Makefile
# depmod version for rpm builds
DEPVER := $(shell /sbin/depmod -V 2>/dev/null | \
awk 'BEGIN {FS="."} NR==1 {print $$2}')
.PHONY: clean
clean:
rm -rf $(TARGET) $(TARGET:.ko=.o) $(TARGET:.ko=.mod.c)\
$(TARGET:.ko=.mod.o) $(CFILES:.c=.o) $(COMPAT24_CFILES:.c=.o)\
$(UNIT_CFILES:.c=.o) $(MANFILE).gz .*cmd .tmp_versions\
compat24_mod.o unit_mod.o tmp/ \
+1
View File
@@ -0,0 +1 @@
KSRC=@KSRC24@
+15
View File
@@ -0,0 +1,15 @@
/Makefile
/datapath.c
/chain.c
/crc32.c
/crc_t.c
/flow.c
/forward.c
/kernel-src.inc
/table-hash.c
/table-linear.c
/table-mac.c
/table_t.c
/unit-exports.c
/unit.c
/tmp
+51
View File
@@ -0,0 +1,51 @@
export builddir = @abs_builddir@
export srcdir = @abs_srcdir@
export top_srcdir = @abs_top_srcdir@
export KSRC = @KSRCUML@
export KVERSION = 2.6
export VMDIR = @VMDIR@
export VERSION = @VERSION@
ARCH = um
export ARCH
CFLAGS_EXTRA += -DVERSION=\"$(VERSION)\"
CFLAGS_EXTRA += -I $(srcdir)/.. -I $(top_srcdir)/include
# Files shared between 2.4 and 2.6 builds
SHAREDFILES = ../chain.c ../crc32.c ../table-hash.c ../table-linear.c \
../table-mac.c ../forward.c ../flow.c ../unit-exports.c \
../datapath_t.c
HFILES = ../openflow.h ../chain.h ../crc32.h ../flow.h ../forward.h \
../table.h ../datapath_t.h
SIMLINKFILES = $(patsubst ../%,%, $(SHAREDFILES))
CFILES = openflow.c $(SIMLINKFILES)
# Testing files used for both 2.6 and 2.4 kernels. Are symlinked
# locally
SHARED_T_FILES = ../table_t.c ../crc_t.c ../unit.c
UNIT_CFILES = $(patsubst ../%,%, $(SHARED_T_FILES))
# General rule to create symlinks of shared files
%.c : ../%.c
ln -s $< $@
# Conditional include so that make dist doesn't puke when
# this build isn't turned on by automake
ifneq (,$(KSRC))
include $(srcdir)/kbuild.inc
else
clean:
endif
distclean : clean
distdir : clean
install :
all: default
check: all
@@ -0,0 +1,896 @@
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.23-rc3
# Wed Sep 26 08:31:01 2007
#
CONFIG_DEFCONFIG_LIST="arch/$ARCH/defconfig"
CONFIG_GENERIC_HARDIRQS=y
CONFIG_UML=y
CONFIG_MMU=y
CONFIG_NO_IOMEM=y
# CONFIG_TRACE_IRQFLAGS_SUPPORT is not set
CONFIG_LOCKDEP_SUPPORT=y
# CONFIG_STACKTRACE_SUPPORT is not set
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_BUG=y
CONFIG_IRQ_RELEASE_METHOD=y
#
# UML-specific options
#
# CONFIG_STATIC_LINK is not set
CONFIG_MODE_SKAS=y
#
# Host processor type and features
#
# CONFIG_M386 is not set
CONFIG_M486=y
# CONFIG_M586 is not set
# CONFIG_M586TSC is not set
# CONFIG_M586MMX is not set
# CONFIG_M686 is not set
# CONFIG_MPENTIUMII is not set
# CONFIG_MPENTIUMIII is not set
# CONFIG_MPENTIUMM is not set
# CONFIG_MCORE2 is not set
# CONFIG_MPENTIUM4 is not set
# CONFIG_MK6 is not set
# CONFIG_MK7 is not set
# CONFIG_MK8 is not set
# CONFIG_MCRUSOE is not set
# CONFIG_MEFFICEON is not set
# CONFIG_MWINCHIPC6 is not set
# CONFIG_MWINCHIP2 is not set
# CONFIG_MWINCHIP3D is not set
# CONFIG_MGEODEGX1 is not set
# CONFIG_MGEODE_LX is not set
# CONFIG_MCYRIXIII is not set
# CONFIG_MVIAC3_2 is not set
# CONFIG_MVIAC7 is not set
CONFIG_X86_GENERIC=y
CONFIG_X86_CMPXCHG=y
CONFIG_X86_L1_CACHE_SHIFT=7
CONFIG_X86_XADD=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
# CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_X86_PPRO_FENCE=y
CONFIG_X86_F00F_BUG=y
CONFIG_X86_WP_WORKS_OK=y
CONFIG_X86_INVLPG=y
CONFIG_X86_BSWAP=y
CONFIG_X86_POPAD_OK=y
CONFIG_X86_ALIGNMENT_16=y
CONFIG_X86_INTEL_USERCOPY=y
CONFIG_X86_MINIMUM_CPU_FAMILY=4
CONFIG_UML_X86=y
# CONFIG_64BIT is not set
CONFIG_SEMAPHORE_SLEEPERS=y
CONFIG_HOST_VMSPLIT_3G=y
# CONFIG_HOST_VMSPLIT_3G_OPT is not set
# CONFIG_HOST_VMSPLIT_2G is not set
# CONFIG_HOST_VMSPLIT_1G is not set
CONFIG_TOP_ADDR=0xC0000000
# CONFIG_3_LEVEL_PGTABLES is not set
CONFIG_STUB_CODE=0xbfffe000
CONFIG_STUB_DATA=0xbffff000
CONFIG_STUB_START=0xbfffe000
CONFIG_ARCH_HAS_SC_SIGNALS=y
CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
# CONFIG_DISCONTIGMEM_MANUAL is not set
# CONFIG_SPARSEMEM_MANUAL is not set
CONFIG_FLATMEM=y
CONFIG_FLAT_NODE_MEM_MAP=y
# CONFIG_SPARSEMEM_STATIC is not set
CONFIG_SPLIT_PTLOCK_CPUS=4
# CONFIG_RESOURCES_64BIT is not set
CONFIG_ZONE_DMA_FLAG=0
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
CONFIG_LD_SCRIPT_DYN=y
CONFIG_NET=y
CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_MISC=m
CONFIG_HOSTFS=m
# CONFIG_HPPFS is not set
CONFIG_MCONSOLE=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_NEST_LEVEL=0
CONFIG_HIGHMEM=y
CONFIG_KERNEL_STACK_ORDER=0
CONFIG_UML_REAL_TIME_CLOCK=y
#
# General setup
#
CONFIG_EXPERIMENTAL=y
CONFIG_BROKEN_ON_SMP=y
CONFIG_INIT_ENV_ARG_LIMIT=128
CONFIG_LOCALVERSION=""
# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
CONFIG_SYSVIPC_SYSCTL=y
CONFIG_POSIX_MQUEUE=y
CONFIG_BSD_PROCESS_ACCT=y
# CONFIG_BSD_PROCESS_ACCT_V3 is not set
CONFIG_TASKSTATS=y
CONFIG_TASK_DELAY_ACCT=y
CONFIG_TASK_XACCT=y
CONFIG_TASK_IO_ACCOUNTING=y
# CONFIG_USER_NS is not set
# CONFIG_AUDIT is not set
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_SYSFS_DEPRECATED=y
CONFIG_RELAY=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_SYSCTL=y
# CONFIG_EMBEDDED is not set
CONFIG_UID16=y
CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
CONFIG_KALLSYMS_ALL=y
CONFIG_KALLSYMS_EXTRA_PASS=y
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
CONFIG_ELF_CORE=y
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_ANON_INODES=y
CONFIG_EPOLL=y
CONFIG_SIGNALFD=y
CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_SLAB=y
# CONFIG_SLUB is not set
# CONFIG_SLOB is not set
CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_MODULE_FORCE_UNLOAD is not set
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_KMOD=y
CONFIG_BLOCK=y
CONFIG_LBD=y
CONFIG_BLK_DEV_IO_TRACE=y
CONFIG_LSF=y
# CONFIG_BLK_DEV_BSG is not set
#
# IO Schedulers
#
CONFIG_IOSCHED_NOOP=y
CONFIG_IOSCHED_AS=y
CONFIG_IOSCHED_DEADLINE=y
CONFIG_IOSCHED_CFQ=y
CONFIG_DEFAULT_AS=y
# CONFIG_DEFAULT_DEADLINE is not set
# CONFIG_DEFAULT_CFQ is not set
# CONFIG_DEFAULT_NOOP is not set
CONFIG_DEFAULT_IOSCHED="anticipatory"
CONFIG_BLK_DEV=y
CONFIG_BLK_DEV_UBD=y
# CONFIG_BLK_DEV_UBD_SYNC is not set
CONFIG_BLK_DEV_COW_COMMON=y
# CONFIG_MMAPPER is not set
CONFIG_BLK_DEV_LOOP=m
CONFIG_BLK_DEV_CRYPTOLOOP=m
CONFIG_BLK_DEV_NBD=m
CONFIG_BLK_DEV_RAM=m
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=4096
CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
# CONFIG_ATA_OVER_ETH is not set
#
# Character Devices
#
CONFIG_STDERR_CONSOLE=y
CONFIG_STDIO_CONSOLE=y
CONFIG_SSL=y
CONFIG_NULL_CHAN=y
CONFIG_PORT_CHAN=y
CONFIG_PTY_CHAN=y
CONFIG_TTY_CHAN=y
CONFIG_XTERM_CHAN=y
# CONFIG_NOCONFIG_CHAN is not set
CONFIG_CON_ZERO_CHAN="fd:0,fd:1"
CONFIG_CON_CHAN="xterm"
CONFIG_SSL_CHAN="pty"
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_RAW_DRIVER=m
CONFIG_MAX_RAW_DEVS=256
CONFIG_LEGACY_PTY_COUNT=256
CONFIG_WATCHDOG=y
CONFIG_WATCHDOG_NOWAYOUT=y
CONFIG_SOFT_WATCHDOG=y
CONFIG_UML_WATCHDOG=m
# CONFIG_UML_SOUND is not set
# CONFIG_SOUND is not set
# CONFIG_HOSTAUDIO is not set
# CONFIG_HW_RANDOM is not set
# CONFIG_UML_RANDOM is not set
#
# Generic Driver Options
#
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_FW_LOADER is not set
# CONFIG_DEBUG_DRIVER is not set
# CONFIG_DEBUG_DEVRES is not set
# CONFIG_SYS_HYPERVISOR is not set
#
# Networking
#
#
# Networking options
#
CONFIG_PACKET=y
CONFIG_PACKET_MMAP=y
CONFIG_UNIX=y
CONFIG_XFRM=y
CONFIG_XFRM_USER=m
CONFIG_XFRM_SUB_POLICY=y
CONFIG_XFRM_MIGRATE=y
CONFIG_NET_KEY=m
CONFIG_NET_KEY_MIGRATE=y
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
CONFIG_IP_ADVANCED_ROUTER=y
CONFIG_ASK_IP_FIB_HASH=y
# CONFIG_IP_FIB_TRIE is not set
CONFIG_IP_FIB_HASH=y
CONFIG_IP_MULTIPLE_TABLES=y
CONFIG_IP_ROUTE_MULTIPATH=y
# CONFIG_IP_ROUTE_VERBOSE is not set
# CONFIG_IP_PNP is not set
CONFIG_NET_IPIP=m
CONFIG_NET_IPGRE=m
CONFIG_NET_IPGRE_BROADCAST=y
CONFIG_IP_MROUTE=y
CONFIG_IP_PIMSM_V1=y
CONFIG_IP_PIMSM_V2=y
# CONFIG_ARPD is not set
CONFIG_SYN_COOKIES=y
CONFIG_INET_AH=m
CONFIG_INET_ESP=m
CONFIG_INET_IPCOMP=m
CONFIG_INET_XFRM_TUNNEL=m
CONFIG_INET_TUNNEL=m
CONFIG_INET_XFRM_MODE_TRANSPORT=m
CONFIG_INET_XFRM_MODE_TUNNEL=m
CONFIG_INET_XFRM_MODE_BEET=m
CONFIG_INET_DIAG=y
CONFIG_INET_TCP_DIAG=y
CONFIG_TCP_CONG_ADVANCED=y
CONFIG_TCP_CONG_BIC=m
CONFIG_TCP_CONG_CUBIC=y
CONFIG_TCP_CONG_WESTWOOD=m
CONFIG_TCP_CONG_HTCP=m
CONFIG_TCP_CONG_HSTCP=m
CONFIG_TCP_CONG_HYBLA=m
CONFIG_TCP_CONG_VEGAS=m
CONFIG_TCP_CONG_SCALABLE=m
CONFIG_TCP_CONG_LP=m
CONFIG_TCP_CONG_VENO=m
CONFIG_TCP_CONG_YEAH=m
CONFIG_TCP_CONG_ILLINOIS=m
# CONFIG_DEFAULT_BIC is not set
CONFIG_DEFAULT_CUBIC=y
# CONFIG_DEFAULT_HTCP is not set
# CONFIG_DEFAULT_VEGAS is not set
# CONFIG_DEFAULT_WESTWOOD is not set
# CONFIG_DEFAULT_RENO is not set
CONFIG_DEFAULT_TCP_CONG="cubic"
CONFIG_TCP_MD5SIG=y
# CONFIG_IP_VS is not set
CONFIG_IPV6=m
CONFIG_IPV6_PRIVACY=y
CONFIG_IPV6_ROUTER_PREF=y
CONFIG_IPV6_ROUTE_INFO=y
# CONFIG_IPV6_OPTIMISTIC_DAD is not set
CONFIG_INET6_AH=m
CONFIG_INET6_ESP=m
CONFIG_INET6_IPCOMP=m
# CONFIG_IPV6_MIP6 is not set
CONFIG_INET6_XFRM_TUNNEL=m
CONFIG_INET6_TUNNEL=m
CONFIG_INET6_XFRM_MODE_TRANSPORT=m
CONFIG_INET6_XFRM_MODE_TUNNEL=m
CONFIG_INET6_XFRM_MODE_BEET=m
# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
CONFIG_IPV6_SIT=m
CONFIG_IPV6_TUNNEL=m
CONFIG_IPV6_MULTIPLE_TABLES=y
CONFIG_IPV6_SUBTREES=y
CONFIG_NETWORK_SECMARK=y
CONFIG_NETFILTER=y
# CONFIG_NETFILTER_DEBUG is not set
CONFIG_BRIDGE_NETFILTER=y
#
# Core Netfilter Configuration
#
CONFIG_NETFILTER_NETLINK=m
CONFIG_NETFILTER_NETLINK_QUEUE=m
CONFIG_NETFILTER_NETLINK_LOG=m
CONFIG_NF_CONNTRACK_ENABLED=m
CONFIG_NF_CONNTRACK=m
CONFIG_NF_CT_ACCT=y
CONFIG_NF_CONNTRACK_MARK=y
CONFIG_NF_CONNTRACK_SECMARK=y
CONFIG_NF_CONNTRACK_EVENTS=y
CONFIG_NF_CT_PROTO_GRE=m
CONFIG_NF_CT_PROTO_SCTP=m
# CONFIG_NF_CT_PROTO_UDPLITE is not set
CONFIG_NF_CONNTRACK_AMANDA=m
CONFIG_NF_CONNTRACK_FTP=m
CONFIG_NF_CONNTRACK_H323=m
CONFIG_NF_CONNTRACK_IRC=m
CONFIG_NF_CONNTRACK_NETBIOS_NS=m
CONFIG_NF_CONNTRACK_PPTP=m
CONFIG_NF_CONNTRACK_SANE=m
CONFIG_NF_CONNTRACK_SIP=m
CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NF_CT_NETLINK=m
CONFIG_NETFILTER_XTABLES=m
CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
# CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set
# CONFIG_NETFILTER_XT_TARGET_DSCP is not set
CONFIG_NETFILTER_XT_TARGET_MARK=m
CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
CONFIG_NETFILTER_XT_TARGET_NFLOG=m
# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set
# CONFIG_NETFILTER_XT_TARGET_TRACE is not set
CONFIG_NETFILTER_XT_TARGET_SECMARK=m
CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m
CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
CONFIG_NETFILTER_XT_MATCH_COMMENT=m
CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set
CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
CONFIG_NETFILTER_XT_MATCH_DCCP=m
CONFIG_NETFILTER_XT_MATCH_DSCP=m
CONFIG_NETFILTER_XT_MATCH_ESP=m
CONFIG_NETFILTER_XT_MATCH_HELPER=m
CONFIG_NETFILTER_XT_MATCH_LENGTH=m
CONFIG_NETFILTER_XT_MATCH_LIMIT=m
CONFIG_NETFILTER_XT_MATCH_MAC=m
CONFIG_NETFILTER_XT_MATCH_MARK=m
CONFIG_NETFILTER_XT_MATCH_POLICY=m
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
CONFIG_NETFILTER_XT_MATCH_QUOTA=m
CONFIG_NETFILTER_XT_MATCH_REALM=m
CONFIG_NETFILTER_XT_MATCH_SCTP=m
CONFIG_NETFILTER_XT_MATCH_STATE=m
CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
CONFIG_NETFILTER_XT_MATCH_STRING=m
CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
# CONFIG_NETFILTER_XT_MATCH_U32 is not set
CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
#
# IP: Netfilter Configuration
#
CONFIG_NF_CONNTRACK_IPV4=m
CONFIG_NF_CONNTRACK_PROC_COMPAT=y
# CONFIG_IP_NF_QUEUE is not set
CONFIG_IP_NF_IPTABLES=m
CONFIG_IP_NF_MATCH_IPRANGE=m
CONFIG_IP_NF_MATCH_TOS=m
CONFIG_IP_NF_MATCH_RECENT=m
CONFIG_IP_NF_MATCH_ECN=m
CONFIG_IP_NF_MATCH_AH=m
CONFIG_IP_NF_MATCH_TTL=m
CONFIG_IP_NF_MATCH_OWNER=m
CONFIG_IP_NF_MATCH_ADDRTYPE=m
CONFIG_IP_NF_FILTER=m
CONFIG_IP_NF_TARGET_REJECT=m
CONFIG_IP_NF_TARGET_LOG=m
CONFIG_IP_NF_TARGET_ULOG=m
CONFIG_NF_NAT=m
CONFIG_NF_NAT_NEEDED=y
CONFIG_IP_NF_TARGET_MASQUERADE=m
CONFIG_IP_NF_TARGET_REDIRECT=m
CONFIG_IP_NF_TARGET_NETMAP=m
CONFIG_IP_NF_TARGET_SAME=m
CONFIG_NF_NAT_SNMP_BASIC=m
CONFIG_NF_NAT_PROTO_GRE=m
CONFIG_NF_NAT_FTP=m
CONFIG_NF_NAT_IRC=m
CONFIG_NF_NAT_TFTP=m
CONFIG_NF_NAT_AMANDA=m
CONFIG_NF_NAT_PPTP=m
CONFIG_NF_NAT_H323=m
CONFIG_NF_NAT_SIP=m
CONFIG_IP_NF_MANGLE=m
CONFIG_IP_NF_TARGET_TOS=m
CONFIG_IP_NF_TARGET_ECN=m
CONFIG_IP_NF_TARGET_TTL=m
CONFIG_IP_NF_TARGET_CLUSTERIP=m
CONFIG_IP_NF_RAW=m
CONFIG_IP_NF_ARPTABLES=m
CONFIG_IP_NF_ARPFILTER=m
CONFIG_IP_NF_ARP_MANGLE=m
#
# IPv6: Netfilter Configuration (EXPERIMENTAL)
#
CONFIG_NF_CONNTRACK_IPV6=m
# CONFIG_IP6_NF_QUEUE is not set
CONFIG_IP6_NF_IPTABLES=m
CONFIG_IP6_NF_MATCH_RT=m
CONFIG_IP6_NF_MATCH_OPTS=m
CONFIG_IP6_NF_MATCH_FRAG=m
CONFIG_IP6_NF_MATCH_HL=m
CONFIG_IP6_NF_MATCH_OWNER=m
CONFIG_IP6_NF_MATCH_IPV6HEADER=m
CONFIG_IP6_NF_MATCH_AH=m
CONFIG_IP6_NF_MATCH_MH=m
CONFIG_IP6_NF_MATCH_EUI64=m
CONFIG_IP6_NF_FILTER=m
CONFIG_IP6_NF_TARGET_LOG=m
CONFIG_IP6_NF_TARGET_REJECT=m
CONFIG_IP6_NF_MANGLE=m
CONFIG_IP6_NF_TARGET_HL=m
CONFIG_IP6_NF_RAW=m
#
# DECnet: Netfilter Configuration
#
# CONFIG_DECNET_NF_GRABULATOR is not set
#
# Bridge: Netfilter Configuration
#
# CONFIG_BRIDGE_NF_EBTABLES is not set
CONFIG_IP_DCCP=m
CONFIG_INET_DCCP_DIAG=m
CONFIG_IP_DCCP_ACKVEC=y
#
# DCCP CCIDs Configuration (EXPERIMENTAL)
#
CONFIG_IP_DCCP_CCID2=m
# CONFIG_IP_DCCP_CCID2_DEBUG is not set
CONFIG_IP_DCCP_CCID3=m
CONFIG_IP_DCCP_TFRC_LIB=m
# CONFIG_IP_DCCP_CCID3_DEBUG is not set
CONFIG_IP_DCCP_CCID3_RTO=100
#
# DCCP Kernel Hacking
#
# CONFIG_IP_DCCP_DEBUG is not set
CONFIG_IP_SCTP=m
# CONFIG_SCTP_DBG_MSG is not set
# CONFIG_SCTP_DBG_OBJCNT is not set
# CONFIG_SCTP_HMAC_NONE is not set
# CONFIG_SCTP_HMAC_SHA1 is not set
CONFIG_SCTP_HMAC_MD5=y
CONFIG_TIPC=m
CONFIG_TIPC_ADVANCED=y
CONFIG_TIPC_ZONES=3
CONFIG_TIPC_CLUSTERS=1
CONFIG_TIPC_NODES=255
CONFIG_TIPC_SLAVE_NODES=0
CONFIG_TIPC_PORTS=8191
CONFIG_TIPC_LOG=0
# CONFIG_TIPC_DEBUG is not set
CONFIG_ATM=m
CONFIG_ATM_CLIP=m
# CONFIG_ATM_CLIP_NO_ICMP is not set
CONFIG_ATM_LANE=m
# CONFIG_ATM_MPOA is not set
CONFIG_ATM_BR2684=m
CONFIG_ATM_BR2684_IPFILTER=y
CONFIG_BRIDGE=m
CONFIG_VLAN_8021Q=m
CONFIG_DECNET=m
# CONFIG_DECNET_ROUTER is not set
CONFIG_LLC=m
CONFIG_LLC2=m
CONFIG_IPX=m
CONFIG_IPX_INTERN=y
CONFIG_ATALK=m
CONFIG_DEV_APPLETALK=m
CONFIG_IPDDP=m
CONFIG_IPDDP_ENCAP=y
CONFIG_IPDDP_DECAP=y
CONFIG_X25=m
CONFIG_LAPB=m
CONFIG_ECONET=m
CONFIG_ECONET_AUNUDP=y
CONFIG_ECONET_NATIVE=y
CONFIG_WAN_ROUTER=m
#
# QoS and/or fair queueing
#
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_FIFO=y
#
# Queueing/Scheduling
#
CONFIG_NET_SCH_CBQ=m
CONFIG_NET_SCH_HTB=m
CONFIG_NET_SCH_HFSC=m
CONFIG_NET_SCH_ATM=m
CONFIG_NET_SCH_PRIO=m
# CONFIG_NET_SCH_RR is not set
CONFIG_NET_SCH_RED=m
CONFIG_NET_SCH_SFQ=m
CONFIG_NET_SCH_TEQL=m
CONFIG_NET_SCH_TBF=m
CONFIG_NET_SCH_GRED=m
CONFIG_NET_SCH_DSMARK=m
CONFIG_NET_SCH_NETEM=m
CONFIG_NET_SCH_INGRESS=m
#
# Classification
#
CONFIG_NET_CLS=y
CONFIG_NET_CLS_BASIC=m
CONFIG_NET_CLS_TCINDEX=m
CONFIG_NET_CLS_ROUTE4=m
CONFIG_NET_CLS_ROUTE=y
CONFIG_NET_CLS_FW=m
CONFIG_NET_CLS_U32=m
CONFIG_CLS_U32_PERF=y
CONFIG_CLS_U32_MARK=y
CONFIG_NET_CLS_RSVP=m
CONFIG_NET_CLS_RSVP6=m
CONFIG_NET_EMATCH=y
CONFIG_NET_EMATCH_STACK=32
CONFIG_NET_EMATCH_CMP=m
CONFIG_NET_EMATCH_NBYTE=m
CONFIG_NET_EMATCH_U32=m
CONFIG_NET_EMATCH_META=m
CONFIG_NET_EMATCH_TEXT=m
CONFIG_NET_CLS_ACT=y
CONFIG_NET_ACT_POLICE=m
CONFIG_NET_ACT_GACT=m
CONFIG_GACT_PROB=y
CONFIG_NET_ACT_MIRRED=m
CONFIG_NET_ACT_IPT=m
CONFIG_NET_ACT_PEDIT=m
CONFIG_NET_ACT_SIMP=m
# CONFIG_NET_CLS_POLICE is not set
CONFIG_NET_CLS_IND=y
#
# Network testing
#
# CONFIG_NET_PKTGEN is not set
# CONFIG_HAMRADIO is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
CONFIG_AF_RXRPC=m
# CONFIG_AF_RXRPC_DEBUG is not set
CONFIG_RXKAD=m
CONFIG_FIB_RULES=y
#
# Wireless
#
# CONFIG_CFG80211 is not set
# CONFIG_WIRELESS_EXT is not set
# CONFIG_MAC80211 is not set
# CONFIG_IEEE80211 is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
#
# UML Network Devices
#
CONFIG_UML_NET=y
CONFIG_UML_NET_ETHERTAP=y
CONFIG_UML_NET_TUNTAP=y
CONFIG_UML_NET_SLIP=y
CONFIG_UML_NET_DAEMON=y
CONFIG_UML_NET_MCAST=y
CONFIG_UML_NET_PCAP=y
CONFIG_UML_NET_SLIRP=y
CONFIG_NETDEVICES=y
# CONFIG_NETDEVICES_MULTIQUEUE is not set
# CONFIG_IFB is not set
CONFIG_DUMMY=m
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
# CONFIG_EQUALIZER is not set
CONFIG_TUN=m
#
# Wireless LAN
#
# CONFIG_WLAN_PRE80211 is not set
# CONFIG_WLAN_80211 is not set
# CONFIG_WAN is not set
CONFIG_ATM_DRIVERS=y
# CONFIG_ATM_DUMMY is not set
# CONFIG_ATM_TCP is not set
# CONFIG_PPP is not set
# CONFIG_SLIP is not set
# CONFIG_SHAPER is not set
# CONFIG_NETCONSOLE is not set
# CONFIG_NETPOLL is not set
# CONFIG_NET_POLL_CONTROLLER is not set
CONFIG_CONNECTOR=m
#
# File systems
#
# CONFIG_EXT2_FS is not set
CONFIG_EXT3_FS=y
CONFIG_EXT3_FS_XATTR=y
CONFIG_EXT3_FS_POSIX_ACL=y
CONFIG_EXT3_FS_SECURITY=y
# CONFIG_EXT4DEV_FS is not set
CONFIG_JBD=y
# CONFIG_JBD_DEBUG is not set
CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
CONFIG_FS_POSIX_ACL=y
# CONFIG_XFS_FS is not set
# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_MINIX_FS is not set
CONFIG_ROMFS_FS=m
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
# CONFIG_FUSE_FS is not set
CONFIG_GENERIC_ACL=y
#
# CD-ROM/DVD Filesystems
#
CONFIG_ISO9660_FS=y
CONFIG_JOLIET=y
CONFIG_ZISOFS=y
CONFIG_UDF_FS=y
CONFIG_UDF_NLS=y
#
# DOS/FAT/NT Filesystems
#
# CONFIG_MSDOS_FS is not set
# CONFIG_VFAT_FS is not set
# CONFIG_NTFS_FS is not set
#
# Pseudo filesystems
#
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
CONFIG_TMPFS=y
CONFIG_TMPFS_POSIX_ACL=y
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
CONFIG_CONFIGFS_FS=m
#
# Miscellaneous filesystems
#
# CONFIG_ADFS_FS is not set
# CONFIG_AFFS_FS is not set
# CONFIG_ECRYPT_FS is not set
# CONFIG_HFS_FS is not set
# CONFIG_HFSPLUS_FS is not set
# CONFIG_BEFS_FS is not set
# CONFIG_BFS_FS is not set
# CONFIG_EFS_FS is not set
CONFIG_CRAMFS=m
# CONFIG_VXFS_FS is not set
# CONFIG_HPFS_FS is not set
# CONFIG_QNX4FS_FS is not set
# CONFIG_SYSV_FS is not set
# CONFIG_UFS_FS is not set
#
# Network File Systems
#
# CONFIG_NFS_FS is not set
# CONFIG_NFSD is not set
# CONFIG_SMB_FS is not set
# CONFIG_CIFS is not set
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
#
# Partition Types
#
# CONFIG_PARTITION_ADVANCED is not set
CONFIG_MSDOS_PARTITION=y
#
# Native Language Support
#
CONFIG_NLS=y
CONFIG_NLS_DEFAULT="iso8859-1"
CONFIG_NLS_CODEPAGE_437=m
CONFIG_NLS_CODEPAGE_737=m
CONFIG_NLS_CODEPAGE_775=m
CONFIG_NLS_CODEPAGE_850=m
CONFIG_NLS_CODEPAGE_852=m
CONFIG_NLS_CODEPAGE_855=m
CONFIG_NLS_CODEPAGE_857=m
CONFIG_NLS_CODEPAGE_860=m
CONFIG_NLS_CODEPAGE_861=m
CONFIG_NLS_CODEPAGE_862=m
CONFIG_NLS_CODEPAGE_863=m
CONFIG_NLS_CODEPAGE_864=m
CONFIG_NLS_CODEPAGE_865=m
CONFIG_NLS_CODEPAGE_866=m
CONFIG_NLS_CODEPAGE_869=m
CONFIG_NLS_CODEPAGE_936=m
CONFIG_NLS_CODEPAGE_950=m
CONFIG_NLS_CODEPAGE_932=m
CONFIG_NLS_CODEPAGE_949=m
CONFIG_NLS_CODEPAGE_874=m
CONFIG_NLS_ISO8859_8=m
CONFIG_NLS_CODEPAGE_1250=m
CONFIG_NLS_CODEPAGE_1251=m
CONFIG_NLS_ASCII=m
CONFIG_NLS_ISO8859_1=m
CONFIG_NLS_ISO8859_2=m
CONFIG_NLS_ISO8859_3=m
CONFIG_NLS_ISO8859_4=m
CONFIG_NLS_ISO8859_5=m
CONFIG_NLS_ISO8859_6=m
CONFIG_NLS_ISO8859_7=m
CONFIG_NLS_ISO8859_9=m
CONFIG_NLS_ISO8859_13=m
CONFIG_NLS_ISO8859_14=m
CONFIG_NLS_ISO8859_15=m
CONFIG_NLS_KOI8_R=m
CONFIG_NLS_KOI8_U=m
CONFIG_NLS_UTF8=m
#
# Distributed Lock Manager
#
# CONFIG_DLM is not set
#
# Security options
#
CONFIG_KEYS=y
# CONFIG_KEYS_DEBUG_PROC_KEYS is not set
# CONFIG_SECURITY is not set
CONFIG_CRYPTO=y
CONFIG_CRYPTO_ALGAPI=y
CONFIG_CRYPTO_BLKCIPHER=m
CONFIG_CRYPTO_HASH=m
CONFIG_CRYPTO_MANAGER=m
CONFIG_CRYPTO_HMAC=m
# CONFIG_CRYPTO_XCBC is not set
CONFIG_CRYPTO_NULL=m
CONFIG_CRYPTO_MD4=m
CONFIG_CRYPTO_MD5=y
CONFIG_CRYPTO_SHA1=m
CONFIG_CRYPTO_SHA256=m
# CONFIG_CRYPTO_SHA512 is not set
# CONFIG_CRYPTO_WP512 is not set
# CONFIG_CRYPTO_TGR192 is not set
CONFIG_CRYPTO_GF128MUL=m
# CONFIG_CRYPTO_ECB is not set
CONFIG_CRYPTO_CBC=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_LRW=m
# CONFIG_CRYPTO_CRYPTD is not set
CONFIG_CRYPTO_DES=m
CONFIG_CRYPTO_FCRYPT=m
# CONFIG_CRYPTO_BLOWFISH is not set
# CONFIG_CRYPTO_TWOFISH is not set
# CONFIG_CRYPTO_TWOFISH_586 is not set
# CONFIG_CRYPTO_SERPENT is not set
CONFIG_CRYPTO_AES=m
# CONFIG_CRYPTO_AES_586 is not set
# CONFIG_CRYPTO_CAST5 is not set
# CONFIG_CRYPTO_CAST6 is not set
CONFIG_CRYPTO_TEA=m
# CONFIG_CRYPTO_ARC4 is not set
# CONFIG_CRYPTO_KHAZAD is not set
# CONFIG_CRYPTO_ANUBIS is not set
CONFIG_CRYPTO_DEFLATE=m
# CONFIG_CRYPTO_MICHAEL_MIC is not set
# CONFIG_CRYPTO_CRC32C is not set
# CONFIG_CRYPTO_CAMELLIA is not set
# CONFIG_CRYPTO_TEST is not set
CONFIG_CRYPTO_HW=y
#
# Library routines
#
CONFIG_BITREVERSE=y
CONFIG_CRC_CCITT=m
CONFIG_CRC16=m
CONFIG_CRC_ITU_T=m
CONFIG_CRC32=y
# CONFIG_CRC7 is not set
CONFIG_LIBCRC32C=m
CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=m
CONFIG_TEXTSEARCH=y
CONFIG_TEXTSEARCH_KMP=m
CONFIG_TEXTSEARCH_BM=m
CONFIG_TEXTSEARCH_FSM=m
CONFIG_PLIST=y
CONFIG_HAS_DMA=y
#
# SCSI device support
#
# CONFIG_RAID_ATTRS is not set
# CONFIG_SCSI is not set
# CONFIG_SCSI_DMA is not set
# CONFIG_SCSI_NETLINK is not set
# CONFIG_MD is not set
# CONFIG_INPUT is not set
#
# Kernel hacking
#
# CONFIG_PRINTK_TIME is not set
# CONFIG_ENABLE_MUST_CHECK is not set
# CONFIG_UNUSED_SYMBOLS is not set
CONFIG_DEBUG_FS=y
CONFIG_DEBUG_KERNEL=y
# CONFIG_DEBUG_SHIRQ is not set
CONFIG_DETECT_SOFTLOCKUP=y
CONFIG_SCHED_DEBUG=y
# CONFIG_SCHEDSTATS is not set
# CONFIG_TIMER_STATS is not set
CONFIG_DEBUG_SLAB=y
CONFIG_DEBUG_SLAB_LEAK=y
CONFIG_DEBUG_RT_MUTEXES=y
CONFIG_DEBUG_PI_LIST=y
# CONFIG_RT_MUTEX_TESTER is not set
CONFIG_DEBUG_SPINLOCK=y
CONFIG_DEBUG_MUTEXES=y
CONFIG_DEBUG_SPINLOCK_SLEEP=y
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
# CONFIG_DEBUG_HIGHMEM is not set
CONFIG_DEBUG_BUGVERBOSE=y
CONFIG_DEBUG_INFO=y
# CONFIG_DEBUG_VM is not set
CONFIG_DEBUG_LIST=y
CONFIG_FRAME_POINTER=y
CONFIG_FORCED_INLINING=y
CONFIG_RCU_TORTURE_TEST=m
# CONFIG_FAULT_INJECTION is not set
# CONFIG_GPROF is not set
# CONFIG_GCOV is not set
# CONFIG_DEBUG_STACK_USAGE is not set
+210
View File
@@ -0,0 +1,210 @@
# The remainder of this file is from Intel's e1000 distribution,
# with the following license:
################################################################################
#
# Intel PRO/1000 Linux driver
# Copyright(c) 1999 - 2007 Intel Corporation.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms and conditions of the GNU General Public License,
# version 2, as published by the Free Software Foundation.
#
# This program is distributed in the hope it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
#
# The full GNU General Public License is included in this distribution in
# the file called "COPYING".
#
# Contact Information:
# Linux NICS <linux.nics@intel.com>
# e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
# Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
#
################################################################################
ifeq (,$(BUILD_KERNEL))
BUILD_KERNEL=$(shell uname -r)
endif
###########################################################################
# Environment tests
CC := gcc cc
CFLAGS += $(CFLAGS_EXTRA)
ifeq (,$(KSRC))
$(error Linux kernel source not found)
else
ifeq (/lib/modules/$(shell uname -r)/source, $(KSRC))
KOBJ := /lib/modules/$(shell uname -r)/build
else
KOBJ := $(KSRC)
endif
endif
# version 2.4 or 2.6? (we assume 2.2 isn't in use anymore
K_VERSION:=$(shell if grep -q 'PATCHLEVEL = 4' $(KSRC)/Makefile; then echo 2.4; else echo 2.6; fi)
ifneq ($(K_VERSION),2.6)
$(error Linux kernel source not not 2.6)
endif
# check for version.h and autoconf.h for running kernel in /boot (SUSE)
ifneq (,$(wildcard /boot/vmlinuz.version.h))
VERSION_FILE := /boot/vmlinuz.version.h
CONFIG_FILE := /boot/vmlinuz.autoconf.h
KVER := $(shell $(CC) $(CFLAGS) -E -dM $(VERSION_FILE) | \
grep UTS_RELEASE | awk '{ print $$3 }' | sed 's/\"//g')
ifeq ($(KVER),$(shell uname -r))
# set up include path to override headers from kernel source
x:=$(shell rm -rf include)
x:=$(shell mkdir -p include/linux)
x:=$(shell cp /boot/vmlinuz.version.h include/linux/version.h)
x:=$(shell cp /boot/vmlinuz.autoconf.h include/linux/autoconf.h)
CFLAGS += -I./include
else
ifneq (,$(wildcard $(KOBJ)/include/linux/utsrelease.h))
VERSION_FILE := $(KOBJ)/include/linux/utsrelease.h
else
VERSION_FILE := $(KOBJ)/include/linux/version.h
endif
CONFIG_FILE := $(KSRC)/include/linux/autoconf.h
endif
else
ifneq (,$(wildcard $(KOBJ)/include/linux/utsrelease.h))
VERSION_FILE := $(KOBJ)/include/linux/utsrelease.h
else
VERSION_FILE := $(KOBJ)/include/linux/version.h
endif
CONFIG_FILE := $(KSRC)/include/linux/autoconf.h
endif
ifeq (,$(wildcard $(VERSION_FILE)))
$(error Linux kernel source not configured - missing version.h)
endif
ifeq (,$(wildcard $(CONFIG_FILE)))
$(error Linux kernel source not configured - missing autoconf.h)
endif
test_cc = $(shell $(cc) --version > /dev/null 2>&1 && echo $(cc))
CC := $(foreach cc, $(CC), $(test_cc))
CC := $(firstword $(CC))
ifeq (,$(CC))
$(error Compiler not found)
endif
# we need to know what platform the driver is being built on
# some additional features are only built on Intel platforms
ARCH := $(shell uname -m | sed 's/i.86/i386/')
ifeq ($(ARCH),alpha)
CFLAGS += -ffixed-8 -mno-fp-regs
endif
ifeq ($(ARCH),x86_64)
CFLAGS += -mcmodel=kernel -mno-red-zone
endif
ifeq ($(ARCH),ppc)
CFLAGS += -msoft-float
endif
ifeq ($(ARCH),ppc64)
CFLAGS += -m64 -msoft-float
LDFLAGS += -melf64ppc
endif
# standard flags for module builds
CFLAGS += -DLINUX -D__KERNEL__ -DMODULE -O2 -pipe -Wall
CFLAGS += -I$(KSRC)/include -I.
CFLAGS += $(shell [ -f $(KSRC)/include/linux/modversions.h ] && \
echo "-DMODVERSIONS -DEXPORT_SYMTAB \
-include $(KSRC)/include/linux/modversions.h")
RHC := $(KSRC)/include/linux/rhconfig.h
ifneq (,$(wildcard $(RHC)))
# 7.3 typo in rhconfig.h
ifneq (,$(shell $(CC) $(CFLAGS) -E -dM $(RHC) | grep __module__bigmem))
CFLAGS += -D__module_bigmem
endif
endif
# get the kernel version - we use this to find the correct install path
KVER := $(shell $(CC) $(CFLAGS) -E -dM $(VERSION_FILE) | grep UTS_RELEASE | \
awk '{ print $$3 }' | sed 's/\"//g')
# assume source symlink is the same as build, otherwise adjust KOBJ
ifneq (,$(wildcard /lib/modules/$(KVER)/build))
ifneq ($(KSRC),$(shell cd /lib/modules/$(KVER)/build ; pwd -P))
KOBJ=/lib/modules/$(KVER)/build
endif
endif
KKVER := $(shell echo $(KVER) | \
awk '{ if ($$0 ~ /2\.[6]\./) print "1"; else print "0"}')
ifeq ($(KKVER), 0)
$(error *** Aborting the build. \
*** This driver is not supported on kernel versions older than 2.6.0)
endif
# look for SMP in config.h
SMP := $(shell $(CC) $(CFLAGS) -E -dM $(CONFIG_FILE) | \
grep -w CONFIG_SMP | awk '{ print $$3 }')
ifneq ($(SMP),1)
SMP := 0
endif
#ifneq ($(SMP),$(shell uname -a | grep SMP > /dev/null 2>&1 && echo 1 || echo 0))
# $(warning ***)
# ifeq ($(SMP),1)
# $(warning *** Warning: kernel source configuration (SMP))
# $(warning *** does not match running kernel (UP))
# else
# $(warning *** Warning: kernel source configuration (UP))
# $(warning *** does not match running kernel (SMP))
# endif
# $(warning *** Continuing with build,)
# $(warning *** resulting driver may not be what you want)
# $(warning ***)
#endif
ifeq ($(SMP),1)
CFLAGS += -D__SMP__
endif
###########################################################################
# Makefile for 2.6.x kernel
all: $(TARGET)
TARGET = openflow_mod.ko unit_mod.ko
$(UNIT_CFILES):
$(foreach UNIT_CFILE, $(UNIT_CFILES), $(shell ln -s $(patsubst %,../t/%,$(UNIT_CFILE)) $(UNIT_CFILE)))
ifneq ($(PATCHLEVEL),)
EXTRA_CFLAGS += $(CFLAGS_EXTRA)
obj-m += openflow_mod.o unit_mod.o
openflow_mod-objs := $(CFILES:.c=.o)
unit_mod-objs := $(UNIT_CFILES:.c=.o)
else
default:
ifeq ($(KOBJ),$(KSRC))
$(MAKE) -C $(KSRC) SUBDIRS=$(shell pwd) modules
else
$(MAKE) -C $(KSRC) O=$(KOBJ) SUBDIRS=$(shell pwd) modules
endif
endif
# depmod version for rpm builds
DEPVER := $(shell /sbin/depmod -V 2>/dev/null | \
awk 'BEGIN {FS="."} NR==1 {print $$2}')
.PHONY: clean
clean:
rm -rf $(TARGET) $(TARGET:.ko=.o) $(TARGET:.ko=.mod.c) \
$(TARGET:.ko=.mod.o) $(CFILES:.c=.o) $(MANFILE).gz .*cmd \
.tmp_versions t/ tmp/
+18
View File
@@ -0,0 +1,18 @@
/Makefile
/datapath.c
/chain.c
/crc32.c
/crc_t.c
/dp_dev.c
/flow.c
/forward.c
/forward_t.c
/datapath_t.c
/kernel-src.inc
/table-hash.c
/table-linear.c
/table-mac.c
/table_t.c
/unit-exports.c
/unit.c
/tmp
+65
View File
@@ -0,0 +1,65 @@
export builddir = @abs_builddir@
export srcdir = @abs_srcdir@
export top_srcdir = @abs_top_srcdir@
export KSRC = @KSRC26@
export KVERSION = 2.6
export VMDIR = @VMDIR@
export VERSION = @VERSION@
CFLAGS_EXTRA += -DVERSION=\"$(VERSION)\"
CFLAGS_EXTRA += -I $(srcdir)/.. -I $(srcdir)/datapath/ -I $(top_srcdir)/include
# Files shared between 2.4 and 2.6 builds
SHAREDFILES = ../chain.c ../crc32.c ../table-hash.c ../table-linear.c \
../table-mac.c ../forward.c ../flow.c ../unit-exports.c \
../datapath_t.c ../dp_dev.c \
compat-2.6/genetlink.c \
compat-2.6/random32.c
HFILES = ../datapath.h ../chain.h ../crc32.h ../flow.h ../forward.h \
../table.h ../datapath_t.h \
compat-2.6/include/compat26.h \
compat-2.6/include/linux/ip.h \
compat-2.6/include/linux/ipv6.h \
compat-2.6/include/linux/lockdep.h \
compat-2.6/include/linux/mutex.h \
compat-2.6/include/linux/netlink.h \
compat-2.6/include/linux/random.h \
compat-2.6/include/linux/skbuff.h \
compat-2.6/include/linux/tcp.h \
compat-2.6/include/linux/timer.h \
compat-2.6/include/linux/types.h \
compat-2.6/include/linux/udp.h \
compat-2.6/include/net/checksum.h \
compat-2.6/include/net/genetlink.h
SIMLINKFILES = $(patsubst ../%,%, $(SHAREDFILES))
CFILES = datapath.c $(SIMLINKFILES)
# Testing files used for both 2.6 and 2.4 kernels. Are symlinked
# locally
SHARED_T_FILES = ../table_t.c ../crc_t.c ../forward_t.c ../unit.c
UNIT_CFILES = $(patsubst ../%,%, $(SHARED_T_FILES))
# General rule to create symlinks of shared files
%.c : ../%.c
ln -s $< $@
# Conditional include so that make dist doesn't puke when
# this build isn't turned on by automake
ifneq (,$(KSRC))
include $(srcdir)/kbuild.inc
else
clean:
endif
distclean : clean
distdir : clean
install :
all: default
check: all
+25
View File
@@ -0,0 +1,25 @@
#ifndef __COMPAT26_H
#define __COMPAT26_H 1
#include <linux/version.h>
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23)
/*----------------------------------------------------------------------------
* In 2.6.24, a namespace argument became required for dev_get_by_name. */
#define net_init NULL
#define dev_get_by_name(net, name) \
dev_get_by_name((name))
#endif /* linux kernel <= 2.6.23 */
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)
/*----------------------------------------------------------------------------
* In 2.6.23, the last argument was dropped from kmem_cache_create. */
#define kmem_cache_create(n, s, a, f, c) \
kmem_cache_create((n), (s), (a), (f), (c), NULL)
#endif /* linux kernel <= 2.6.22 */
#endif /* compat26.h */
+15
View File
@@ -0,0 +1,15 @@
#include "net/genetlink.h"
#include <linux/version.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
int genl_register_mc_group(struct genl_family *family,
struct genl_multicast_group *grp)
{
grp->id = 1;
grp->family = family;
return 0;
}
#endif /* kernel < 2.6.23 */
@@ -0,0 +1,20 @@
#ifndef __LINUX_IP_WRAPPER_H
#define __LINUX_IP_WRAPPER_H 1
#include_next <linux/ip.h>
#include <linux/version.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
#ifdef __KERNEL__
#include <linux/skbuff.h>
static inline struct iphdr *ip_hdr(const struct sk_buff *skb)
{
return (struct iphdr *)skb_network_header(skb);
}
#endif /* __KERNEL__ */
#endif /* linux kernel < 2.6.22 */
#endif
@@ -0,0 +1,20 @@
#ifndef __LINUX_IPV6_WRAPPER_H
#define __LINUX_IPV6_WRAPPER_H 1
#include_next <linux/ipv6.h>
#include <linux/version.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
#ifdef __KERNEL__
#include <linux/skbuff.h>
static inline struct ipv6hdr *ipv6_hdr(const struct sk_buff *skb)
{
return (struct ipv6hdr *)skb_network_header(skb);
}
#endif /* __KERNEL__ */
#endif /* linux kernel < 2.6.22 */
#endif
@@ -0,0 +1,450 @@
/*
* Runtime locking correctness validator
*
* Copyright (C) 2006,2007 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
* Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
*
* see Documentation/lockdep-design.txt for more details.
*/
#ifndef __LINUX_LOCKDEP_WRAPPER_H
#define __LINUX_LOCKDEP_WRAPPER_H
#include_next <linux/lockdep.h>
#include <linux/version.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
struct task_struct;
struct lockdep_map;
#ifdef CONFIG_LOCKDEP
#include <linux/linkage.h>
#include <linux/list.h>
#include <linux/debug_locks.h>
#include <linux/stacktrace.h>
/*
* Lock-class usage-state bits:
*/
enum lock_usage_bit
{
LOCK_USED = 0,
LOCK_USED_IN_HARDIRQ,
LOCK_USED_IN_SOFTIRQ,
LOCK_ENABLED_SOFTIRQS,
LOCK_ENABLED_HARDIRQS,
LOCK_USED_IN_HARDIRQ_READ,
LOCK_USED_IN_SOFTIRQ_READ,
LOCK_ENABLED_SOFTIRQS_READ,
LOCK_ENABLED_HARDIRQS_READ,
LOCK_USAGE_STATES
};
/*
* Usage-state bitmasks:
*/
#define LOCKF_USED (1 << LOCK_USED)
#define LOCKF_USED_IN_HARDIRQ (1 << LOCK_USED_IN_HARDIRQ)
#define LOCKF_USED_IN_SOFTIRQ (1 << LOCK_USED_IN_SOFTIRQ)
#define LOCKF_ENABLED_HARDIRQS (1 << LOCK_ENABLED_HARDIRQS)
#define LOCKF_ENABLED_SOFTIRQS (1 << LOCK_ENABLED_SOFTIRQS)
#define LOCKF_ENABLED_IRQS (LOCKF_ENABLED_HARDIRQS | LOCKF_ENABLED_SOFTIRQS)
#define LOCKF_USED_IN_IRQ (LOCKF_USED_IN_HARDIRQ | LOCKF_USED_IN_SOFTIRQ)
#define LOCKF_USED_IN_HARDIRQ_READ (1 << LOCK_USED_IN_HARDIRQ_READ)
#define LOCKF_USED_IN_SOFTIRQ_READ (1 << LOCK_USED_IN_SOFTIRQ_READ)
#define LOCKF_ENABLED_HARDIRQS_READ (1 << LOCK_ENABLED_HARDIRQS_READ)
#define LOCKF_ENABLED_SOFTIRQS_READ (1 << LOCK_ENABLED_SOFTIRQS_READ)
#define LOCKF_ENABLED_IRQS_READ \
(LOCKF_ENABLED_HARDIRQS_READ | LOCKF_ENABLED_SOFTIRQS_READ)
#define LOCKF_USED_IN_IRQ_READ \
(LOCKF_USED_IN_HARDIRQ_READ | LOCKF_USED_IN_SOFTIRQ_READ)
#define MAX_LOCKDEP_SUBCLASSES 8UL
/*
* Lock-classes are keyed via unique addresses, by embedding the
* lockclass-key into the kernel (or module) .data section. (For
* static locks we use the lock address itself as the key.)
*/
struct lockdep_subclass_key {
char __one_byte;
} __attribute__ ((__packed__));
struct lock_class_key {
struct lockdep_subclass_key subkeys[MAX_LOCKDEP_SUBCLASSES];
};
/*
* The lock-class itself:
*/
struct lock_class {
/*
* class-hash:
*/
struct list_head hash_entry;
/*
* global list of all lock-classes:
*/
struct list_head lock_entry;
struct lockdep_subclass_key *key;
unsigned int subclass;
/*
* IRQ/softirq usage tracking bits:
*/
unsigned long usage_mask;
struct stack_trace usage_traces[LOCK_USAGE_STATES];
/*
* These fields represent a directed graph of lock dependencies,
* to every node we attach a list of "forward" and a list of
* "backward" graph nodes.
*/
struct list_head locks_after, locks_before;
/*
* Generation counter, when doing certain classes of graph walking,
* to ensure that we check one node only once:
*/
unsigned int version;
/*
* Statistics counter:
*/
unsigned long ops;
const char *name;
int name_version;
#ifdef CONFIG_LOCK_STAT
unsigned long contention_point[4];
#endif
};
#ifdef CONFIG_LOCK_STAT
struct lock_time {
s64 min;
s64 max;
s64 total;
unsigned long nr;
};
enum bounce_type {
bounce_acquired_write,
bounce_acquired_read,
bounce_contended_write,
bounce_contended_read,
nr_bounce_types,
bounce_acquired = bounce_acquired_write,
bounce_contended = bounce_contended_write,
};
struct lock_class_stats {
unsigned long contention_point[4];
struct lock_time read_waittime;
struct lock_time write_waittime;
struct lock_time read_holdtime;
struct lock_time write_holdtime;
unsigned long bounces[nr_bounce_types];
};
struct lock_class_stats lock_stats(struct lock_class *class);
void clear_lock_stats(struct lock_class *class);
#endif
/*
* Map the lock object (the lock instance) to the lock-class object.
* This is embedded into specific lock instances:
*/
struct lockdep_map {
struct lock_class_key *key;
struct lock_class *class_cache;
const char *name;
#ifdef CONFIG_LOCK_STAT
int cpu;
#endif
};
/*
* Every lock has a list of other locks that were taken after it.
* We only grow the list, never remove from it:
*/
struct lock_list {
struct list_head entry;
struct lock_class *class;
struct stack_trace trace;
int distance;
};
/*
* We record lock dependency chains, so that we can cache them:
*/
struct lock_chain {
struct list_head entry;
u64 chain_key;
};
struct held_lock {
/*
* One-way hash of the dependency chain up to this point. We
* hash the hashes step by step as the dependency chain grows.
*
* We use it for dependency-caching and we skip detection
* passes and dependency-updates if there is a cache-hit, so
* it is absolutely critical for 100% coverage of the validator
* to have a unique key value for every unique dependency path
* that can occur in the system, to make a unique hash value
* as likely as possible - hence the 64-bit width.
*
* The task struct holds the current hash value (initialized
* with zero), here we store the previous hash value:
*/
u64 prev_chain_key;
struct lock_class *class;
unsigned long acquire_ip;
struct lockdep_map *instance;
#ifdef CONFIG_LOCK_STAT
u64 waittime_stamp;
u64 holdtime_stamp;
#endif
/*
* The lock-stack is unified in that the lock chains of interrupt
* contexts nest ontop of process context chains, but we 'separate'
* the hashes by starting with 0 if we cross into an interrupt
* context, and we also keep do not add cross-context lock
* dependencies - the lock usage graph walking covers that area
* anyway, and we'd just unnecessarily increase the number of
* dependencies otherwise. [Note: hardirq and softirq contexts
* are separated from each other too.]
*
* The following field is used to detect when we cross into an
* interrupt context:
*/
int irq_context;
int trylock;
int read;
int check;
int hardirqs_off;
};
/*
* Initialization, self-test and debugging-output methods:
*/
extern void lockdep_init(void);
extern void lockdep_info(void);
extern void lockdep_reset(void);
extern void lockdep_reset_lock(struct lockdep_map *lock);
extern void lockdep_free_key_range(void *start, unsigned long size);
extern void lockdep_off(void);
extern void lockdep_on(void);
/*
* These methods are used by specific locking variants (spinlocks,
* rwlocks, mutexes and rwsems) to pass init/acquire/release events
* to lockdep:
*/
extern void lockdep_init_map(struct lockdep_map *lock, const char *name,
struct lock_class_key *key, int subclass);
/*
* Reinitialize a lock key - for cases where there is special locking or
* special initialization of locks so that the validator gets the scope
* of dependencies wrong: they are either too broad (they need a class-split)
* or they are too narrow (they suffer from a false class-split):
*/
#define lockdep_set_class(lock, key) \
lockdep_init_map(&(lock)->dep_map, #key, key, 0)
#define lockdep_set_class_and_name(lock, key, name) \
lockdep_init_map(&(lock)->dep_map, name, key, 0)
#define lockdep_set_class_and_subclass(lock, key, sub) \
lockdep_init_map(&(lock)->dep_map, #key, key, sub)
#define lockdep_set_subclass(lock, sub) \
lockdep_init_map(&(lock)->dep_map, #lock, \
(lock)->dep_map.key, sub)
/*
* Acquire a lock.
*
* Values for "read":
*
* 0: exclusive (write) acquire
* 1: read-acquire (no recursion allowed)
* 2: read-acquire with same-instance recursion allowed
*
* Values for check:
*
* 0: disabled
* 1: simple checks (freeing, held-at-exit-time, etc.)
* 2: full validation
*/
extern void lock_acquire(struct lockdep_map *lock, unsigned int subclass,
int trylock, int read, int check, unsigned long ip);
extern void lock_release(struct lockdep_map *lock, int nested,
unsigned long ip);
# define INIT_LOCKDEP .lockdep_recursion = 0,
#define lockdep_depth(tsk) (debug_locks ? (tsk)->lockdep_depth : 0)
#else /* !LOCKDEP */
static inline void lockdep_off(void)
{
}
static inline void lockdep_on(void)
{
}
# define lock_acquire(l, s, t, r, c, i) do { } while (0)
# define lock_release(l, n, i) do { } while (0)
# define lockdep_init() do { } while (0)
# define lockdep_info() do { } while (0)
# define lockdep_init_map(lock, name, key, sub) do { (void)(key); } while (0)
# define lockdep_set_class(lock, key) do { (void)(key); } while (0)
# define lockdep_set_class_and_name(lock, key, name) \
do { (void)(key); } while (0)
#define lockdep_set_class_and_subclass(lock, key, sub) \
do { (void)(key); } while (0)
#define lockdep_set_subclass(lock, sub) do { } while (0)
# define INIT_LOCKDEP
# define lockdep_reset() do { debug_locks = 1; } while (0)
# define lockdep_free_key_range(start, size) do { } while (0)
/*
* The class key takes no space if lockdep is disabled:
*/
struct lock_class_key { };
#define lockdep_depth(tsk) (0)
#endif /* !LOCKDEP */
#ifdef CONFIG_LOCK_STAT
extern void lock_contended(struct lockdep_map *lock, unsigned long ip);
extern void lock_acquired(struct lockdep_map *lock);
#define LOCK_CONTENDED(_lock, try, lock) \
do { \
if (!try(_lock)) { \
lock_contended(&(_lock)->dep_map, _RET_IP_); \
lock(_lock); \
} \
lock_acquired(&(_lock)->dep_map); \
} while (0)
#else /* CONFIG_LOCK_STAT */
#define lock_contended(lockdep_map, ip) do {} while (0)
#define lock_acquired(lockdep_map) do {} while (0)
#define LOCK_CONTENDED(_lock, try, lock) \
lock(_lock)
#endif /* CONFIG_LOCK_STAT */
#if defined(CONFIG_TRACE_IRQFLAGS) && defined(CONFIG_GENERIC_HARDIRQS)
extern void early_init_irq_lock_class(void);
#else
static inline void early_init_irq_lock_class(void)
{
}
#endif
#ifdef CONFIG_TRACE_IRQFLAGS
extern void early_boot_irqs_off(void);
extern void early_boot_irqs_on(void);
extern void print_irqtrace_events(struct task_struct *curr);
#else
static inline void early_boot_irqs_off(void)
{
}
static inline void early_boot_irqs_on(void)
{
}
static inline void print_irqtrace_events(struct task_struct *curr)
{
}
#endif
/*
* For trivial one-depth nesting of a lock-class, the following
* global define can be used. (Subsystems with multiple levels
* of nesting should define their own lock-nesting subclasses.)
*/
#define SINGLE_DEPTH_NESTING 1
/*
* Map the dependency ops to NOP or to real lockdep ops, depending
* on the per lock-class debug mode:
*/
#ifdef CONFIG_DEBUG_LOCK_ALLOC
# ifdef CONFIG_PROVE_LOCKING
# define spin_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 2, i)
# else
# define spin_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 1, i)
# endif
# define spin_release(l, n, i) lock_release(l, n, i)
#else
# define spin_acquire(l, s, t, i) do { } while (0)
# define spin_release(l, n, i) do { } while (0)
#endif
#ifdef CONFIG_DEBUG_LOCK_ALLOC
# ifdef CONFIG_PROVE_LOCKING
# define rwlock_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 2, i)
# define rwlock_acquire_read(l, s, t, i) lock_acquire(l, s, t, 2, 2, i)
# else
# define rwlock_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 1, i)
# define rwlock_acquire_read(l, s, t, i) lock_acquire(l, s, t, 2, 1, i)
# endif
# define rwlock_release(l, n, i) lock_release(l, n, i)
#else
# define rwlock_acquire(l, s, t, i) do { } while (0)
# define rwlock_acquire_read(l, s, t, i) do { } while (0)
# define rwlock_release(l, n, i) do { } while (0)
#endif
#ifdef CONFIG_DEBUG_LOCK_ALLOC
# ifdef CONFIG_PROVE_LOCKING
# define mutex_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 2, i)
# else
# define mutex_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 1, i)
# endif
# define mutex_release(l, n, i) lock_release(l, n, i)
#else
# define mutex_acquire(l, s, t, i) do { } while (0)
# define mutex_release(l, n, i) do { } while (0)
#endif
#ifdef CONFIG_DEBUG_LOCK_ALLOC
# ifdef CONFIG_PROVE_LOCKING
# define rwsem_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 2, i)
# define rwsem_acquire_read(l, s, t, i) lock_acquire(l, s, t, 1, 2, i)
# else
# define rwsem_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 1, i)
# define rwsem_acquire_read(l, s, t, i) lock_acquire(l, s, t, 1, 1, i)
# endif
# define rwsem_release(l, n, i) lock_release(l, n, i)
#else
# define rwsem_acquire(l, s, t, i) do { } while (0)
# define rwsem_acquire_read(l, s, t, i) do { } while (0)
# define rwsem_release(l, n, i) do { } while (0)
#endif
#endif /* linux kernel < 2.6.18 */
#endif /* __LINUX_LOCKDEP_WRAPPER_H */
@@ -0,0 +1,59 @@
#ifndef __LINUX_MUTEX_WRAPPER_H
#define __LINUX_MUTEX_WRAPPER_H
#include <linux/version.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)
#include <asm/semaphore.h>
struct mutex {
struct semaphore sema;
};
#define mutex_init(mutex) init_MUTEX(&mutex->sema)
#define mutex_destroy(mutex) do { } while (0)
#define __MUTEX_INITIALIZER(name) \
__SEMAPHORE_INITIALIZER(name,1)
#define DEFINE_MUTEX(mutexname) \
struct mutex mutexname = { __MUTEX_INITIALIZER(mutexname.sema) }
/*
* See kernel/mutex.c for detailed documentation of these APIs.
* Also see Documentation/mutex-design.txt.
*/
static inline void mutex_lock(struct mutex *lock)
{
down(&lock->sema);
}
static inline int mutex_lock_interruptible(struct mutex *lock)
{
return down_interruptible(&lock->sema);
}
#define mutex_lock_nested(lock, subclass) mutex_lock(lock)
#define mutex_lock_interruptible_nested(lock, subclass) mutex_lock_interruptible(lock)
/*
* NOTE: mutex_trylock() follows the spin_trylock() convention,
* not the down_trylock() convention!
*/
static inline int mutex_trylock(struct mutex *lock)
{
return !down_trylock(&lock->sema);
}
static inline void mutex_unlock(struct mutex *lock)
{
up(&lock->sema);
}
#else
#include_next <linux/mutex.h>
#endif /* linux version < 2.6.16 */
#endif
@@ -0,0 +1,22 @@
#ifndef __LINUX_NETLINK_WRAPPER_H
#define __LINUX_NETLINK_WRAPPER_H 1
#include <linux/skbuff.h>
#include_next <linux/netlink.h>
#include <net/netlink.h>
#include <linux/version.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
#define NLMSG_DEFAULT_SIZE (NLMSG_GOODSIZE - NLMSG_HDRLEN)
#define nlmsg_new(s, f) nlmsg_new_proper((s), (f))
static inline struct sk_buff *nlmsg_new_proper(int size, gfp_t flags)
{
return alloc_skb(size, flags);
}
#endif /* linux kernel < 2.6.19 */
#endif
@@ -0,0 +1,17 @@
#ifndef __LINUX_RANDOM_WRAPPER_H
#define __LINUX_RANDOM_WRAPPER_H 1
#include_next <linux/random.h>
#include <linux/version.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
#ifdef __KERNEL__
u32 random32(void);
void srandom32(u32 seed);
#endif /* __KERNEL__ */
#endif /* linux kernel < 2.6.19 */
#endif
@@ -0,0 +1,63 @@
#ifndef __LINUX_SKBUFF_WRAPPER_H
#define __LINUX_SKBUFF_WRAPPER_H 1
#include_next <linux/skbuff.h>
#include <linux/version.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
/* Emulate Linux 2.6.17 and later behavior, in which kfree_skb silently ignores
* null pointer arguments. */
#define kfree_skb(skb) kfree_skb_maybe_null(skb)
static inline void kfree_skb_maybe_null(struct sk_buff *skb)
{
if (likely(skb != NULL))
(kfree_skb)(skb);
}
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
#define mac_header mac.raw
#define network_header nh.raw
/* Note that CHECKSUM_PARTIAL is not implemented, but this allows us to at
* least test against it: see update_csum() in forward.c. */
#define CHECKSUM_PARTIAL 3
#define CHECKSUM_COMPLETE CHECKSUM_HW
static inline unsigned char *skb_transport_header(const struct sk_buff *skb)
{
return skb->h.raw;
}
static inline void skb_set_transport_header(struct sk_buff *skb,
const int offset)
{
skb->h.raw = skb->data + offset;
}
static inline unsigned char *skb_network_header(const struct sk_buff *skb)
{
return skb->nh.raw;
}
static inline void skb_set_network_header(struct sk_buff *skb, const int offset)
{
skb->nh.raw = skb->data + offset;
}
static inline unsigned char *skb_mac_header(const struct sk_buff *skb)
{
return skb->mac.raw;
}
static inline void skb_set_mac_header(struct sk_buff *skb, const int offset)
{
skb->mac.raw = skb->data + offset;
}
#endif /* linux kernel < 2.6.22 */
#endif
@@ -0,0 +1,18 @@
#ifndef __LINUX_TCP_WRAPPER_H
#define __LINUX_TCP_WRAPPER_H 1
#include_next <linux/tcp.h>
#include <linux/version.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
#ifdef __KERNEL__
static inline struct tcphdr *tcp_hdr(const struct sk_buff *skb)
{
return (struct tcphdr *)skb_transport_header(skb);
}
#endif /* __KERNEL__ */
#endif /* linux kernel < 2.6.22 */
#endif
@@ -0,0 +1,90 @@
#ifndef __LINUX_TIMER_WRAPPER_H
#define __LINUX_TIMER_WRAPPER_H 1
#include_next <linux/timer.h>
#include <linux/version.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
extern unsigned long volatile jiffies;
/**
* __round_jiffies - function to round jiffies to a full second
* @j: the time in (absolute) jiffies that should be rounded
* @cpu: the processor number on which the timeout will happen
*
* __round_jiffies() rounds an absolute time in the future (in jiffies)
* up or down to (approximately) full seconds. This is useful for timers
* for which the exact time they fire does not matter too much, as long as
* they fire approximately every X seconds.
*
* By rounding these timers to whole seconds, all such timers will fire
* at the same time, rather than at various times spread out. The goal
* of this is to have the CPU wake up less, which saves power.
*
* The exact rounding is skewed for each processor to avoid all
* processors firing at the exact same time, which could lead
* to lock contention or spurious cache line bouncing.
*
* The return value is the rounded version of the @j parameter.
*/
static inline unsigned long __round_jiffies(unsigned long j, int cpu)
{
int rem;
unsigned long original = j;
/*
* We don't want all cpus firing their timers at once hitting the
* same lock or cachelines, so we skew each extra cpu with an extra
* 3 jiffies. This 3 jiffies came originally from the mm/ code which
* already did this.
* The skew is done by adding 3*cpunr, then round, then subtract this
* extra offset again.
*/
j += cpu * 3;
rem = j % HZ;
/*
* If the target jiffie is just after a whole second (which can happen
* due to delays of the timer irq, long irq off times etc etc) then
* we should round down to the whole second, not up. Use 1/4th second
* as cutoff for this rounding as an extreme upper bound for this.
*/
if (rem < HZ/4) /* round down */
j = j - rem;
else /* round up */
j = j - rem + HZ;
/* now that we have rounded, subtract the extra skew again */
j -= cpu * 3;
if (j <= jiffies) /* rounding ate our timeout entirely; */
return original;
return j;
}
/**
* round_jiffies - function to round jiffies to a full second
* @j: the time in (absolute) jiffies that should be rounded
*
* round_jiffies() rounds an absolute time in the future (in jiffies)
* up or down to (approximately) full seconds. This is useful for timers
* for which the exact time they fire does not matter too much, as long as
* they fire approximately every X seconds.
*
* By rounding these timers to whole seconds, all such timers will fire
* at the same time, rather than at various times spread out. The goal
* of this is to have the CPU wake up less, which saves power.
*
* The return value is the rounded version of the @j parameter.
*/
static inline unsigned long round_jiffies(unsigned long j)
{
return __round_jiffies(j, 0); // FIXME
}
#endif /* linux kernel < 2.6.20 */
#endif
Loaded 100 of 190 files, more files were not shown because too many files have changed in this diff. Show more