Initial import
This commit is contained in:
1 parent
219b913228
commit
468e00132f
190 files changed
+25756
No files matched your search
@@ -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.
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,2 @@
|
||||
AUTOMAKE_OPTIONS=foreign
|
||||
SUBDIRS = lib datapath secchan controller utilities man include third-party
|
||||
@@ -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/
|
||||
@@ -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")
|
||||
])
|
||||
@@ -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
|
||||
@@ -0,0 +1,3 @@
|
||||
/Makefile
|
||||
/Makefile.in
|
||||
/controller
|
||||
@@ -0,0 +1,6 @@
|
||||
include ../Make.vars
|
||||
|
||||
bin_PROGRAMS = controller
|
||||
|
||||
controller_SOURCES = controller.c
|
||||
controller_LDADD = ../lib/libopenflow.la
|
||||
@@ -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);
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
/Makefile
|
||||
/Makefile.in
|
||||
@@ -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
|
||||
Whitespace-only changes.
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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
File diff suppressed because it is too large.
Load diff
@@ -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 */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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 */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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 */
|
||||
@@ -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 == ¬ify_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, ¬ify_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
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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
|
||||
@@ -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/ \
|
||||
@@ -0,0 +1 @@
|
||||
KSRC=@KSRC24@
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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/
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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
Reference in new issue
Block a user