mirror of
https://github.com/openvswitch/ovs
synced 2025-08-22 09:58:01 +00:00
Import from old repository commit 61ef2b42a9c4ba8e1600f15bb0236765edc2ad45.
This commit is contained in:
commit
064af42167
43
.gitignore
vendored
Normal file
43
.gitignore
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
#*#
|
||||
*.a
|
||||
*.d
|
||||
*.ko
|
||||
*.la
|
||||
*.lo
|
||||
*.loT
|
||||
*.mod.c
|
||||
*.o
|
||||
*.o
|
||||
*.pyc
|
||||
*.so
|
||||
*~
|
||||
.#*
|
||||
.*.cmd
|
||||
.*.swp
|
||||
.deps
|
||||
.libs
|
||||
.tmp_versions
|
||||
/Makefile
|
||||
/Makefile.in
|
||||
/aclocal.m4
|
||||
/autom4te.cache
|
||||
/build-arch-stamp
|
||||
/build-aux
|
||||
/build-indep-stamp
|
||||
/compile
|
||||
/config.guess
|
||||
/config.h
|
||||
/config.h.in
|
||||
/config.log
|
||||
/config.status
|
||||
/config.sub
|
||||
/configure
|
||||
/configure-stamp
|
||||
/depcomp
|
||||
/install-sh
|
||||
/missing
|
||||
/stamp-h1
|
||||
Module.symvers
|
||||
TAGS
|
||||
cscope.*
|
||||
tags
|
29
COPYING
Normal file
29
COPYING
Normal file
@ -0,0 +1,29 @@
|
||||
This file is a summary of the licensing of files in this distribution.
|
||||
Some files may be marked specifically with a different license, in
|
||||
which case that license applies to the file in question.
|
||||
|
||||
Files under the debian, doc, include, lib, m4, secchan, tests,
|
||||
third-party, and utilities directories are licensed under the ISC
|
||||
license:
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
Files under the datapath directory are licensed under the GNU General
|
||||
Public License, version 2.
|
||||
|
||||
Files under the extras and vswitchd directories are licensed under the
|
||||
GNU General Public License, version 3 or later.
|
||||
|
||||
Files under the xenserver directory are licensed on a file-by-file
|
||||
basis. Some files are under an uncertain license that may not be
|
||||
DFSG-compliant or GPL-compatible. Refer to each file for details.
|
504
CodingStyle
Normal file
504
CodingStyle
Normal file
@ -0,0 +1,504 @@
|
||||
Open vSwitch Coding Style
|
||||
=========================
|
||||
|
||||
This file describes the coding style used in most C files in the Open
|
||||
vSwitch distribution. However, Linux kernel code datapath directory
|
||||
follows the Linux kernel's established coding conventions.
|
||||
|
||||
BASICS
|
||||
|
||||
Limit lines to 79 characters.
|
||||
|
||||
Use form feeds (control+L) to divide long source files into logical
|
||||
pieces. A form feed should appear as the only character on a line.
|
||||
|
||||
Do not use tabs for indentation.
|
||||
|
||||
Avoid trailing spaces on lines.
|
||||
|
||||
|
||||
NAMING
|
||||
|
||||
Use names that explain the purpose of a function or object.
|
||||
|
||||
Use underscores to separate words in an identifier: multi_word_name.
|
||||
|
||||
Use lowercase for most names. Use uppercase for macros, macro
|
||||
parameters, and members of enumerations.
|
||||
|
||||
Give arrays names that are plural.
|
||||
|
||||
Pick a unique name prefix (ending with an underscore) for each
|
||||
module, and apply that prefix to all of that module's externally
|
||||
visible names. Names of macro parameters, struct and union members,
|
||||
and parameters in function prototypes are not considered externally
|
||||
visible for this purpose.
|
||||
|
||||
Do not use names that begin with _. If you need a name for
|
||||
"internal use only", use __ as a suffix instead of a prefix.
|
||||
|
||||
Avoid negative names: "found" is a better name than "not_found".
|
||||
|
||||
In names, a "size" is a count of bytes, a "length" is a count of
|
||||
characters. A buffer has size, but a string has length. The length
|
||||
of a string does not include the null terminator, but the size of the
|
||||
buffer that contains the string does.
|
||||
|
||||
|
||||
COMMENTS
|
||||
|
||||
Comments should be written as full sentences that start with a
|
||||
capital letter and end with a period. Put two spaces between
|
||||
sentences.
|
||||
|
||||
Write block comments as shown below. You may put the /* and */ on
|
||||
the same line as comment text if you prefer.
|
||||
|
||||
/*
|
||||
* We redirect stderr to /dev/null because we often want to remove all
|
||||
* traffic control configuration on a port so its in a known state. If
|
||||
* this done when there is no such configuration, tc complains, so we just
|
||||
* always ignore it.
|
||||
*/
|
||||
|
||||
Each function and each variable declared outside a function, and
|
||||
each struct, union, and typedef declaration should be preceded by a
|
||||
comment. See FUNCTION DEFINITIONS below for function comment
|
||||
guidelines.
|
||||
|
||||
Each struct and union member should each have an inline comment that
|
||||
explains its meaning. structs and unions with many members should be
|
||||
additionally divided into logical groups of members by block comments,
|
||||
e.g.:
|
||||
|
||||
/* An event that will wake the following call to poll_block(). */
|
||||
struct poll_waiter {
|
||||
/* Set when the waiter is created. */
|
||||
struct list node; /* Element in global waiters list. */
|
||||
int fd; /* File descriptor. */
|
||||
short int events; /* Events to wait for (POLLIN, POLLOUT). */
|
||||
poll_fd_func *function; /* Callback function, if any, or null. */
|
||||
void *aux; /* Argument to callback function. */
|
||||
struct backtrace *backtrace; /* Event that created waiter, or null. */
|
||||
|
||||
/* Set only when poll_block() is called. */
|
||||
struct pollfd *pollfd; /* Pointer to element of the pollfds array
|
||||
(null if added from a callback). */
|
||||
};
|
||||
|
||||
Use XXX or FIXME comments to mark code that needs work.
|
||||
|
||||
Don't use // comments.
|
||||
|
||||
Don't comment out or #if 0 out code. Just remove it. The code that
|
||||
was there will still be in version control history.
|
||||
|
||||
|
||||
FUNCTIONS
|
||||
|
||||
Put the return type, function name, and the braces that surround the
|
||||
function's code on separate lines, all starting in column 0.
|
||||
|
||||
Before each function definition, write a comment that describes the
|
||||
function's purpose, including each parameter, the return value, and
|
||||
side effects. References to argument names should be given in
|
||||
single-quotes, e.g. 'arg'. The comment should not include the
|
||||
function name, nor need it follow any formal structure. The comment
|
||||
does not need to describe how a function does its work, unless this
|
||||
information is needed to use the function correctly (this is often
|
||||
better done with comments *inside* the function).
|
||||
|
||||
Simple static functions do not need a comment.
|
||||
|
||||
Within a file, non-static functions should come first, in the order
|
||||
that they are declared in the header file, followed by static
|
||||
functions. Static functions should be in one or more separate pages
|
||||
(separated by form feed characters) in logical groups. A commonly
|
||||
useful way to divide groups is by "level", with high-level functions
|
||||
first, followed by groups of progressively lower-level functions.
|
||||
This makes it easy for the program's reader to see the top-down
|
||||
structure by reading from top to bottom.
|
||||
|
||||
All function declarations and definitions should include a
|
||||
prototype. Empty parentheses, e.g. "int foo();", do not include a
|
||||
prototype (they state that the function's parameters are unknown);
|
||||
write "void" in parentheses instead, e.g. "int foo(void);".
|
||||
|
||||
Prototypes for static functions should either all go at the top of
|
||||
the file, separated into groups by blank lines, or they should appear
|
||||
at the top of each page of functions. Don't comment individual
|
||||
prototypes, but a comment on each group of prototypes is often
|
||||
appropriate.
|
||||
|
||||
In the absence of good reasons for another order, the following
|
||||
parameter order is preferred. One notable exception is that data
|
||||
parameters and their corresponding size parameters should be paired.
|
||||
|
||||
1. The primary object being manipulated, if any (equivalent to the
|
||||
"this" pointer in C++).
|
||||
2. Input-only parameters.
|
||||
3. Input/output parameters.
|
||||
4. Output-only parameters.
|
||||
5. Status parameter.
|
||||
|
||||
Example:
|
||||
|
||||
/* Stores the features supported by 'netdev' into each of '*current',
|
||||
* '*advertised', '*supported', and '*peer' that are non-null. Each value
|
||||
* is a bitmap of "enum ofp_port_features" bits, in host byte order.
|
||||
* Returns 0 if successful, otherwise a positive errno value. On failure,
|
||||
* all of the passed-in values are set to 0. */
|
||||
int
|
||||
netdev_get_features(struct netdev *netdev,
|
||||
uint32_t *current, uint32_t *advertised,
|
||||
uint32_t *supported, uint32_t *peer)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
|
||||
FUNCTION PROTOTYPES
|
||||
|
||||
Put the return type and function name on the same line in a function
|
||||
prototype:
|
||||
|
||||
static const struct option_class *get_option_class(int code);
|
||||
|
||||
|
||||
Omit parameter names from function prototypes when the names do not
|
||||
give useful information, e.g.:
|
||||
|
||||
int netdev_get_mtu(const struct netdev *);
|
||||
|
||||
|
||||
STATEMENTS
|
||||
|
||||
Indent each level of code with 4 spaces. Use BSD-style brace
|
||||
placement:
|
||||
|
||||
if (a()) {
|
||||
b();
|
||||
d();
|
||||
}
|
||||
|
||||
Put a space between "if", "while", "for", etc. and the expressions
|
||||
that follow them.
|
||||
|
||||
Enclose single statements in braces:
|
||||
|
||||
if (a > b) {
|
||||
return a;
|
||||
} else {
|
||||
return b;
|
||||
}
|
||||
|
||||
Use comments and blank lines to divide long functions into logical
|
||||
groups of statements.
|
||||
|
||||
Avoid assignments inside "if" and "while" conditions.
|
||||
|
||||
Do not put gratuitous parentheses around the expression in a return
|
||||
statement, that is, write "return 0;" and not "return(0);"
|
||||
|
||||
Write only one statement per line.
|
||||
|
||||
Indent "switch" statements like this:
|
||||
|
||||
switch (conn->state) {
|
||||
case S_RECV:
|
||||
error = run_connection_input(conn);
|
||||
break;
|
||||
|
||||
case S_PROCESS:
|
||||
error = 0;
|
||||
break;
|
||||
|
||||
case S_SEND:
|
||||
error = run_connection_output(conn);
|
||||
break;
|
||||
|
||||
default:
|
||||
NOT_REACHED();
|
||||
}
|
||||
|
||||
"switch" statements with very short, uniform cases may use an
|
||||
abbreviated style:
|
||||
|
||||
switch (code) {
|
||||
case 200: return "OK";
|
||||
case 201: return "Created";
|
||||
case 202: return "Accepted";
|
||||
case 204: return "No Content";
|
||||
default: return "Unknown";
|
||||
}
|
||||
|
||||
Use "for (;;)" to write an infinite loop.
|
||||
|
||||
In an if/else construct where one branch is the "normal" or "common"
|
||||
case and the other branch is the "uncommon" or "error" case, put the
|
||||
common case after the "if", not the "else". This is a form of
|
||||
documentation. It also places the most important code in sequential
|
||||
order without forcing the reader to visually skip past less important
|
||||
details. (Some compilers also assume that the "if" branch is the more
|
||||
common case, so this can be a real form of optimization as well.)
|
||||
|
||||
|
||||
MACROS
|
||||
|
||||
Don't define an object-like macro if an enum can be used instead.
|
||||
|
||||
Don't define a function-like macro if a "static inline" function
|
||||
can be used instead.
|
||||
|
||||
If a macro's definition contains multiple statements, enclose them
|
||||
with "do { ... } while (0)" to allow them to work properly in all
|
||||
syntactic circumstances.
|
||||
|
||||
Do use macros to eliminate the need to update different parts of a
|
||||
single file in parallel, e.g. a list of enums and an array that gives
|
||||
the name of each enum. For example:
|
||||
|
||||
/* Logging importance levels. */
|
||||
#define VLOG_LEVELS \
|
||||
VLOG_LEVEL(EMER, LOG_ALERT) \
|
||||
VLOG_LEVEL(ERR, LOG_ERR) \
|
||||
VLOG_LEVEL(WARN, LOG_WARNING) \
|
||||
VLOG_LEVEL(INFO, LOG_NOTICE) \
|
||||
VLOG_LEVEL(DBG, LOG_DEBUG)
|
||||
enum vlog_level {
|
||||
#define VLOG_LEVEL(NAME, SYSLOG_LEVEL) VLL_##NAME,
|
||||
VLOG_LEVELS
|
||||
#undef VLOG_LEVEL
|
||||
VLL_N_LEVELS
|
||||
};
|
||||
|
||||
/* Name for each logging level. */
|
||||
static const char *level_names[VLL_N_LEVELS] = {
|
||||
#define VLOG_LEVEL(NAME, SYSLOG_LEVEL) #NAME,
|
||||
VLOG_LEVELS
|
||||
#undef VLOG_LEVEL
|
||||
};
|
||||
|
||||
|
||||
SOURCE FILES
|
||||
|
||||
Each source file should state its license in a comment at the very
|
||||
top, followed by a comment explaining the purpose of the code that is
|
||||
in that file. The comment should explain how the code in the file
|
||||
relates to code in other files. The goal is to allow a programmer to
|
||||
quickly figure out where a given module fits into the larger system.
|
||||
|
||||
The first non-comment line in a .c source file should be:
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include directives should appear in the following order:
|
||||
|
||||
1. #include <config.h>
|
||||
|
||||
2. The module's own headers, if any. Including this before any
|
||||
other header (besides <config.h>) ensures that the module's
|
||||
header file is self-contained (see HEADER FILES) below.
|
||||
|
||||
3. Standard C library headers and other system headers, preferably
|
||||
in alphabetical order. (Occasionally one encounters a set of
|
||||
system headers that must be included in a particular order, in
|
||||
which case that order must take precedence.)
|
||||
|
||||
4. Open vSwitch headers, in alphabetical order. Use "", not <>,
|
||||
to specify Open vSwitch header names.
|
||||
|
||||
|
||||
HEADER FILES
|
||||
|
||||
Each header file should start with its license, as described under
|
||||
SOURCE FILES above, followed by a "header guard" to make the header
|
||||
file idempotent, like so:
|
||||
|
||||
#ifndef NETDEV_H
|
||||
#define NETDEV_H 1
|
||||
|
||||
...
|
||||
|
||||
#endif /* netdev.h */
|
||||
|
||||
Header files should be self-contained; that is, they should #include
|
||||
whatever additional headers are required, without requiring the client
|
||||
to #include them for it.
|
||||
|
||||
Don't define the members of a struct or union in a header file,
|
||||
unless client code is actually intended to access them directly or if
|
||||
the definition is otherwise actually needed (e.g. inline functions
|
||||
defined in the header need them).
|
||||
|
||||
Similarly, don't #include a header file just for the declaration of
|
||||
a struct or union tag (e.g. just for "struct <name>;"). Just declare
|
||||
the tag yourself. This reduces the number of header file
|
||||
dependencies.
|
||||
|
||||
|
||||
TYPES
|
||||
|
||||
Use typedefs sparingly. Code is clearer if the actual type is
|
||||
visible at the point of declaration. Do not, in general, declare a
|
||||
typedef for a struct, union, or enum. Do not declare a typedef for a
|
||||
pointer type, because this can be very confusing to the reader.
|
||||
|
||||
A function type is a good use for a typedef because it can clarify
|
||||
code. The type should be a function type, not a pointer-to-function
|
||||
type. That way, the typedef name can be used to declare function
|
||||
prototypes. (It cannot be used for function definitions, because that
|
||||
is explicitly prohibited by C89 and C99.)
|
||||
|
||||
You may assume that "char" is exactly 8 bits and that "int" and
|
||||
"long" are at least 32 bits.
|
||||
|
||||
Don't assume that "long" is big enough to hold a pointer. If you
|
||||
need to cast a pointer to an integer, use "intptr_t" or "uintptr_t"
|
||||
from <stdint.h>.
|
||||
|
||||
Use the int<N>_t and uint<N>_t types from <stdint.h> for exact-width
|
||||
integer types. Use the PRId<N>, PRIu<N>, and PRIx<N> macros from
|
||||
<inttypes.h> for formatting them with printf() and related functions.
|
||||
|
||||
Use %zu to format size_t with printf().
|
||||
|
||||
Use bit-fields sparingly. Do not use bit-fields for layout of
|
||||
network protocol fields or in other circumstances where the exact
|
||||
format is important.
|
||||
|
||||
Declare bit-fields to be type "unsigned int" or "signed int". Do
|
||||
*not* declare bit-fields of type "int": C89 allows these to be either
|
||||
signed or unsigned according to the compiler's whim. (A 1-bit
|
||||
bit-field of type "int" may have a range of -1...0!) Do not declare
|
||||
bit-fields of type _Bool or enum or any other type, because these are
|
||||
not portable.
|
||||
|
||||
Try to order structure members such that they pack well on a system
|
||||
with 2-byte "short", 4-byte "int", and 4- or 8-byte "long" and pointer
|
||||
types. Prefer clear organization over size optimization unless you
|
||||
are convinced there is a size or speed benefit.
|
||||
|
||||
Pointer declarators bind to the variable name, not the type name.
|
||||
Write "int *x", not "int* x" and definitely not "int * x".
|
||||
|
||||
|
||||
EXPRESSIONS
|
||||
|
||||
Put one space on each side of infix binary and ternary operators:
|
||||
|
||||
* / %
|
||||
+ -
|
||||
<< >>
|
||||
< <= > >=
|
||||
== !=
|
||||
&
|
||||
^
|
||||
|
|
||||
&&
|
||||
||
|
||||
?:
|
||||
= += -= *= /= %= &= ^= |= <<= >>=
|
||||
|
||||
Avoid comma operators.
|
||||
|
||||
Do not put any white space around postfix, prefix, or grouping
|
||||
operators:
|
||||
|
||||
() [] -> .
|
||||
! ~ ++ -- + - * &
|
||||
|
||||
Exception 1: Put a space after (but not before) the "sizeof" keyword.
|
||||
Exception 2: Put a space between the () used in a cast and the
|
||||
expression whose type is cast: (void *) 0.
|
||||
|
||||
Break long lines before binary operators and the ternary operators ?
|
||||
and :, rather than after them, e.g.
|
||||
|
||||
if (first_long_condition() || second_long_condition()
|
||||
|| third_long_condition())
|
||||
|
||||
and
|
||||
|
||||
return (out_port != VIGP_CONTROL_PATH
|
||||
? alpheus_output_port(dp, skb, out_port)
|
||||
: alpheus_output_control(dp, skb, fwd_save_skb(skb),
|
||||
VIGR_ACTION));
|
||||
|
||||
|
||||
Do not parenthesize the operands of && and || unless operator
|
||||
precedence makes it necessary, or unless the operands are themselves
|
||||
expressions that use && and ||. Thus:
|
||||
|
||||
if (!isdigit(s[0]) || !isdigit(s[1]) || !isdigit(s[2])) {
|
||||
printf("string %s does not start with 3-digit code\n", s);
|
||||
}
|
||||
|
||||
but
|
||||
|
||||
if (rule && (!best || rule->priority > best->priority)) {
|
||||
best = rule;
|
||||
}
|
||||
|
||||
Do parenthesize a subexpression that must be split across more than
|
||||
one line, e.g.:
|
||||
|
||||
*idxp = ((l1_idx << PORT_ARRAY_L1_SHIFT)
|
||||
| (l2_idx << PORT_ARRAY_L2_SHIFT)
|
||||
| (l3_idx << PORT_ARRAY_L3_SHIFT));
|
||||
|
||||
Try to avoid casts. Don't cast the return value of malloc().
|
||||
|
||||
The "sizeof" operator is unique among C operators in that it accepts
|
||||
two very different kinds of operands: an expression or a type. In
|
||||
general, prefer to specify an expression, e.g. "int *x =
|
||||
xmalloc(sizeof *x);". When the operand of sizeof is an expression,
|
||||
there is no need to parenthesize that operand, and please don't.
|
||||
|
||||
Use the ARRAY_SIZE macro from lib/util.h to calculate the number of
|
||||
elements in an array.
|
||||
|
||||
When using a relational operator like "<" or "==", put an expression
|
||||
or variable argument on the left and a constant argument on the
|
||||
right, e.g. "x == 0", *not* "0 == x".
|
||||
|
||||
|
||||
BLANK LINES
|
||||
|
||||
Put one blank line between top-level definitions of functions and
|
||||
global variables.
|
||||
|
||||
|
||||
C DIALECT
|
||||
|
||||
Try to avoid using GCC extensions where possible.
|
||||
|
||||
Some C99 extensions are OK:
|
||||
|
||||
* Flexible array members (e.g. struct { int foo[]; }).
|
||||
|
||||
* "static inline" functions (but no other forms of "inline", for
|
||||
which GCC and C99 have differing interpretations).
|
||||
|
||||
* "long long"
|
||||
|
||||
* <stdint.h> and <inttypes.h>.
|
||||
|
||||
* bool and <stdbool.h>, but don't assume that bool or _Bool can
|
||||
only take on the values 0 or 1, because this behavior can't be
|
||||
simulated on C89 compilers.
|
||||
|
||||
Don't use other C99 extensions, and especially:
|
||||
|
||||
* Don't use // comments.
|
||||
|
||||
* Don't use designated initializers (e.g. don't write "struct foo
|
||||
foo = {.a = 1};" or "int a[] = {[2] = 5};").
|
||||
|
||||
* Don't mix declarations and code within a block.
|
||||
|
||||
* Don't use declarations in iteration statements (e.g. don't write
|
||||
"for (int i = 0; i < 10; i++)").
|
||||
|
||||
* Don't put a trailing comma in an enum declaration (e.g. don't
|
||||
write "enum { x = 1, };").
|
514
INSTALL
Normal file
514
INSTALL
Normal file
@ -0,0 +1,514 @@
|
||||
Open vSwitch Installation Instructions
|
||||
|
||||
This document describes how to build, install, and execute
|
||||
Open vSwitch.
|
||||
|
||||
Open vSwitch implements an Ethernet switch with MAC learning that may
|
||||
be configured with any of the following features:
|
||||
|
||||
* NIC bonding with automatic fail-over and source MAC-based TX
|
||||
load balancing ("SLB").
|
||||
|
||||
* 802.1Q VLAN support.
|
||||
|
||||
* Port mirroring, with optional VLAN tagging.
|
||||
|
||||
* NetFlow v5 flow logging.
|
||||
|
||||
* Connectivity to an external OpenFlow controller, such as
|
||||
NOX.
|
||||
|
||||
The current version of this distribution requires a kernel module to
|
||||
be built and loaded. An (optional) entirely userspace switch is on
|
||||
the roadmap for future versions.
|
||||
|
||||
The distribution also contains a number of related utilities.
|
||||
|
||||
Build Methods
|
||||
=============
|
||||
|
||||
There are two principal ways to build and install this distribution:
|
||||
|
||||
- Using "configure" and "make" in the ordinary way. See
|
||||
Building Conventionally below for detailed instructions.
|
||||
|
||||
- As a set of Debian packages. Refer to Building Debian
|
||||
Packages, below, for instructions.
|
||||
|
||||
Base Prerequisites
|
||||
------------------
|
||||
|
||||
Regardless of how it is built, Open vSwitch has a common set of
|
||||
prerequisites. To compile the userspace programs in the OpenFlow
|
||||
reference distribution, you will need the following software:
|
||||
|
||||
- A make program, e.g. GNU make
|
||||
(http://www.gnu.org/software/make/). BSD make should also work.
|
||||
|
||||
- The GNU C compiler (http://gcc.gnu.org/). We generally test
|
||||
with version 4.2 or 4.3.
|
||||
|
||||
- libssl, from OpenSSL (http://www.openssl.org/), is optional but
|
||||
recommended if you plan to connect the Open vSwitch to an
|
||||
OpenFlow controller. libssl is required to establish
|
||||
confidentiality and authenticity in the connections from an
|
||||
Open vSwitch to an OpenFlow controller. To enable, configure
|
||||
with --enable-ssl=yes.
|
||||
|
||||
To compile the kernel module, you must also install the following:
|
||||
|
||||
- A supported Linux kernel version. Please refer to README for a
|
||||
list of supported versions.
|
||||
|
||||
The OpenFlow datapath requires bridging support (CONFIG_BRIDGE)
|
||||
to be built as a kernel module. (This is common in kernels
|
||||
provided by Linux distributions.) The bridge module must not be
|
||||
loaded or in use. If the bridge module is running (check with
|
||||
"lsmod | grep bridge"), you must remove it ("rmmod bridge")
|
||||
before starting the datapath.
|
||||
|
||||
- To build a kernel module, you need the same version of GCC that
|
||||
was used to build that kernel (usually version 4.0 or later).
|
||||
|
||||
- A kernel build directory corresponding to the Linux kernel image
|
||||
the module is to run on. Under Debian and Ubuntu, for example,
|
||||
each linux-image package containing a kernel binary has a
|
||||
corresponding linux-headers package with the required build
|
||||
infrastructure.
|
||||
|
||||
If you are working from a Git tree or snapshot (instead of from a
|
||||
distribution tarball), or if you modify the Open vSwitch build system,
|
||||
you will also need the following software:
|
||||
|
||||
- Autoconf version 2.60 or later (http://www.gnu.org/software/autoconf).
|
||||
|
||||
- Automake version 1.10 or later (http://www.gnu.org/software/automake).
|
||||
|
||||
- pkg-config (http://pkg-config.freedesktop.org/wiki/). We test
|
||||
with version 0.22.
|
||||
|
||||
Debian Prerequisites
|
||||
--------------------
|
||||
|
||||
To build Debian packages from the Open vSwitch distribution, you will
|
||||
need to install a number of Debian packages in addition to the base
|
||||
prerequisites listed above. These additional prerequisites may be
|
||||
found listed as "Build-Depends" in debian/control in the source tree.
|
||||
To check that they are installed, first install the dpkg-dev package,
|
||||
then run dpkg-checkbuilddeps from the top level of the OpenFlow source
|
||||
tree.
|
||||
|
||||
To build Debian packages without being root, also install the
|
||||
"fakeroot" package.
|
||||
|
||||
Building Conventionally
|
||||
=======================
|
||||
|
||||
This section explains how to build and install the Open vSwitch
|
||||
distribution in the ordinary way using "configure" and "make".
|
||||
|
||||
0. Check that you have installed all the prerequisites listed above in
|
||||
the Base Prerequisites section.
|
||||
|
||||
1. In the top source directory, configure the package by running the
|
||||
configure script. You can usually invoke configure without any
|
||||
arguments:
|
||||
|
||||
% ./configure
|
||||
|
||||
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
|
||||
|
||||
To build the Linux kernel module, so that you can run the
|
||||
kernel-based switch, pass the location of the kernel build
|
||||
directory on --with-l26. For example, to build for a running
|
||||
instance of Linux 2.6:
|
||||
|
||||
% ./configure --with-l26=/lib/modules/`uname -r`/build
|
||||
|
||||
If you wish to build the kernel module for an architecture other
|
||||
than the architecture of the machine used for the build, you may
|
||||
specify the kernel architecture string using the KARCH variable
|
||||
when invoking the configure script. For example, to build for MIPS
|
||||
with Linux 2.6:
|
||||
|
||||
% ./configure --with-l26=/path/to/linux-2.6 KARCH=mips
|
||||
|
||||
The configure script accepts a number of other options and honors
|
||||
additional environment variables. For a full list, invoke
|
||||
configure with the --help option.
|
||||
|
||||
2. Run make in the top source directory:
|
||||
|
||||
% make
|
||||
|
||||
The following main binaries will be built:
|
||||
|
||||
- Virtual switch daemon: vswitchd/ovs-vswitchd
|
||||
|
||||
- Bridge compatibility daemon: vswitchd/ovs-brcompatd
|
||||
|
||||
- Datapath administration utility: utilities/ovs-dpctl.
|
||||
|
||||
Some less important binaries will be built also:
|
||||
|
||||
- Runtime configuration utility: utilities/ovs-appctl.
|
||||
|
||||
- Simple OpenFlow controller: utilities/ovs-controller.
|
||||
|
||||
- Secure channel executable: secchan/secchan.
|
||||
|
||||
- Miscellaneous utilities: utilities/ovs-discover,
|
||||
utilities/ovs-kill.
|
||||
|
||||
- ANSI terminal support for EZIO 16x2 LCD panel:
|
||||
extras/ezio/ezio-term (only if the proper libraries are
|
||||
installed).
|
||||
|
||||
- Switch monitoring UI for small text displays:
|
||||
extras/ezio/ovs-switchui (only if the proper libraries are
|
||||
installed).
|
||||
|
||||
- Tests: various binaries in tests/.
|
||||
|
||||
If you passed --with-l26 to configure, "make" will also build the
|
||||
following kernel modules:
|
||||
|
||||
- datapath/linux-2.6/brcompat_mod.ko
|
||||
|
||||
- datapath/linux-2.6/openflow_mod.ko
|
||||
|
||||
3. Run "make install" to install the executables and manpages into the
|
||||
running system, by default under /usr/local.
|
||||
|
||||
4. If you built kernel modules, you may load them with "insmod", e.g.:
|
||||
|
||||
% insmod datapath/linux-2.6/openflow_mod.ko
|
||||
|
||||
The insmod program must be run as root. You may need to specify a
|
||||
full path to insmod, e.g. /sbin/insmod. To verify that the modules
|
||||
have been loaded, run "/sbin/lsmod" and check that openflow_mod is
|
||||
listed.
|
||||
|
||||
5. Test the virtuaal switch, as described under Testing the Virtual
|
||||
Switch below.
|
||||
|
||||
Building Debian Packages
|
||||
========================
|
||||
|
||||
Follow these instructions to build Debian packages for OpenFlow.
|
||||
|
||||
0. Check that you have installed all the prerequisites listed above in
|
||||
the Base Prerequisites and Debian Prerequisites sections above.
|
||||
|
||||
1. In the top source directory, run the following command, as root:
|
||||
|
||||
% dpkg-buildpackage
|
||||
|
||||
Alternatively, if you installed the "fakeroot" package, you may run
|
||||
dpkg-buildpackage as an ordinary user with the following syntax:
|
||||
|
||||
% dpkg-buildpackage -rfakeroot
|
||||
|
||||
The following packages will be built in the directory above the
|
||||
source tree:
|
||||
|
||||
- openflow-controller: The OpenFlow controller. Depends on
|
||||
openflow-pki (see below).
|
||||
|
||||
- openflow-switch: Install this package on a machine that acts
|
||||
as an OpenFlow kernel switch.
|
||||
|
||||
- openflow-datapath-source: Source code for OpenFlow's Linux
|
||||
kernel module.
|
||||
|
||||
- openflow-pki: Public-key infrastructure for OpenFlow. Install
|
||||
this package on a machine that acts as an OpenFlow PKI server
|
||||
(see "Establishing a Public Key Infrastructure" below).
|
||||
|
||||
- openflow-common: Files and utilities required by more than one
|
||||
of the above packages.
|
||||
|
||||
2. To set up an OpenFlow controller, install the openflow-controller
|
||||
package and its dependencies. You may configure it by editing
|
||||
/etc/default/openflow-controller, e.g. to enable non-SSL
|
||||
connections, which are disabled by default. If you change the
|
||||
default settings, you will need to restart the controller by
|
||||
running:
|
||||
|
||||
% /etc/init.d/openflow-controller restart
|
||||
|
||||
3. To set up an OpenFlow switch, install the openflow-switch package
|
||||
and its dependencies. If it is to be a kernel-based switch, also
|
||||
install openflow-datapath-source, then follow the instructions in
|
||||
/usr/share/doc/openflow-datapath-source/README.Debian to build and
|
||||
install the kernel module.
|
||||
|
||||
You may configure the switch one of the following ways:
|
||||
|
||||
- Completely by hand, as described under the Testing section
|
||||
below.
|
||||
|
||||
For the userspace datapath-based switch, this is the only
|
||||
supported form of configuration.
|
||||
|
||||
- By editing /etc/default/openflow-switch. You must at least
|
||||
configure some network devices, by uncommenting NETDEVS and
|
||||
adding the appropriate devices to the list, e.g. NETDEVS="eth0
|
||||
eth1".
|
||||
|
||||
After you edit this file, you will need to start the switch by
|
||||
running:
|
||||
|
||||
% /etc/init.d/openflow-switch restart
|
||||
|
||||
This form of configuration is not supported for the userspace
|
||||
datapath-based switch.
|
||||
|
||||
- By running the ovs-switch-setup program. This interactive
|
||||
program will walk you through all the steps of configuring an
|
||||
OpenFlow switch, including configuration of SSL certificates.
|
||||
Run it without arguments, as root:
|
||||
|
||||
% ovs-switch-setup
|
||||
|
||||
This form of configuration is not supported for the userspace
|
||||
datapath-based switch.
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
This section explains how to install Open vSwitch in a network with one
|
||||
controller and one or more switches, each of which runs on a separate
|
||||
machine. Before you begin, you must decide on one of two ways for
|
||||
each switch to reach the controller over the network:
|
||||
|
||||
- Use a "control network" that is completely separate from the
|
||||
"data network" to be controlled ("out-of-band control"). The
|
||||
location of the controller must be configured manually in this
|
||||
case.
|
||||
|
||||
- Use the same network for control and for data ("in-band
|
||||
control"). When in-band control is used, the location of the
|
||||
controller may be configured manually or discovered
|
||||
automatically. We will assume manual configuration here;
|
||||
please refer to secchan(8) for instructions on setting up
|
||||
controller discovery.
|
||||
|
||||
Controller Setup
|
||||
----------------
|
||||
|
||||
On the machine that is to be the OpenFlow controller, start the
|
||||
"ovs-controller" program listening for connections from switches on
|
||||
TCP port 6633 (the default), as shown below.
|
||||
|
||||
# ovs-controller -v ptcp:
|
||||
|
||||
(See ovs-controller(8) for more details)
|
||||
|
||||
Make sure the machine hosting the controller is reachable by the
|
||||
switch.
|
||||
|
||||
Testing the Virtual Switch
|
||||
--------------------------
|
||||
|
||||
The Open vSwitch kernel module must be loaded, as described under
|
||||
"Building Conventionally", before it may be used.
|
||||
|
||||
0. The commands below must run as root, so log in as root, or use a
|
||||
program such as "su" to become root temporarily.
|
||||
|
||||
1. Create a datapath instance. The command below creates a datapath
|
||||
identified as dp0 (see ovs-dpctl(8) for more detailed usage
|
||||
information).
|
||||
|
||||
# ovs-dpctl add-dp dp0
|
||||
|
||||
(dp0 is the first datapath within a host. openvswitch_mod supports
|
||||
multiple datapaths within the same host, which would be identified
|
||||
as dp1, dp2, etc.)
|
||||
|
||||
Creating datapath dp0 creates a new network device, also named dp0.
|
||||
This network device, called the datapath's "local port", will be
|
||||
bridged to the physical switch ports by the secchan, for use in
|
||||
in-band control.
|
||||
|
||||
2. Use ovs-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:
|
||||
|
||||
# ovs-dpctl add-if dp0 eth1
|
||||
# ovs-dpctl add-if dp0 eth2
|
||||
|
||||
You can verify that the interfaces were successfully added by asking
|
||||
ovs-dpctl to print the current status of datapath dp0:
|
||||
|
||||
# ovs-dpctl show dp0
|
||||
|
||||
3. Arrange so that the switch can reach the controller over the
|
||||
network.
|
||||
|
||||
- If you are using out-of-band control, at this point make sure
|
||||
that the switch machine can reach the controller over the
|
||||
network.
|
||||
|
||||
- If you are using in-band control, then at this point you must
|
||||
configure the dp0 network device created in step 1. This
|
||||
device is not yet bridged to any physical network (because
|
||||
secchan does that, and it is not yet running), so the next
|
||||
step depends on whether connectivity is required to configure
|
||||
the device's IP address:
|
||||
|
||||
* If the switch has a static IP address, you may configure
|
||||
its IP address now, e.g.:
|
||||
|
||||
# ifconfig dp0 192.168.1.1
|
||||
|
||||
* If the switch does not have a static IP address, e.g. its
|
||||
IP address is obtained dynamically via DHCP, then proceed
|
||||
to step 4. The DHCP client will not be able to contact
|
||||
the DHCP server until the secure channel has started up.
|
||||
|
||||
- If you are using in-band control with controller discovery, no
|
||||
configuration is required at this point. You may proceed to
|
||||
step 4.
|
||||
|
||||
4. Run secchan to start the secure channel connecting the datapath to
|
||||
a remote controller. If the controller is running on host
|
||||
192.168.1.2 port 6633 (the default port), the secchan invocation
|
||||
would look like this:
|
||||
|
||||
# secchan dp0 tcp:192.168.1.2
|
||||
|
||||
- If you are using in-band control with controller discovery, omit
|
||||
the second argument to the secchan command.
|
||||
|
||||
- If you are using out-of-band control, add --out-of-band to the
|
||||
command line.
|
||||
|
||||
5. If you are using in-band control with manual configuration, and the
|
||||
switch obtains its IP address dynamically, then you may now obtain
|
||||
the switch's IP address, e.g. by invoking a DHCP client. The
|
||||
secure channel will only be able to connect to the controller after
|
||||
an IP address has been obtained.
|
||||
|
||||
6. The secure channel should connect to the controller within a few
|
||||
seconds. It may take a little longer if controller discovery is in
|
||||
use, because the switch must then also obtain its own IP address
|
||||
and the controller's location via DHCP.
|
||||
|
||||
Configuration
|
||||
=============
|
||||
|
||||
Secure operation over SSL
|
||||
-------------------------
|
||||
|
||||
The instructions above set up Open vSwitch for operation over a
|
||||
plaintext TCP connection. Production use of Open vSwitch should use
|
||||
SSL[*] to ensure confidentiality and authenticity of traffic among
|
||||
switches and controllers. The source must be configured with
|
||||
--enable-ssl=yes to build with SSL support.
|
||||
|
||||
To use SSL with Open vSwitch, you must set up a public-key infrastructure
|
||||
(PKI) including a pair of certificate authorities (CAs), one for
|
||||
controllers and one for switches. If you have an established PKI,
|
||||
Open vSwitch can use it directly. Otherwise, refer to "Establishing a
|
||||
Public Key Infrastructure" below.
|
||||
|
||||
To configure the controller to listen for SSL connections on port 6633
|
||||
(the default), invoke it as follows:
|
||||
|
||||
# ovs-controller -v pssl: --private-key=PRIVKEY --certificate=CERT \
|
||||
--ca-cert=CACERT
|
||||
|
||||
where PRIVKEY is a file containing the controller's private key, CERT
|
||||
is a file containing the controller CA's certificate for the
|
||||
controller's public key, and CACERT is a file containing the root
|
||||
certificate for the switch CA. If, for example, your PKI was created
|
||||
with the instructions below, then the invocation would look like:
|
||||
|
||||
# ovs-controller -v pssl: --private-key=ctl-privkey.pem \
|
||||
--certificate=ctl-cert.pem --ca-cert=pki/switchca/cacert.pem
|
||||
|
||||
To configure a switch to connect to a controller running on port 6633
|
||||
(the default) on host 192.168.1.2 over SSL, invoke secchan as follows:
|
||||
|
||||
# secchan -v DATAPATH ssl:192.168.1.2 --private-key=PRIVKEY \
|
||||
--certificate=CERT --ca-cert=CACERT
|
||||
|
||||
where DATAPATH is the datapath to connect to (e.g. dp0 or
|
||||
unix:/var/run/dp0.sock), PRIVKEY is a file containing the switch's
|
||||
private key, CERT is a file containing the switch CA's certificate for
|
||||
the switch's public key, and CACERT is a file containing the root
|
||||
certificate for the controller CA. If, for example, your PKI was
|
||||
created with the instructions below, then the invocation would look
|
||||
like:
|
||||
|
||||
# secchan -v DATAPATH ssl:192.168.1.2 --private-key=sc-privkey.pem \
|
||||
--certificate=sc-cert.pem --ca-cert=pki/controllerca/cacert.pem
|
||||
|
||||
[*] To be specific, Open vSwitch uses TLS version 1.0 or later (TLSv1), as
|
||||
specified by RFC 2246, which is very similar to SSL version 3.0.
|
||||
TLSv1 was released in January 1999, so all current software and
|
||||
hardware should implement it.
|
||||
|
||||
Establishing a Public Key Infrastructure
|
||||
----------------------------------------
|
||||
|
||||
If you do not have a PKI, the ovs-pki script included with Open vSwitch
|
||||
can help. To create an initial PKI structure, invoke it as:
|
||||
% ovs-pki init
|
||||
which will create and populate a new PKI directory. The default
|
||||
location for the PKI directory depends on how the Open vSwitch tree was
|
||||
configured (to see the configured default, look for the --dir option
|
||||
description in the output of "ovs-pki --help").
|
||||
|
||||
The pki directory contains two important subdirectories. The
|
||||
controllerca subdirectory contains controller certificate authority
|
||||
related files, including the following:
|
||||
|
||||
- cacert.pem: Root certificate for the controller certificate
|
||||
authority. This file must be provided to secchan with the
|
||||
--ca-cert option to enable it to authenticate valid controllers.
|
||||
|
||||
- private/cakey.pem: Private signing key for the controller
|
||||
certificate authority. This file must be kept secret. There is
|
||||
no need for switches or controllers to have a copy of it.
|
||||
|
||||
The switchca subdirectory contains switch certificate authority
|
||||
related files, analogous to those in the controllerca subdirectory:
|
||||
|
||||
- cacert.pem: Root certificate for the switch certificate
|
||||
authority. This file must be provided to the controller program
|
||||
with the --ca-cert option to enable it to authenticate valid
|
||||
switches.
|
||||
|
||||
- private/cakey.pem: Private signing key for the switch
|
||||
certificate authority. This file must be kept secret. There is
|
||||
no need for switches or controllers to have a copy of it.
|
||||
|
||||
After you create the initial structure, you can create keys and
|
||||
certificates for switches and controllers with ovs-pki. To create a
|
||||
controller private key and certificate in files named ctl-privkey.pem
|
||||
and ctl-cert.pem, for example, you could run:
|
||||
% ovs-pki req+sign ctl controller
|
||||
ctl-privkey.pem and ctl-cert.pem would need to be copied to the
|
||||
controller for its use at runtime (they could then be deleted from
|
||||
their original locations). The --private-key and --certificate
|
||||
options of ovs-controller, respectively, would point to these files.
|
||||
|
||||
Analogously, to create a switch private key and certificate in files
|
||||
named sc-privkey.pem and sc-cert.pem, for example, you could run:
|
||||
% ovs-pki req+sign sc switch
|
||||
sc-privkey.pem and sc-cert.pem would need to be copied to the switch
|
||||
for its use at runtime (they could then be deleted from their original
|
||||
locations). The --private-key and --certificate options,
|
||||
respectively, of secchan would point to these files.
|
||||
|
||||
Bug Reporting
|
||||
-------------
|
||||
|
||||
Please report problems to ovs-bugs@openvswitch.org.
|
74
Makefile.am
Normal file
74
Makefile.am
Normal file
@ -0,0 +1,74 @@
|
||||
AUTOMAKE_OPTIONS = foreign subdir-objects
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
SUBDIRS = datapath
|
||||
|
||||
if ENABLE_USERSPACE
|
||||
if HAVE_DPKG_BUILDPACKAGE
|
||||
distcheck-hook:
|
||||
cd $(srcdir) && dpkg-buildpackage -rfakeroot -us -uc
|
||||
cd $(srcdir) && fakeroot ./debian/rules clean
|
||||
else
|
||||
distcheck-hook:
|
||||
endif
|
||||
|
||||
AM_CPPFLAGS = $(SSL_CFLAGS)
|
||||
AM_CPPFLAGS += $(NCURSES_CFLAGS)
|
||||
AM_CPPFLAGS += $(PCRE_CFLAGS)
|
||||
AM_CPPFLAGS += -I $(top_srcdir)/include
|
||||
AM_CPPFLAGS += -I $(top_srcdir)/lib
|
||||
|
||||
AM_CFLAGS = -Wstrict-prototypes
|
||||
|
||||
if NDEBUG
|
||||
AM_CPPFLAGS += -DNDEBUG
|
||||
AM_CFLAGS += -fomit-frame-pointer
|
||||
else
|
||||
AM_LDFLAGS = -export-dynamic
|
||||
endif
|
||||
|
||||
CLEANFILES =
|
||||
DISTCLEANFILES =
|
||||
EXTRA_DIST =
|
||||
TESTS =
|
||||
TESTS_ENVIRONMENT =
|
||||
bin_PROGRAMS =
|
||||
sbin_PROGRAMS =
|
||||
bin_SCRIPTS =
|
||||
dist_commands_DATA =
|
||||
dist_man_MANS =
|
||||
dist_pkgdata_SCRIPTS =
|
||||
dist_sbin_SCRIPTS =
|
||||
man_MANS =
|
||||
noinst_HEADERS =
|
||||
noinst_LIBRARIES =
|
||||
noinst_PROGRAMS =
|
||||
noinst_SCRIPTS =
|
||||
|
||||
EXTRA_DIST += soexpand.pl
|
||||
|
||||
ro_c = echo '/* -*- mode: c; buffer-read-only: t -*- */'
|
||||
|
||||
SUFFIXES = .in
|
||||
.in:
|
||||
$(PERL) $(srcdir)/soexpand.pl -I$(srcdir) < $< | \
|
||||
sed -e 's,[@]LOGDIR[@],$(LOGDIR),g' \
|
||||
-e 's,[@]PKIDIR[@],$(PKIDIR),g' \
|
||||
-e 's,[@]RUNDIR[@],$(RUNDIR),g' \
|
||||
-e 's,[@]pkgdatadir[@],$(pkgdatadir),g' \
|
||||
-e 's,[@]PERL[@],$(PERL),g' > $@
|
||||
|
||||
include lib/automake.mk
|
||||
include secchan/automake.mk
|
||||
include utilities/automake.mk
|
||||
include tests/automake.mk
|
||||
include include/automake.mk
|
||||
include third-party/automake.mk
|
||||
include debian/automake.mk
|
||||
include vswitchd/automake.mk
|
||||
include xenserver/automake.mk
|
||||
if HAVE_CURSES
|
||||
if HAVE_PCRE
|
||||
include extras/ezio/automake.mk
|
||||
endif
|
||||
endif
|
||||
endif # ENABLE_USERSPACE
|
74
README
Normal file
74
README
Normal file
@ -0,0 +1,74 @@
|
||||
Open vSwitch <http://openvswitch.org>
|
||||
|
||||
What is Open vSwitch?
|
||||
---------------------
|
||||
|
||||
Open vSwitch is an Ethernet switch for virtual servers with the
|
||||
following features:
|
||||
|
||||
* NIC bonding with automatic fail-over and source MAC-based TX
|
||||
load balancing ("SLB").
|
||||
|
||||
* 802.1Q VLAN support.
|
||||
|
||||
* Port mirroring, with optional VLAN tagging.
|
||||
|
||||
* NetFlow v5 flow logging.
|
||||
|
||||
* Connectivity to an external OpenFlow controller, such as
|
||||
NOX.
|
||||
|
||||
What's here?
|
||||
------------
|
||||
|
||||
The most important components of this distribution are:
|
||||
|
||||
- A Linux kernel module for flow-based switching, in the
|
||||
datapath directory.
|
||||
|
||||
- ovs-vswitchd, a daemon that implements the virtual switch.
|
||||
|
||||
- ovs-dpctl, a tool for configuring the kernel module and
|
||||
controlling OpenFlow switches.
|
||||
|
||||
This distribution includes some additional software as well:
|
||||
|
||||
- secchan, a program that implements a simple OpenFlow switch
|
||||
(without the special features provided by ovs-vswitchd) using
|
||||
the same kernel module as ovs-vswitchd.
|
||||
|
||||
- ovs-controller, a simple OpenFlow switch
|
||||
|
||||
- ovs-ofctl, a utility for querying and controlling OpenFlow
|
||||
switches and controllers.
|
||||
|
||||
- vlog-appctl, a utility that can control Open vSwitch daemons,
|
||||
adjusting their logging levels among other uses.
|
||||
|
||||
- ovs-pki, a utility for creating and managing the public-key
|
||||
infrastructure for OpenFlow switches.
|
||||
|
||||
- A patch to tcpdump that enables it to parse OpenFlow
|
||||
messages.
|
||||
|
||||
For installation instructions, read INSTALL. Each userspace program
|
||||
is also accompanied by a manpage.
|
||||
|
||||
Platform support
|
||||
----------------
|
||||
|
||||
Our primary test environment is Debian GNU/Linux. Ports to other
|
||||
platforms are welcome. Please contact us with portability-related bug
|
||||
reports or patches.
|
||||
|
||||
The testing of the kernel module has focused on version 2.6.18 from
|
||||
Xen and version 2.6.26 from kernel.org. Linux 2.6 releases from
|
||||
2.6.15 onward should also work.
|
||||
|
||||
GCC is the expected compiler.
|
||||
|
||||
Contact
|
||||
-------
|
||||
|
||||
ovs-bugs@openvswitch.org
|
||||
http://openvswitch.org/
|
195
acinclude.m4
Normal file
195
acinclude.m4
Normal file
@ -0,0 +1,195 @@
|
||||
# -*- autoconf -*-
|
||||
|
||||
# Copyright (c) 2008, 2009 Nicira Networks.
|
||||
#
|
||||
# Permission to use, copy, modify, and/or distribute this software for any
|
||||
# purpose with or without fee is hereby granted, provided that the above
|
||||
# copyright notice and this permission notice appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
dnl Checks for --disable-userspace.
|
||||
AC_DEFUN([OVS_CHECK_USERSPACE],
|
||||
[AC_ARG_ENABLE(
|
||||
[userspace],
|
||||
[AC_HELP_STRING([--disable-userspace],
|
||||
[Disable building userspace components.])],
|
||||
[case "${enableval}" in
|
||||
(yes) build_userspace=true ;;
|
||||
(no) build_userspace=false ;;
|
||||
(*) AC_MSG_ERROR([bad value ${enableval} for --enable-userspace]) ;;
|
||||
esac],
|
||||
[build_userspace=true])
|
||||
AM_CONDITIONAL([ENABLE_USERSPACE], [$build_userspace])])
|
||||
|
||||
dnl OVS_CHECK_LINUX(OPTION, VERSION, VARIABLE, CONDITIONAL)
|
||||
dnl
|
||||
dnl Configure linux kernel source tree
|
||||
AC_DEFUN([OVS_CHECK_LINUX], [
|
||||
AC_ARG_WITH([$1],
|
||||
[AC_HELP_STRING([--with-$1=/path/to/linux-$2],
|
||||
[Specify the linux $2 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])
|
||||
$3=$path
|
||||
AC_SUBST($3)
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
AC_ERROR([source dir $path doesn't exist])
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([for $path kernel version])
|
||||
patchlevel=`sed -n 's/^PATCHLEVEL = //p' "$path/Makefile"`
|
||||
sublevel=`sed -n 's/^SUBLEVEL = //p' "$path/Makefile"`
|
||||
AC_MSG_RESULT([2.$patchlevel.$sublevel])
|
||||
if test "2.$patchlevel" != '$2'; then
|
||||
AC_ERROR([Linux kernel source in $path is not version $2])
|
||||
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
|
||||
m4_if($2, [2.6], [OVS_CHECK_LINUX26_COMPAT])
|
||||
fi
|
||||
AM_CONDITIONAL($4, test -n "$path")
|
||||
])
|
||||
|
||||
dnl OVS_GREP_IFELSE(FILE, REGEX, IF-MATCH, IF-NO-MATCH)
|
||||
dnl
|
||||
dnl Greps FILE for REGEX. If it matches, runs IF-MATCH, otherwise IF-NO-MATCH.
|
||||
AC_DEFUN([OVS_GREP_IFELSE], [
|
||||
AC_MSG_CHECKING([whether $2 matches in $1])
|
||||
grep '$2' $1 >/dev/null 2>&1
|
||||
status=$?
|
||||
case $status in
|
||||
0)
|
||||
AC_MSG_RESULT([yes])
|
||||
$3
|
||||
;;
|
||||
1)
|
||||
AC_MSG_RESULT([no])
|
||||
$4
|
||||
;;
|
||||
*)
|
||||
AC_MSG_ERROR([grep exited with status $status])
|
||||
;;
|
||||
esac
|
||||
])
|
||||
|
||||
dnl OVS_DEFINE(NAME)
|
||||
dnl
|
||||
dnl Defines NAME to 1 in kcompat.h.
|
||||
AC_DEFUN([OVS_DEFINE], [
|
||||
echo '#define $1 1' >> datapath/linux-2.6/kcompat.h.new
|
||||
])
|
||||
|
||||
AC_DEFUN([OVS_CHECK_VETH], [
|
||||
AC_MSG_CHECKING([whether to build veth module])
|
||||
if test "$sublevel" = 18; then
|
||||
AC_MSG_RESULT([yes])
|
||||
AC_SUBST([BUILD_VETH], 1)
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
])
|
||||
|
||||
AC_DEFUN([OVS_CHECK_LOG2_H], [
|
||||
AC_MSG_CHECKING([for $KSRC26/include/linux/log2.h])
|
||||
if test -e $KSRC26/include/linux/log2.h; then
|
||||
AC_MSG_RESULT([yes])
|
||||
OVS_DEFINE([HAVE_LOG2_H])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
])
|
||||
|
||||
dnl OVS_CHECK_LINUX26_COMPAT
|
||||
dnl
|
||||
dnl Runs various Autoconf checks on the Linux 2.6 kernel source in
|
||||
dnl the directory in $KSRC26.
|
||||
AC_DEFUN([OVS_CHECK_LINUX26_COMPAT], [
|
||||
rm -f datapath/linux-2.6/kcompat.h.new
|
||||
mkdir -p datapath/linux-2.6
|
||||
: > datapath/linux-2.6/kcompat.h.new
|
||||
OVS_GREP_IFELSE([$KSRC26/include/linux/skbuff.h], [skb_transport_header],
|
||||
[OVS_DEFINE([HAVE_SKBUFF_HEADER_HELPERS])])
|
||||
OVS_GREP_IFELSE([$KSRC26/include/linux/skbuff.h], [raw],
|
||||
[OVS_DEFINE([HAVE_MAC_RAW])])
|
||||
OVS_GREP_IFELSE([$KSRC26/include/linux/skbuff.h],
|
||||
[skb_copy_from_linear_data_offset],
|
||||
[OVS_DEFINE([HAVE_SKB_COPY_FROM_LINEAR_DATA_OFFSET])])
|
||||
OVS_GREP_IFELSE([$KSRC26/include/net/netlink.h], [NLA_NUL_STRING],
|
||||
[OVS_DEFINE([HAVE_NLA_NUL_STRING])])
|
||||
OVS_GREP_IFELSE([$KSRC26/include/linux/err.h], [ERR_CAST],
|
||||
[OVS_DEFINE([HAVE_ERR_CAST])])
|
||||
OVS_CHECK_LOG2_H
|
||||
OVS_CHECK_VETH
|
||||
if cmp -s datapath/linux-2.6/kcompat.h.new \
|
||||
datapath/linux-2.6/kcompat.h >/dev/null 2>&1; then
|
||||
rm datapath/linux-2.6/kcompat.h.new
|
||||
else
|
||||
mv datapath/linux-2.6/kcompat.h.new datapath/linux-2.6/kcompat.h
|
||||
fi
|
||||
])
|
||||
|
||||
dnl Checks for net/if_packet.h.
|
||||
AC_DEFUN([OVS_CHECK_IF_PACKET],
|
||||
[AC_CHECK_HEADER([net/if_packet.h],
|
||||
[HAVE_IF_PACKET=yes],
|
||||
[HAVE_IF_PACKET=no])
|
||||
AM_CONDITIONAL([HAVE_IF_PACKET], [test "$HAVE_IF_PACKET" = yes])
|
||||
if test "$HAVE_IF_PACKET" = yes; then
|
||||
AC_DEFINE([HAVE_IF_PACKET], [1],
|
||||
[Define to 1 if net/if_packet.h is available.])
|
||||
fi])
|
||||
|
||||
dnl Checks for dpkg-buildpackage. If this is available then we check
|
||||
dnl that the Debian packaging is functional at "make distcheck" time.
|
||||
AC_DEFUN([OVS_CHECK_DPKG_BUILDPACKAGE],
|
||||
[AC_CHECK_PROG([HAVE_DPKG_BUILDPACKAGE], [dpkg-buildpackage], [yes], [no])
|
||||
AM_CONDITIONAL([HAVE_DPKG_BUILDPACKAGE],
|
||||
[test $HAVE_DPKG_BUILDPACKAGE = yes])])
|
||||
|
||||
dnl ----------------------------------------------------------------------
|
||||
dnl These macros are from GNU PSPP, with the following original license:
|
||||
dnl Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
|
||||
dnl This file is free software; the Free Software Foundation
|
||||
dnl gives unlimited permission to copy and/or distribute it,
|
||||
dnl with or without modifications, as long as this notice is preserved.
|
||||
|
||||
dnl OVS_CHECK_CC_OPTION([OPTION], [ACTION-IF-ACCEPTED], [ACTION-IF-REJECTED])
|
||||
dnl Check whether the given C compiler OPTION is accepted.
|
||||
dnl If so, execute ACTION-IF-ACCEPTED, otherwise ACTION-IF-REJECTED.
|
||||
AC_DEFUN([OVS_CHECK_CC_OPTION],
|
||||
[
|
||||
m4_define([ovs_cv_name], [ovs_cv_[]m4_translit([$1], [-], [_])])dnl
|
||||
AC_CACHE_CHECK([whether $CC accepts $1], [ovs_cv_name],
|
||||
[ovs_save_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS $1"
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM(,)], [ovs_cv_name[]=yes], [ovs_cv_name[]=no])
|
||||
CFLAGS="$ovs_save_CFLAGS"])
|
||||
if test $ovs_cv_name = yes; then
|
||||
m4_if([$2], [], [;], [$2])
|
||||
else
|
||||
m4_if([$3], [], [:], [$3])
|
||||
fi
|
||||
])
|
||||
|
||||
dnl OVS_ENABLE_OPTION([OPTION])
|
||||
dnl Check whether the given C compiler OPTION is accepted.
|
||||
dnl If so, add it to CFLAGS.
|
||||
dnl Example: OVS_ENABLE_OPTION([-Wdeclaration-after-statement])
|
||||
AC_DEFUN([OVS_ENABLE_OPTION],
|
||||
[OVS_CHECK_CC_OPTION([$1], [CFLAGS="$CFLAGS $1"])])
|
||||
dnl ----------------------------------------------------------------------
|
89
configure.ac
Normal file
89
configure.ac
Normal file
@ -0,0 +1,89 @@
|
||||
# Copyright (c) 2008, 2009 Nicira Networks
|
||||
#
|
||||
# Permission to use, copy, modify, and/or distribute this software for any
|
||||
# purpose with or without fee is hereby granted, provided that the above
|
||||
# copyright notice and this permission notice appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
AC_PREREQ(2.60)
|
||||
AC_INIT(openvswitch, 0.90.0, ovs-bugs@openvswitch.org)
|
||||
NX_BUILDNR
|
||||
AC_CONFIG_SRCDIR([datapath/datapath.c])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_CONFIG_AUX_DIR([build-aux])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AM_INIT_AUTOMAKE
|
||||
|
||||
AC_PROG_CC
|
||||
AM_PROG_CC_C_O
|
||||
AC_PROG_CPP
|
||||
AC_PROG_RANLIB
|
||||
AC_PROG_MKDIR_P
|
||||
|
||||
AC_ARG_VAR([PERL], [path to Perl interpreter])
|
||||
AC_PATH_PROG([PERL], perl, no)
|
||||
if test "$PERL" = no; then
|
||||
AC_MSG_ERROR([Perl interpreter not found in $PATH or $PERL.])
|
||||
fi
|
||||
|
||||
AC_USE_SYSTEM_EXTENSIONS
|
||||
AC_C_BIGENDIAN
|
||||
AC_SYS_LARGEFILE
|
||||
|
||||
OVS_CHECK_USERSPACE
|
||||
OVS_CHECK_NDEBUG
|
||||
OVS_CHECK_NETLINK
|
||||
OVS_CHECK_OPENSSL
|
||||
OVS_CHECK_LOGDIR
|
||||
OVS_CHECK_CURSES
|
||||
OVS_CHECK_LINUX_VT_H
|
||||
OVS_CHECK_PCRE
|
||||
OVS_CHECK_IF_PACKET
|
||||
OVS_CHECK_DPKG_BUILDPACKAGE
|
||||
|
||||
if $build_userspace; then
|
||||
OVS_CHECK_PKIDIR
|
||||
OVS_CHECK_RUNDIR
|
||||
OVS_CHECK_MALLOC_HOOKS
|
||||
OVS_CHECK_VALGRIND
|
||||
OVS_CHECK_TTY_LOCK_DIR
|
||||
OVS_CHECK_SOCKET_LIBS
|
||||
OVS_CHECK_FAULT_LIBS
|
||||
|
||||
AC_CHECK_FUNCS([strsignal])
|
||||
|
||||
OVS_ENABLE_OPTION([-Wall])
|
||||
OVS_ENABLE_OPTION([-Wno-sign-compare])
|
||||
OVS_ENABLE_OPTION([-Wpointer-arith])
|
||||
OVS_ENABLE_OPTION([-Wdeclaration-after-statement])
|
||||
OVS_ENABLE_OPTION([-Wformat-security])
|
||||
OVS_ENABLE_OPTION([-Wswitch-enum])
|
||||
OVS_ENABLE_OPTION([-Wunused-parameter])
|
||||
OVS_ENABLE_OPTION([-Wstrict-aliasing])
|
||||
OVS_ENABLE_OPTION([-Wbad-function-cast])
|
||||
OVS_ENABLE_OPTION([-Wcast-align])
|
||||
OVS_ENABLE_OPTION([-Wstrict-prototypes])
|
||||
OVS_ENABLE_OPTION([-Wold-style-definition])
|
||||
OVS_ENABLE_OPTION([-Wmissing-prototypes])
|
||||
OVS_ENABLE_OPTION([-Wmissing-field-initializers])
|
||||
OVS_ENABLE_OPTION([-Wno-override-init])
|
||||
fi
|
||||
|
||||
AC_ARG_VAR(KARCH, [Kernel Architecture String])
|
||||
AC_SUBST(KARCH)
|
||||
OVS_CHECK_LINUX(l26, 2.6, KSRC26, L26_ENABLED)
|
||||
|
||||
AC_CONFIG_FILES([Makefile
|
||||
datapath/Makefile
|
||||
datapath/linux-2.6/Kbuild
|
||||
datapath/linux-2.6/Makefile
|
||||
datapath/linux-2.6/Makefile.main])
|
||||
|
||||
AC_OUTPUT
|
7
datapath/.gitignore
vendored
Normal file
7
datapath/.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
/Makefile
|
||||
/Makefile.in
|
||||
*.cmd
|
||||
*.ko
|
||||
*.mod.c
|
||||
Module.symvers
|
||||
|
12
datapath/Makefile.am
Normal file
12
datapath/Makefile.am
Normal file
@ -0,0 +1,12 @@
|
||||
SUBDIRS =
|
||||
if L26_ENABLED
|
||||
SUBDIRS += linux-2.6
|
||||
endif
|
||||
|
||||
EXTRA_DIST = $(dist_headers) $(dist_sources)
|
||||
|
||||
# Suppress warnings about GNU extensions in Modules.mk files.
|
||||
AUTOMAKE_OPTIONS = -Wno-portability
|
||||
|
||||
include Modules.mk
|
||||
include linux-2.6/Modules.mk
|
32
datapath/Modules.mk
Normal file
32
datapath/Modules.mk
Normal file
@ -0,0 +1,32 @@
|
||||
# Some modules should be built and distributed, e.g. openvswitch.
|
||||
#
|
||||
# Some modules should be distributed but not built, e.g. we do not build
|
||||
# veth if the kernel in question already has it.
|
||||
#
|
||||
# Some modules should be built but not distributed, e.g. third-party
|
||||
# hwtable modules.
|
||||
both_modules = openvswitch
|
||||
build_modules = $(both_modules) # Modules to build
|
||||
dist_modules = $(both_modules) # Modules to distribute
|
||||
|
||||
openvswitch_sources = \
|
||||
actions.c \
|
||||
datapath.c \
|
||||
dp_dev.c \
|
||||
dp_notify.c \
|
||||
flow.c \
|
||||
table.c
|
||||
|
||||
openvswitch_headers = \
|
||||
actions.h \
|
||||
compat.h \
|
||||
datapath.h \
|
||||
dp_dev.h \
|
||||
flow.h
|
||||
|
||||
dist_sources = $(foreach module,$(dist_modules),$($(module)_sources))
|
||||
dist_headers = $(foreach module,$(dist_modules),$($(module)_headers))
|
||||
build_sources = $(foreach module,$(build_modules),$($(module)_sources))
|
||||
build_headers = $(foreach module,$(build_modules),$($(module)_headers))
|
||||
build_links = $(notdir $(build_sources))
|
||||
build_objects = $(notdir $(patsubst %.c,%.o,$(build_sources)))
|
421
datapath/actions.c
Normal file
421
datapath/actions.c
Normal file
@ -0,0 +1,421 @@
|
||||
/*
|
||||
* Distributed under the terms of the GNU GPL version 2.
|
||||
* Copyright (c) 2007, 2008, 2009 Nicira Networks.
|
||||
*/
|
||||
|
||||
/* Functions for executing flow actions. */
|
||||
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/udp.h>
|
||||
#include <linux/in6.h>
|
||||
#include <linux/if_vlan.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/checksum.h>
|
||||
#include "datapath.h"
|
||||
#include "dp_dev.h"
|
||||
#include "actions.h"
|
||||
#include "openvswitch/datapath-protocol.h"
|
||||
|
||||
struct sk_buff *
|
||||
make_writable(struct sk_buff *skb, gfp_t gfp)
|
||||
{
|
||||
if (skb_shared(skb) || skb_cloned(skb)) {
|
||||
struct sk_buff *nskb = skb_copy(skb, gfp);
|
||||
if (nskb) {
|
||||
kfree_skb(skb);
|
||||
return nskb;
|
||||
}
|
||||
} else {
|
||||
unsigned int hdr_len = (skb_transport_offset(skb)
|
||||
+ sizeof(struct tcphdr));
|
||||
if (pskb_may_pull(skb, min(hdr_len, skb->len)))
|
||||
return skb;
|
||||
}
|
||||
kfree_skb(skb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
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 != 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_tci(struct datapath *dp, struct sk_buff *skb,
|
||||
struct odp_flow_key *key, const union odp_action *a,
|
||||
int n_actions, gfp_t gfp)
|
||||
{
|
||||
u16 tci, mask;
|
||||
|
||||
if (a->type == ODPAT_SET_VLAN_VID) {
|
||||
tci = ntohs(a->vlan_vid.vlan_vid);
|
||||
mask = VLAN_VID_MASK;
|
||||
key->dl_vlan = htons(tci & mask);
|
||||
} else {
|
||||
tci = a->vlan_pcp.vlan_pcp << 13;
|
||||
mask = VLAN_PCP_MASK;
|
||||
}
|
||||
|
||||
skb = make_writable(skb, gfp);
|
||||
if (!skb)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
if (skb->protocol == htons(ETH_P_8021Q)) {
|
||||
/* Modify vlan id, but maintain other TCI values */
|
||||
struct vlan_ethhdr *vh = vlan_eth_hdr(skb);
|
||||
vh->h_vlan_TCI = htons((ntohs(vh->h_vlan_TCI) & ~mask) | tci);
|
||||
} else {
|
||||
/* Add vlan header */
|
||||
|
||||
/* Set up checksumming pointers for checksum-deferred packets
|
||||
* on Xen. Otherwise, dev_queue_xmit() will try to do this
|
||||
* when we send the packet out on the wire, and it will fail at
|
||||
* that point because skb_checksum_setup() will not look inside
|
||||
* an 802.1Q header. */
|
||||
skb_checksum_setup(skb);
|
||||
|
||||
/* GSO is not implemented for packets with an 802.1Q header, so
|
||||
* we have to do segmentation before we add that header.
|
||||
*
|
||||
* GSO does work with hardware-accelerated VLAN tagging, but we
|
||||
* can't use hardware-accelerated VLAN tagging since it
|
||||
* requires the device to have a VLAN group configured (with
|
||||
* e.g. vconfig(8)) and we don't do that.
|
||||
*
|
||||
* Having to do this here may be a performance loss, since we
|
||||
* can't take advantage of TSO hardware support, although it
|
||||
* does not make a measurable network performance difference
|
||||
* for 1G Ethernet. Fixing that would require patching the
|
||||
* kernel (either to add GSO support to the VLAN protocol or to
|
||||
* support hardware-accelerated VLAN tagging without VLAN
|
||||
* groups configured). */
|
||||
if (skb_is_gso(skb)) {
|
||||
struct sk_buff *segs;
|
||||
|
||||
segs = skb_gso_segment(skb, 0);
|
||||
kfree_skb(skb);
|
||||
if (unlikely(IS_ERR(segs)))
|
||||
return ERR_CAST(segs);
|
||||
|
||||
do {
|
||||
struct sk_buff *nskb = segs->next;
|
||||
int err;
|
||||
|
||||
segs->next = NULL;
|
||||
|
||||
segs = __vlan_put_tag(segs, tci);
|
||||
err = -ENOMEM;
|
||||
if (segs) {
|
||||
struct odp_flow_key segkey = *key;
|
||||
err = execute_actions(dp, segs,
|
||||
&segkey, a + 1,
|
||||
n_actions - 1,
|
||||
gfp);
|
||||
}
|
||||
|
||||
if (unlikely(err)) {
|
||||
while ((segs = nskb)) {
|
||||
nskb = segs->next;
|
||||
segs->next = NULL;
|
||||
kfree_skb(segs);
|
||||
}
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
segs = nskb;
|
||||
} while (segs->next);
|
||||
|
||||
skb = segs;
|
||||
}
|
||||
|
||||
/* The hardware-accelerated version of vlan_put_tag() works
|
||||
* only for a device that has a VLAN group configured (with
|
||||
* e.g. vconfig(8)), so call the software-only version
|
||||
* __vlan_put_tag() directly instead.
|
||||
*/
|
||||
skb = __vlan_put_tag(skb, tci);
|
||||
if (!skb)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
||||
static struct sk_buff *strip_vlan(struct sk_buff *skb,
|
||||
struct odp_flow_key *key, gfp_t gfp)
|
||||
{
|
||||
skb = make_writable(skb, gfp);
|
||||
if (skb) {
|
||||
vlan_pull_tag(skb);
|
||||
key->dl_vlan = htons(ODP_VLAN_NONE);
|
||||
}
|
||||
return skb;
|
||||
}
|
||||
|
||||
static struct sk_buff *set_dl_addr(struct sk_buff *skb,
|
||||
const struct odp_action_dl_addr *a,
|
||||
gfp_t gfp)
|
||||
{
|
||||
skb = make_writable(skb, gfp);
|
||||
if (skb) {
|
||||
struct ethhdr *eh = eth_hdr(skb);
|
||||
memcpy(a->type == ODPAT_SET_DL_SRC ? eh->h_source : eh->h_dest,
|
||||
a->dl_addr, ETH_ALEN);
|
||||
}
|
||||
return 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 struct sk_buff *set_nw_addr(struct sk_buff *skb,
|
||||
struct odp_flow_key *key,
|
||||
const struct odp_action_nw_addr *a,
|
||||
gfp_t gfp)
|
||||
{
|
||||
if (key->dl_type != htons(ETH_P_IP))
|
||||
return skb;
|
||||
|
||||
skb = make_writable(skb, gfp);
|
||||
if (skb) {
|
||||
struct iphdr *nh = ip_hdr(skb);
|
||||
u32 *f = a->type == ODPAT_SET_NW_SRC ? &nh->saddr : &nh->daddr;
|
||||
u32 old = *f;
|
||||
u32 new = a->nw_addr;
|
||||
|
||||
if (key->nw_proto == IPPROTO_TCP) {
|
||||
struct tcphdr *th = tcp_hdr(skb);
|
||||
update_csum(&th->check, skb, old, new, 1);
|
||||
} else if (key->nw_proto == IPPROTO_UDP) {
|
||||
struct udphdr *th = udp_hdr(skb);
|
||||
update_csum(&th->check, skb, old, new, 1);
|
||||
}
|
||||
update_csum(&nh->check, skb, old, new, 0);
|
||||
*f = new;
|
||||
}
|
||||
return skb;
|
||||
}
|
||||
|
||||
static struct sk_buff *
|
||||
set_tp_port(struct sk_buff *skb, struct odp_flow_key *key,
|
||||
const struct odp_action_tp_port *a,
|
||||
gfp_t gfp)
|
||||
{
|
||||
int check_ofs;
|
||||
|
||||
if (key->dl_type != htons(ETH_P_IP))
|
||||
return skb;
|
||||
|
||||
if (key->nw_proto == IPPROTO_TCP)
|
||||
check_ofs = offsetof(struct tcphdr, check);
|
||||
else if (key->nw_proto == IPPROTO_UDP)
|
||||
check_ofs = offsetof(struct udphdr, check);
|
||||
else
|
||||
return skb;
|
||||
|
||||
skb = make_writable(skb, gfp);
|
||||
if (skb) {
|
||||
struct udphdr *th = udp_hdr(skb);
|
||||
u16 *f = a->type == ODPAT_SET_TP_SRC ? &th->source : &th->dest;
|
||||
u16 old = *f;
|
||||
u16 new = a->tp_port;
|
||||
update_csum((u16*)((u8*)skb->data + check_ofs),
|
||||
skb, old, new, 1);
|
||||
*f = new;
|
||||
}
|
||||
return skb;
|
||||
}
|
||||
|
||||
static inline unsigned packet_length(const struct sk_buff *skb)
|
||||
{
|
||||
unsigned length = skb->len - ETH_HLEN;
|
||||
if (skb->protocol == htons(ETH_P_8021Q))
|
||||
length -= VLAN_HLEN;
|
||||
return length;
|
||||
}
|
||||
|
||||
int dp_xmit_skb(struct sk_buff *skb)
|
||||
{
|
||||
struct datapath *dp = skb->dev->br_port->dp;
|
||||
int len = skb->len;
|
||||
|
||||
if (packet_length(skb) > skb->dev->mtu && !skb_is_gso(skb)) {
|
||||
printk(KERN_WARNING "%s: dropped over-mtu packet: %d > %d\n",
|
||||
dp_name(dp), packet_length(skb), skb->dev->mtu);
|
||||
kfree_skb(skb);
|
||||
return -E2BIG;
|
||||
}
|
||||
|
||||
dev_queue_xmit(skb);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static void
|
||||
do_output(struct datapath *dp, struct sk_buff *skb, int out_port)
|
||||
{
|
||||
struct net_bridge_port *p;
|
||||
struct net_device *dev;
|
||||
|
||||
if (!skb)
|
||||
goto error;
|
||||
|
||||
p = dp->ports[out_port];
|
||||
if (!p)
|
||||
goto error;
|
||||
|
||||
dev = skb->dev = p->dev;
|
||||
if (is_dp_dev(dev))
|
||||
dp_dev_recv(dev, skb);
|
||||
else
|
||||
dp_xmit_skb(skb);
|
||||
return;
|
||||
|
||||
error:
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
/* Never consumes 'skb'. Returns a port that 'skb' should be sent to, -1 if
|
||||
* none. */
|
||||
static int output_group(struct datapath *dp, __u16 group,
|
||||
struct sk_buff *skb, gfp_t gfp)
|
||||
{
|
||||
struct dp_port_group *g = rcu_dereference(dp->groups[group]);
|
||||
int prev_port = -1;
|
||||
int i;
|
||||
|
||||
if (!g)
|
||||
return -1;
|
||||
for (i = 0; i < g->n_ports; i++) {
|
||||
struct net_bridge_port *p = dp->ports[g->ports[i]];
|
||||
if (!p || skb->dev == p->dev)
|
||||
continue;
|
||||
if (prev_port != -1) {
|
||||
struct sk_buff *clone = skb_clone(skb, gfp);
|
||||
if (!clone)
|
||||
return -1;
|
||||
do_output(dp, clone, prev_port);
|
||||
}
|
||||
prev_port = p->port_no;
|
||||
}
|
||||
return prev_port;
|
||||
}
|
||||
|
||||
static int
|
||||
output_control(struct datapath *dp, struct sk_buff *skb, u32 arg, gfp_t gfp)
|
||||
{
|
||||
skb = skb_clone(skb, gfp);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
return dp_output_control(dp, skb, _ODPL_ACTION_NR, arg);
|
||||
}
|
||||
|
||||
/* Execute a list of actions against 'skb'. */
|
||||
int execute_actions(struct datapath *dp, struct sk_buff *skb,
|
||||
struct odp_flow_key *key,
|
||||
const union odp_action *a, int n_actions,
|
||||
gfp_t gfp)
|
||||
{
|
||||
/* 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 = -1;
|
||||
int err = 0;
|
||||
for (; n_actions > 0; a++, n_actions--) {
|
||||
WARN_ON_ONCE(skb_shared(skb));
|
||||
if (prev_port != -1) {
|
||||
do_output(dp, skb_clone(skb, gfp), prev_port);
|
||||
prev_port = -1;
|
||||
}
|
||||
|
||||
switch (a->type) {
|
||||
case ODPAT_OUTPUT:
|
||||
prev_port = a->output.port;
|
||||
break;
|
||||
|
||||
case ODPAT_OUTPUT_GROUP:
|
||||
prev_port = output_group(dp, a->output_group.group,
|
||||
skb, gfp);
|
||||
break;
|
||||
|
||||
case ODPAT_CONTROLLER:
|
||||
err = output_control(dp, skb, a->controller.arg, gfp);
|
||||
if (err) {
|
||||
kfree_skb(skb);
|
||||
return err;
|
||||
}
|
||||
break;
|
||||
|
||||
case ODPAT_SET_VLAN_VID:
|
||||
case ODPAT_SET_VLAN_PCP:
|
||||
skb = modify_vlan_tci(dp, skb, key, a, n_actions, gfp);
|
||||
if (IS_ERR(skb))
|
||||
return PTR_ERR(skb);
|
||||
break;
|
||||
|
||||
case ODPAT_STRIP_VLAN:
|
||||
skb = strip_vlan(skb, key, gfp);
|
||||
break;
|
||||
|
||||
case ODPAT_SET_DL_SRC:
|
||||
case ODPAT_SET_DL_DST:
|
||||
skb = set_dl_addr(skb, &a->dl_addr, gfp);
|
||||
break;
|
||||
|
||||
case ODPAT_SET_NW_SRC:
|
||||
case ODPAT_SET_NW_DST:
|
||||
skb = set_nw_addr(skb, key, &a->nw_addr, gfp);
|
||||
break;
|
||||
|
||||
case ODPAT_SET_TP_SRC:
|
||||
case ODPAT_SET_TP_DST:
|
||||
skb = set_tp_port(skb, key, &a->tp_port, gfp);
|
||||
break;
|
||||
}
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (prev_port != -1)
|
||||
do_output(dp, skb, prev_port);
|
||||
else
|
||||
kfree_skb(skb);
|
||||
return err;
|
||||
}
|
18
datapath/actions.h
Normal file
18
datapath/actions.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef ACTIONS_H
|
||||
#define ACTIONS_H 1
|
||||
|
||||
#include <linux/gfp.h>
|
||||
|
||||
struct datapath;
|
||||
struct sk_buff;
|
||||
struct odp_flow_key;
|
||||
union odp_action;
|
||||
|
||||
struct sk_buff *make_writable(struct sk_buff *, gfp_t gfp);
|
||||
int dp_xmit_skb(struct sk_buff *);
|
||||
int execute_actions(struct datapath *dp, struct sk_buff *skb,
|
||||
struct odp_flow_key *key,
|
||||
const union odp_action *, int n_actions,
|
||||
gfp_t gfp);
|
||||
|
||||
#endif /* actions.h */
|
185
datapath/brc_procfs.c
Normal file
185
datapath/brc_procfs.c
Normal file
@ -0,0 +1,185 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <net/genetlink.h>
|
||||
#include "openvswitch/brcompat-netlink.h"
|
||||
|
||||
/* This code implements a Generic Netlink command BRC_GENL_C_SET_PROC that can
|
||||
* be used to add, modify, and delete arbitrary files in selected
|
||||
* subdirectories of /proc. It's a horrible kluge prompted by the need to
|
||||
* simulate certain /proc/net/vlan and /proc/net/bonding files for software
|
||||
* that wants to read them, and with any luck it will go away eventually.
|
||||
*
|
||||
* The implementation is a kluge too. In particular, we want to release the
|
||||
* strings copied into the 'data' members of proc_dir_entry when the
|
||||
* proc_dir_entry structures are freed, but there doesn't appear to be a way to
|
||||
* hook that, so instead we have to rely on being the only entity modifying the
|
||||
* directories in question.
|
||||
*/
|
||||
|
||||
static int brc_seq_show(struct seq_file *seq, void *unused)
|
||||
{
|
||||
seq_puts(seq, seq->private);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int brc_seq_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, brc_seq_show, PDE(inode)->data);
|
||||
}
|
||||
|
||||
static struct file_operations brc_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = brc_seq_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static struct proc_dir_entry *proc_vlan_dir;
|
||||
static struct proc_dir_entry *proc_bonding_dir;
|
||||
|
||||
struct proc_dir_entry *brc_lookup_entry(struct proc_dir_entry *de, const char *name)
|
||||
{
|
||||
int namelen = strlen(name);
|
||||
for (de = de->subdir; de; de = de->next) {
|
||||
if (de->namelen != namelen)
|
||||
continue;
|
||||
if (!memcmp(name, de->name, de->namelen))
|
||||
return de;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct proc_dir_entry *brc_open_dir(const char *dir_name,
|
||||
struct proc_dir_entry *parent,
|
||||
struct proc_dir_entry **dirp)
|
||||
{
|
||||
if (!*dirp) {
|
||||
struct proc_dir_entry *dir;
|
||||
if (brc_lookup_entry(parent, dir_name)) {
|
||||
printk(KERN_WARNING "%s proc directory exists, can't "
|
||||
"simulate--probably its real module is "
|
||||
"loaded\n", dir_name);
|
||||
return NULL;
|
||||
}
|
||||
dir = *dirp = proc_mkdir(dir_name, parent);
|
||||
}
|
||||
return *dirp;
|
||||
}
|
||||
|
||||
/* Maximum length of the BRC_GENL_A_PROC_DIR and BRC_GENL_A_PROC_NAME strings.
|
||||
* If we could depend on supporting NLA_NUL_STRING and the .len member in
|
||||
* Generic Netlink policy, then we could just put this in brc_genl_policy (and
|
||||
* simplify brc_genl_set_proc() below too), but upstream 2.6.18 does not have
|
||||
* either. */
|
||||
#define BRC_NAME_LEN_MAX 32
|
||||
|
||||
int brc_genl_set_proc(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct proc_dir_entry *dir, *entry;
|
||||
const char *dir_name, *name;
|
||||
char *data;
|
||||
|
||||
if (!info->attrs[BRC_GENL_A_PROC_DIR] ||
|
||||
VERIFY_NUL_STRING(info->attrs[BRC_GENL_A_PROC_DIR]) ||
|
||||
!info->attrs[BRC_GENL_A_PROC_NAME] ||
|
||||
VERIFY_NUL_STRING(info->attrs[BRC_GENL_A_PROC_NAME]) ||
|
||||
(info->attrs[BRC_GENL_A_PROC_DATA] &&
|
||||
VERIFY_NUL_STRING(info->attrs[BRC_GENL_A_PROC_DATA])))
|
||||
return -EINVAL;
|
||||
|
||||
dir_name = nla_data(info->attrs[BRC_GENL_A_PROC_DIR]);
|
||||
name = nla_data(info->attrs[BRC_GENL_A_PROC_NAME]);
|
||||
if (strlen(dir_name) > BRC_NAME_LEN_MAX ||
|
||||
strlen(name) > BRC_NAME_LEN_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
if (!strcmp(dir_name, "net/vlan"))
|
||||
dir = brc_open_dir("vlan", proc_net, &proc_vlan_dir);
|
||||
else if (!strcmp(dir_name, "net/bonding"))
|
||||
dir = brc_open_dir("bonding", proc_net, &proc_bonding_dir);
|
||||
else
|
||||
return -EINVAL;
|
||||
if (!dir) {
|
||||
/* Probably failed because the module that really implements
|
||||
* the function in question is loaded and already owns the
|
||||
* directory in question.*/
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
entry = brc_lookup_entry(dir, name);
|
||||
if (!info->attrs[BRC_GENL_A_PROC_DATA]) {
|
||||
if (!entry)
|
||||
return -ENOENT;
|
||||
|
||||
data = entry->data;
|
||||
remove_proc_entry(name, dir);
|
||||
if (brc_lookup_entry(dir, name))
|
||||
return -EBUSY; /* Shouldn't happen */
|
||||
|
||||
kfree(data);
|
||||
} else {
|
||||
data = kstrdup(nla_data(info->attrs[BRC_GENL_A_PROC_DATA]),
|
||||
GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
if (entry) {
|
||||
char *old_data = entry->data;
|
||||
entry->data = data;
|
||||
kfree(old_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
entry = create_proc_entry(name, S_IFREG|S_IRUSR|S_IWUSR, dir);
|
||||
if (!entry) {
|
||||
kfree(data);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
entry->proc_fops = &brc_fops;
|
||||
entry->data = data;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void kill_proc_dir(const char *dir_name,
|
||||
struct proc_dir_entry *parent,
|
||||
struct proc_dir_entry *dir)
|
||||
{
|
||||
if (!dir)
|
||||
return;
|
||||
for (;;) {
|
||||
struct proc_dir_entry *e;
|
||||
char *data;
|
||||
char name[BRC_NAME_LEN_MAX + 1];
|
||||
|
||||
e = dir->subdir;
|
||||
if (!e)
|
||||
break;
|
||||
|
||||
if (e->namelen >= sizeof name) {
|
||||
/* Can't happen: we prevent adding names this long by
|
||||
* limiting the BRC_GENL_A_PROC_NAME string to
|
||||
* BRC_NAME_LEN_MAX bytes. */
|
||||
WARN_ON(1);
|
||||
break;
|
||||
}
|
||||
strcpy(name, e->name);
|
||||
|
||||
data = e->data;
|
||||
e->data = NULL;
|
||||
kfree(data);
|
||||
|
||||
remove_proc_entry(name, dir);
|
||||
}
|
||||
remove_proc_entry(dir_name, parent);
|
||||
}
|
||||
|
||||
void brc_procfs_exit(void)
|
||||
{
|
||||
kill_proc_dir("vlan", proc_net, proc_vlan_dir);
|
||||
kill_proc_dir("bonding", proc_net, proc_bonding_dir);
|
||||
}
|
11
datapath/brc_procfs.h
Normal file
11
datapath/brc_procfs.h
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef BRC_PROCFS_H
|
||||
#define BRC_PROCFS_H 1
|
||||
|
||||
struct sk_buff;
|
||||
struct genl_info;
|
||||
|
||||
void brc_procfs_exit(void);
|
||||
int brc_genl_set_proc(struct sk_buff *skb, struct genl_info *info);
|
||||
|
||||
#endif /* brc_procfs.h */
|
||||
|
25
datapath/brc_sysfs.h
Normal file
25
datapath/brc_sysfs.h
Normal file
@ -0,0 +1,25 @@
|
||||
#ifndef BRC_SYSFS_H
|
||||
#define BRC_SYSFS_H 1
|
||||
|
||||
struct datapath;
|
||||
struct net_bridge_port;
|
||||
|
||||
/* brc_sysfs_dp.c */
|
||||
int brc_sysfs_add_dp(struct datapath *dp);
|
||||
int brc_sysfs_del_dp(struct datapath *dp);
|
||||
|
||||
/* brc_sysfs_if.c */
|
||||
int brc_sysfs_add_if(struct net_bridge_port *p);
|
||||
int brc_sysfs_del_if(struct net_bridge_port *p);
|
||||
|
||||
#include <linux/version.h>
|
||||
#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18)
|
||||
#define SUPPORT_SYSFS 1
|
||||
#else
|
||||
/* We only support sysfs on Linux 2.6.18 because that's the only place we
|
||||
* really need it (on Xen, for brcompat) and it's a big pain to try to support
|
||||
* multiple versions. */
|
||||
#endif
|
||||
|
||||
#endif /* brc_sysfs.h */
|
||||
|
532
datapath/brc_sysfs_dp.c
Normal file
532
datapath/brc_sysfs_dp.c
Normal file
@ -0,0 +1,532 @@
|
||||
#include <linux/version.h>
|
||||
|
||||
/*
|
||||
* Sysfs attributes of bridge for Open vSwitch
|
||||
*
|
||||
* This has been shamelessly copied from the kernel sources.
|
||||
*/
|
||||
|
||||
#include <linux/capability.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/if_bridge.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/times.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
#include "brc_sysfs.h"
|
||||
#include "datapath.h"
|
||||
#include "dp_dev.h"
|
||||
|
||||
#ifdef SUPPORT_SYSFS
|
||||
#define to_dev(obj) container_of(obj, struct device, kobj)
|
||||
|
||||
/* Hack to attempt to build on more platforms. */
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)
|
||||
#define to_kobj(d) &(d)->class_dev.kobj
|
||||
#define BRC_DEVICE_ATTR CLASS_DEVICE_ATTR
|
||||
#else
|
||||
#define to_kobj(d) &(d)->dev.kobj
|
||||
#define BRC_DEVICE_ATTR DEVICE_ATTR
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Common code for storing bridge parameters.
|
||||
*/
|
||||
static ssize_t store_bridge_parm(struct class_device *d,
|
||||
const char *buf, size_t len,
|
||||
void (*set)(struct datapath *, unsigned long))
|
||||
{
|
||||
struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
|
||||
char *endp;
|
||||
unsigned long val;
|
||||
|
||||
if (!capable(CAP_NET_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
val = simple_strtoul(buf, &endp, 0);
|
||||
if (endp == buf)
|
||||
return -EINVAL;
|
||||
|
||||
#if 0
|
||||
spin_lock_bh(&br->lock);
|
||||
(*set)(br, val);
|
||||
spin_unlock_bh(&br->lock);
|
||||
#else
|
||||
/* xxx We use a default value of 0 for all fields. If the caller is
|
||||
* xxx attempting to set the value to our default, just silently
|
||||
* xxx ignore the request.
|
||||
*/
|
||||
if (val != 0) {
|
||||
printk("%s: xxx writing dp parms not supported yet!\n",
|
||||
dp_name(dp));
|
||||
}
|
||||
#endif
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static ssize_t show_forward_delay(struct class_device *d,
|
||||
char *buf)
|
||||
{
|
||||
#if 0
|
||||
struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
|
||||
return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->forward_delay));
|
||||
#else
|
||||
return sprintf(buf, "%d\n", 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void set_forward_delay(struct datapath *dp, unsigned long val)
|
||||
{
|
||||
#if 0
|
||||
unsigned long delay = clock_t_to_jiffies(val);
|
||||
br->forward_delay = delay;
|
||||
if (br_is_root_bridge(br))
|
||||
br->bridge_forward_delay = delay;
|
||||
#else
|
||||
printk("%s: xxx attempt to set_forward_delay()\n", dp_name(dp));
|
||||
#endif
|
||||
}
|
||||
|
||||
static ssize_t store_forward_delay(struct class_device *d,
|
||||
const char *buf, size_t len)
|
||||
{
|
||||
return store_bridge_parm(d, buf, len, set_forward_delay);
|
||||
}
|
||||
static BRC_DEVICE_ATTR(forward_delay, S_IRUGO | S_IWUSR,
|
||||
show_forward_delay, store_forward_delay);
|
||||
|
||||
static ssize_t show_hello_time(struct class_device *d, char *buf)
|
||||
{
|
||||
#if 0
|
||||
return sprintf(buf, "%lu\n",
|
||||
jiffies_to_clock_t(to_bridge(d)->hello_time));
|
||||
#else
|
||||
return sprintf(buf, "%d\n", 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void set_hello_time(struct datapath *dp, unsigned long val)
|
||||
{
|
||||
#if 0
|
||||
unsigned long t = clock_t_to_jiffies(val);
|
||||
br->hello_time = t;
|
||||
if (br_is_root_bridge(br))
|
||||
br->bridge_hello_time = t;
|
||||
#else
|
||||
printk("%s: xxx attempt to set_hello_time()\n", dp_name(dp));
|
||||
#endif
|
||||
}
|
||||
|
||||
static ssize_t store_hello_time(struct class_device *d,
|
||||
const char *buf,
|
||||
size_t len)
|
||||
{
|
||||
return store_bridge_parm(d, buf, len, set_hello_time);
|
||||
}
|
||||
static BRC_DEVICE_ATTR(hello_time, S_IRUGO | S_IWUSR, show_hello_time,
|
||||
store_hello_time);
|
||||
|
||||
static ssize_t show_max_age(struct class_device *d,
|
||||
char *buf)
|
||||
{
|
||||
#if 0
|
||||
return sprintf(buf, "%lu\n",
|
||||
jiffies_to_clock_t(to_bridge(d)->max_age));
|
||||
#else
|
||||
return sprintf(buf, "%d\n", 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void set_max_age(struct datapath *dp, unsigned long val)
|
||||
{
|
||||
#if 0
|
||||
unsigned long t = clock_t_to_jiffies(val);
|
||||
br->max_age = t;
|
||||
if (br_is_root_bridge(br))
|
||||
br->bridge_max_age = t;
|
||||
#else
|
||||
printk("%s: xxx attempt to set_max_age()\n", dp_name(dp));
|
||||
#endif
|
||||
}
|
||||
|
||||
static ssize_t store_max_age(struct class_device *d,
|
||||
const char *buf, size_t len)
|
||||
{
|
||||
return store_bridge_parm(d, buf, len, set_max_age);
|
||||
}
|
||||
static BRC_DEVICE_ATTR(max_age, S_IRUGO | S_IWUSR, show_max_age, store_max_age);
|
||||
|
||||
static ssize_t show_ageing_time(struct class_device *d,
|
||||
char *buf)
|
||||
{
|
||||
#if 0
|
||||
struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
|
||||
return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->ageing_time));
|
||||
#else
|
||||
return sprintf(buf, "%d\n", 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void set_ageing_time(struct datapath *dp, unsigned long val)
|
||||
{
|
||||
#if 0
|
||||
br->ageing_time = clock_t_to_jiffies(val);
|
||||
#else
|
||||
printk("%s: xxx attempt to set_ageing_time()\n", dp_name(dp));
|
||||
#endif
|
||||
}
|
||||
|
||||
static ssize_t store_ageing_time(struct class_device *d,
|
||||
const char *buf, size_t len)
|
||||
{
|
||||
return store_bridge_parm(d, buf, len, set_ageing_time);
|
||||
}
|
||||
static BRC_DEVICE_ATTR(ageing_time, S_IRUGO | S_IWUSR, show_ageing_time,
|
||||
store_ageing_time);
|
||||
|
||||
static ssize_t show_stp_state(struct class_device *d,
|
||||
char *buf)
|
||||
{
|
||||
#if 0
|
||||
struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
|
||||
return sprintf(buf, "%d\n", br->stp_enabled);
|
||||
#else
|
||||
return sprintf(buf, "%d\n", 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static ssize_t store_stp_state(struct class_device *d,
|
||||
const char *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
|
||||
#if 0
|
||||
char *endp;
|
||||
unsigned long val;
|
||||
|
||||
if (!capable(CAP_NET_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
val = simple_strtoul(buf, &endp, 0);
|
||||
if (endp == buf)
|
||||
return -EINVAL;
|
||||
|
||||
rtnl_lock();
|
||||
br_stp_set_enabled(br, val);
|
||||
rtnl_unlock();
|
||||
#else
|
||||
printk("%s: xxx attempt to set_stp_state()\n", dp_name(dp));
|
||||
#endif
|
||||
|
||||
return len;
|
||||
}
|
||||
static BRC_DEVICE_ATTR(stp_state, S_IRUGO | S_IWUSR, show_stp_state,
|
||||
store_stp_state);
|
||||
|
||||
static ssize_t show_priority(struct class_device *d,
|
||||
char *buf)
|
||||
{
|
||||
#if 0
|
||||
struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
|
||||
return sprintf(buf, "%d\n",
|
||||
(br->bridge_id.prio[0] << 8) | br->bridge_id.prio[1]);
|
||||
#else
|
||||
return sprintf(buf, "%d\n", 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void set_priority(struct datapath *dp, unsigned long val)
|
||||
{
|
||||
#if 0
|
||||
br_stp_set_bridge_priority(br, (u16) val);
|
||||
#else
|
||||
printk("%s: xxx attempt to set_priority()\n", dp_name(dp));
|
||||
#endif
|
||||
}
|
||||
|
||||
static ssize_t store_priority(struct class_device *d,
|
||||
const char *buf, size_t len)
|
||||
{
|
||||
return store_bridge_parm(d, buf, len, set_priority);
|
||||
}
|
||||
static BRC_DEVICE_ATTR(priority, S_IRUGO | S_IWUSR, show_priority, store_priority);
|
||||
|
||||
static ssize_t show_root_id(struct class_device *d,
|
||||
char *buf)
|
||||
{
|
||||
#if 0
|
||||
return br_show_bridge_id(buf, &to_bridge(d)->designated_root);
|
||||
#else
|
||||
return sprintf(buf, "0000.010203040506\n");
|
||||
#endif
|
||||
}
|
||||
static BRC_DEVICE_ATTR(root_id, S_IRUGO, show_root_id, NULL);
|
||||
|
||||
static ssize_t show_bridge_id(struct class_device *d,
|
||||
char *buf)
|
||||
{
|
||||
struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
|
||||
const unsigned char *addr = dp->ports[ODPP_LOCAL]->dev->dev_addr;
|
||||
|
||||
/* xxx Do we need a lock of some sort? */
|
||||
return sprintf(buf, "%.2x%.2x.%.2x%.2x%.2x%.2x%.2x%.2x\n",
|
||||
0, 0, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
|
||||
}
|
||||
static BRC_DEVICE_ATTR(bridge_id, S_IRUGO, show_bridge_id, NULL);
|
||||
|
||||
static ssize_t show_root_port(struct class_device *d,
|
||||
char *buf)
|
||||
{
|
||||
#if 0
|
||||
return sprintf(buf, "%d\n", to_bridge(d)->root_port);
|
||||
#else
|
||||
return sprintf(buf, "%d\n", 0);
|
||||
#endif
|
||||
}
|
||||
static BRC_DEVICE_ATTR(root_port, S_IRUGO, show_root_port, NULL);
|
||||
|
||||
static ssize_t show_root_path_cost(struct class_device *d,
|
||||
char *buf)
|
||||
{
|
||||
#if 0
|
||||
return sprintf(buf, "%d\n", to_bridge(d)->root_path_cost);
|
||||
#else
|
||||
return sprintf(buf, "%d\n", 0);
|
||||
#endif
|
||||
}
|
||||
static BRC_DEVICE_ATTR(root_path_cost, S_IRUGO, show_root_path_cost, NULL);
|
||||
|
||||
static ssize_t show_topology_change(struct class_device *d,
|
||||
char *buf)
|
||||
{
|
||||
#if 0
|
||||
return sprintf(buf, "%d\n", to_bridge(d)->topology_change);
|
||||
#else
|
||||
return sprintf(buf, "%d\n", 0);
|
||||
#endif
|
||||
}
|
||||
static BRC_DEVICE_ATTR(topology_change, S_IRUGO, show_topology_change, NULL);
|
||||
|
||||
static ssize_t show_topology_change_detected(struct class_device *d,
|
||||
char *buf)
|
||||
{
|
||||
#if 0
|
||||
struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
|
||||
return sprintf(buf, "%d\n", br->topology_change_detected);
|
||||
#else
|
||||
return sprintf(buf, "%d\n", 0);
|
||||
#endif
|
||||
}
|
||||
static BRC_DEVICE_ATTR(topology_change_detected, S_IRUGO,
|
||||
show_topology_change_detected, NULL);
|
||||
|
||||
static ssize_t show_hello_timer(struct class_device *d,
|
||||
char *buf)
|
||||
{
|
||||
#if 0
|
||||
struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
|
||||
return sprintf(buf, "%ld\n", br_timer_value(&br->hello_timer));
|
||||
#else
|
||||
return sprintf(buf, "%d\n", 0);
|
||||
#endif
|
||||
}
|
||||
static BRC_DEVICE_ATTR(hello_timer, S_IRUGO, show_hello_timer, NULL);
|
||||
|
||||
static ssize_t show_tcn_timer(struct class_device *d,
|
||||
char *buf)
|
||||
{
|
||||
#if 0
|
||||
struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
|
||||
return sprintf(buf, "%ld\n", br_timer_value(&br->tcn_timer));
|
||||
#else
|
||||
return sprintf(buf, "%d\n", 0);
|
||||
#endif
|
||||
}
|
||||
static BRC_DEVICE_ATTR(tcn_timer, S_IRUGO, show_tcn_timer, NULL);
|
||||
|
||||
static ssize_t show_topology_change_timer(struct class_device *d,
|
||||
char *buf)
|
||||
{
|
||||
#if 0
|
||||
struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
|
||||
return sprintf(buf, "%ld\n", br_timer_value(&br->topology_change_timer));
|
||||
#else
|
||||
return sprintf(buf, "%d\n", 0);
|
||||
#endif
|
||||
}
|
||||
static BRC_DEVICE_ATTR(topology_change_timer, S_IRUGO, show_topology_change_timer,
|
||||
NULL);
|
||||
|
||||
static ssize_t show_gc_timer(struct class_device *d,
|
||||
char *buf)
|
||||
{
|
||||
#if 0
|
||||
struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
|
||||
return sprintf(buf, "%ld\n", br_timer_value(&br->gc_timer));
|
||||
#else
|
||||
return sprintf(buf, "%d\n", 0);
|
||||
#endif
|
||||
}
|
||||
static BRC_DEVICE_ATTR(gc_timer, S_IRUGO, show_gc_timer, NULL);
|
||||
|
||||
static ssize_t show_group_addr(struct class_device *d,
|
||||
char *buf)
|
||||
{
|
||||
#if 0
|
||||
struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
|
||||
return sprintf(buf, "%x:%x:%x:%x:%x:%x\n",
|
||||
br->group_addr[0], br->group_addr[1],
|
||||
br->group_addr[2], br->group_addr[3],
|
||||
br->group_addr[4], br->group_addr[5]);
|
||||
#else
|
||||
return sprintf(buf, "00:01:02:03:04:05\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
static ssize_t store_group_addr(struct class_device *d,
|
||||
const char *buf, size_t len)
|
||||
{
|
||||
struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
|
||||
#if 0
|
||||
unsigned new_addr[6];
|
||||
int i;
|
||||
|
||||
if (!capable(CAP_NET_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
if (sscanf(buf, "%x:%x:%x:%x:%x:%x",
|
||||
&new_addr[0], &new_addr[1], &new_addr[2],
|
||||
&new_addr[3], &new_addr[4], &new_addr[5]) != 6)
|
||||
return -EINVAL;
|
||||
|
||||
/* Must be 01:80:c2:00:00:0X */
|
||||
for (i = 0; i < 5; i++)
|
||||
if (new_addr[i] != br_group_address[i])
|
||||
return -EINVAL;
|
||||
|
||||
if (new_addr[5] & ~0xf)
|
||||
return -EINVAL;
|
||||
|
||||
if (new_addr[5] == 1 /* 802.3x Pause address */
|
||||
|| new_addr[5] == 2 /* 802.3ad Slow protocols */
|
||||
|| new_addr[5] == 3) /* 802.1X PAE address */
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_bh(&br->lock);
|
||||
for (i = 0; i < 6; i++)
|
||||
br->group_addr[i] = new_addr[i];
|
||||
spin_unlock_bh(&br->lock);
|
||||
#else
|
||||
printk("%s: xxx attempt to store_group_addr()\n", dp_name(dp));
|
||||
#endif
|
||||
return len;
|
||||
}
|
||||
|
||||
static BRC_DEVICE_ATTR(group_addr, S_IRUGO | S_IWUSR,
|
||||
show_group_addr, store_group_addr);
|
||||
|
||||
static struct attribute *bridge_attrs[] = {
|
||||
&class_device_attr_forward_delay.attr,
|
||||
&class_device_attr_hello_time.attr,
|
||||
&class_device_attr_max_age.attr,
|
||||
&class_device_attr_ageing_time.attr,
|
||||
&class_device_attr_stp_state.attr,
|
||||
&class_device_attr_priority.attr,
|
||||
&class_device_attr_bridge_id.attr,
|
||||
&class_device_attr_root_id.attr,
|
||||
&class_device_attr_root_path_cost.attr,
|
||||
&class_device_attr_root_port.attr,
|
||||
&class_device_attr_topology_change.attr,
|
||||
&class_device_attr_topology_change_detected.attr,
|
||||
&class_device_attr_hello_timer.attr,
|
||||
&class_device_attr_tcn_timer.attr,
|
||||
&class_device_attr_topology_change_timer.attr,
|
||||
&class_device_attr_gc_timer.attr,
|
||||
&class_device_attr_group_addr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group bridge_group = {
|
||||
.name = SYSFS_BRIDGE_ATTR,
|
||||
.attrs = bridge_attrs,
|
||||
};
|
||||
|
||||
/*
|
||||
* Add entries in sysfs onto the existing network class device
|
||||
* for the bridge.
|
||||
* Adds a attribute group "bridge" containing tuning parameters.
|
||||
* Sub directory to hold links to interfaces.
|
||||
*
|
||||
* Note: the ifobj exists only to be a subdirectory
|
||||
* to hold links. The ifobj exists in the same data structure
|
||||
* as its parent the bridge so reference counting works.
|
||||
*/
|
||||
int brc_sysfs_add_dp(struct datapath *dp)
|
||||
{
|
||||
struct kobject *kobj = to_kobj(dp->ports[ODPP_LOCAL]->dev);
|
||||
int err;
|
||||
|
||||
err = sysfs_create_group(kobj, &bridge_group);
|
||||
if (err) {
|
||||
pr_info("%s: can't create group %s/%s\n",
|
||||
__func__, dp_name(dp), bridge_group.name);
|
||||
goto out1;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
|
||||
kobject_set_name(&dp->ifobj, SYSFS_BRIDGE_PORT_SUBDIR);
|
||||
dp->ifobj.ktype = NULL;
|
||||
dp->ifobj.kset = NULL;
|
||||
dp->ifobj.parent = kobj;
|
||||
|
||||
err = kobject_register(&dp->ifobj);
|
||||
if (err) {
|
||||
pr_info("%s: can't add kobject (directory) %s/%s\n",
|
||||
__FUNCTION__, dp_name(dp), dp->ifobj.name);
|
||||
goto out2;
|
||||
}
|
||||
#else
|
||||
br->ifobj = kobject_create_and_add(SYSFS_BRIDGE_PORT_SUBDIR, kobj);
|
||||
if (!br->ifobj) {
|
||||
pr_info("%s: can't add kobject (directory) %s/%s\n",
|
||||
__func__, dp_name(dp), SYSFS_BRIDGE_PORT_SUBDIR);
|
||||
goto out2;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
out2:
|
||||
sysfs_remove_group(kobj, &bridge_group);
|
||||
out1:
|
||||
return err;
|
||||
}
|
||||
|
||||
int brc_sysfs_del_dp(struct datapath *dp)
|
||||
{
|
||||
struct kobject *kobj = to_kobj(dp->ports[ODPP_LOCAL]->dev);
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
|
||||
kobject_unregister(&dp->ifobj);
|
||||
#else
|
||||
kobject_put(dp->ifobj);
|
||||
#endif
|
||||
sysfs_remove_group(kobj, &bridge_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else /* !SUPPORT_SYSFS */
|
||||
int brc_sysfs_add_dp(struct datapath *dp) { return 0; }
|
||||
int brc_sysfs_del_dp(struct datapath *dp) { return 0; }
|
||||
int brc_sysfs_add_if(struct net_bridge_port *p) { return 0; }
|
||||
int brc_sysfs_del_if(struct net_bridge_port *p)
|
||||
{
|
||||
dev_put(p->dev);
|
||||
kfree(p);
|
||||
return 0;
|
||||
}
|
||||
#endif /* !SUPPORT_SYSFS */
|
334
datapath/brc_sysfs_if.c
Normal file
334
datapath/brc_sysfs_if.c
Normal file
@ -0,0 +1,334 @@
|
||||
/*
|
||||
* Sysfs attributes of bridge ports for Open vSwitch
|
||||
*
|
||||
* This has been shamelessly copied from the kernel sources.
|
||||
*/
|
||||
|
||||
#include <linux/capability.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/if_bridge.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include "brc_sysfs.h"
|
||||
#include "datapath.h"
|
||||
|
||||
#ifdef SUPPORT_SYSFS
|
||||
|
||||
struct brport_attribute {
|
||||
struct attribute attr;
|
||||
ssize_t (*show)(struct net_bridge_port *, char *);
|
||||
ssize_t (*store)(struct net_bridge_port *, unsigned long);
|
||||
};
|
||||
|
||||
#define BRPORT_ATTR(_name,_mode,_show,_store) \
|
||||
struct brport_attribute brport_attr_##_name = { \
|
||||
.attr = {.name = __stringify(_name), \
|
||||
.mode = _mode, \
|
||||
.owner = THIS_MODULE, }, \
|
||||
.show = _show, \
|
||||
.store = _store, \
|
||||
};
|
||||
|
||||
static ssize_t show_path_cost(struct net_bridge_port *p, char *buf)
|
||||
{
|
||||
#if 0
|
||||
return sprintf(buf, "%d\n", p->path_cost);
|
||||
#else
|
||||
return sprintf(buf, "%d\n", 0);
|
||||
#endif
|
||||
}
|
||||
static ssize_t store_path_cost(struct net_bridge_port *p, unsigned long v)
|
||||
{
|
||||
#if 0
|
||||
br_stp_set_path_cost(p, v);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
static BRPORT_ATTR(path_cost, S_IRUGO | S_IWUSR,
|
||||
show_path_cost, store_path_cost);
|
||||
|
||||
static ssize_t show_priority(struct net_bridge_port *p, char *buf)
|
||||
{
|
||||
#if 0
|
||||
return sprintf(buf, "%d\n", p->priority);
|
||||
#else
|
||||
return sprintf(buf, "%d\n", 0);
|
||||
#endif
|
||||
}
|
||||
static ssize_t store_priority(struct net_bridge_port *p, unsigned long v)
|
||||
{
|
||||
#if 0
|
||||
if (v >= (1<<(16-BR_PORT_BITS)))
|
||||
return -ERANGE;
|
||||
br_stp_set_port_priority(p, v);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
static BRPORT_ATTR(priority, S_IRUGO | S_IWUSR,
|
||||
show_priority, store_priority);
|
||||
|
||||
static ssize_t show_designated_root(struct net_bridge_port *p, char *buf)
|
||||
{
|
||||
#if 0
|
||||
return br_show_bridge_id(buf, &p->designated_root);
|
||||
#else
|
||||
return sprintf(buf, "0000.010203040506\n");
|
||||
#endif
|
||||
}
|
||||
static BRPORT_ATTR(designated_root, S_IRUGO, show_designated_root, NULL);
|
||||
|
||||
static ssize_t show_designated_bridge(struct net_bridge_port *p, char *buf)
|
||||
{
|
||||
#if 0
|
||||
return br_show_bridge_id(buf, &p->designated_bridge);
|
||||
#else
|
||||
return sprintf(buf, "0000.060504030201\n");
|
||||
#endif
|
||||
}
|
||||
static BRPORT_ATTR(designated_bridge, S_IRUGO, show_designated_bridge, NULL);
|
||||
|
||||
static ssize_t show_designated_port(struct net_bridge_port *p, char *buf)
|
||||
{
|
||||
#if 0
|
||||
return sprintf(buf, "%d\n", p->designated_port);
|
||||
#else
|
||||
return sprintf(buf, "%d\n", 0);
|
||||
#endif
|
||||
}
|
||||
static BRPORT_ATTR(designated_port, S_IRUGO, show_designated_port, NULL);
|
||||
|
||||
static ssize_t show_designated_cost(struct net_bridge_port *p, char *buf)
|
||||
{
|
||||
#if 0
|
||||
return sprintf(buf, "%d\n", p->designated_cost);
|
||||
#else
|
||||
return sprintf(buf, "%d\n", 0);
|
||||
#endif
|
||||
}
|
||||
static BRPORT_ATTR(designated_cost, S_IRUGO, show_designated_cost, NULL);
|
||||
|
||||
static ssize_t show_port_id(struct net_bridge_port *p, char *buf)
|
||||
{
|
||||
#if 0
|
||||
return sprintf(buf, "0x%x\n", p->port_id);
|
||||
#else
|
||||
return sprintf(buf, "0x%x\n", 0);
|
||||
#endif
|
||||
}
|
||||
static BRPORT_ATTR(port_id, S_IRUGO, show_port_id, NULL);
|
||||
|
||||
static ssize_t show_port_no(struct net_bridge_port *p, char *buf)
|
||||
{
|
||||
return sprintf(buf, "0x%x\n", p->port_no);
|
||||
}
|
||||
|
||||
static BRPORT_ATTR(port_no, S_IRUGO, show_port_no, NULL);
|
||||
|
||||
static ssize_t show_change_ack(struct net_bridge_port *p, char *buf)
|
||||
{
|
||||
#if 0
|
||||
return sprintf(buf, "%d\n", p->topology_change_ack);
|
||||
#else
|
||||
return sprintf(buf, "%d\n", 0);
|
||||
#endif
|
||||
}
|
||||
static BRPORT_ATTR(change_ack, S_IRUGO, show_change_ack, NULL);
|
||||
|
||||
static ssize_t show_config_pending(struct net_bridge_port *p, char *buf)
|
||||
{
|
||||
#if 0
|
||||
return sprintf(buf, "%d\n", p->config_pending);
|
||||
#else
|
||||
return sprintf(buf, "%d\n", 0);
|
||||
#endif
|
||||
}
|
||||
static BRPORT_ATTR(config_pending, S_IRUGO, show_config_pending, NULL);
|
||||
|
||||
static ssize_t show_port_state(struct net_bridge_port *p, char *buf)
|
||||
{
|
||||
#if 0
|
||||
return sprintf(buf, "%d\n", p->state);
|
||||
#else
|
||||
return sprintf(buf, "%d\n", 0);
|
||||
#endif
|
||||
}
|
||||
static BRPORT_ATTR(state, S_IRUGO, show_port_state, NULL);
|
||||
|
||||
static ssize_t show_message_age_timer(struct net_bridge_port *p,
|
||||
char *buf)
|
||||
{
|
||||
#if 0
|
||||
return sprintf(buf, "%ld\n", br_timer_value(&p->message_age_timer));
|
||||
#else
|
||||
return sprintf(buf, "%d\n", 0);
|
||||
#endif
|
||||
}
|
||||
static BRPORT_ATTR(message_age_timer, S_IRUGO, show_message_age_timer, NULL);
|
||||
|
||||
static ssize_t show_forward_delay_timer(struct net_bridge_port *p,
|
||||
char *buf)
|
||||
{
|
||||
#if 0
|
||||
return sprintf(buf, "%ld\n", br_timer_value(&p->forward_delay_timer));
|
||||
#else
|
||||
return sprintf(buf, "%d\n", 0);
|
||||
#endif
|
||||
}
|
||||
static BRPORT_ATTR(forward_delay_timer, S_IRUGO, show_forward_delay_timer, NULL);
|
||||
|
||||
static ssize_t show_hold_timer(struct net_bridge_port *p,
|
||||
char *buf)
|
||||
{
|
||||
#if 0
|
||||
return sprintf(buf, "%ld\n", br_timer_value(&p->hold_timer));
|
||||
#else
|
||||
return sprintf(buf, "%d\n", 0);
|
||||
#endif
|
||||
}
|
||||
static BRPORT_ATTR(hold_timer, S_IRUGO, show_hold_timer, NULL);
|
||||
|
||||
static struct brport_attribute *brport_attrs[] = {
|
||||
&brport_attr_path_cost,
|
||||
&brport_attr_priority,
|
||||
&brport_attr_port_id,
|
||||
&brport_attr_port_no,
|
||||
&brport_attr_designated_root,
|
||||
&brport_attr_designated_bridge,
|
||||
&brport_attr_designated_port,
|
||||
&brport_attr_designated_cost,
|
||||
&brport_attr_state,
|
||||
&brport_attr_change_ack,
|
||||
&brport_attr_config_pending,
|
||||
&brport_attr_message_age_timer,
|
||||
&brport_attr_forward_delay_timer,
|
||||
&brport_attr_hold_timer,
|
||||
NULL
|
||||
};
|
||||
|
||||
#define to_brport_attr(_at) container_of(_at, struct brport_attribute, attr)
|
||||
#define to_brport(obj) container_of(obj, struct net_bridge_port, kobj)
|
||||
|
||||
static ssize_t brport_show(struct kobject * kobj,
|
||||
struct attribute * attr, char * buf)
|
||||
{
|
||||
struct brport_attribute * brport_attr = to_brport_attr(attr);
|
||||
struct net_bridge_port * p = to_brport(kobj);
|
||||
|
||||
return brport_attr->show(p, buf);
|
||||
}
|
||||
|
||||
static ssize_t brport_store(struct kobject * kobj,
|
||||
struct attribute * attr,
|
||||
const char * buf, size_t count)
|
||||
{
|
||||
struct net_bridge_port * p = to_brport(kobj);
|
||||
#if 0
|
||||
struct brport_attribute * brport_attr = to_brport_attr(attr);
|
||||
char *endp;
|
||||
unsigned long val;
|
||||
#endif
|
||||
ssize_t ret = -EINVAL;
|
||||
|
||||
if (!capable(CAP_NET_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
#if 0
|
||||
val = simple_strtoul(buf, &endp, 0);
|
||||
if (endp != buf) {
|
||||
rtnl_lock();
|
||||
if (p->dev && p->br && brport_attr->store) {
|
||||
spin_lock_bh(&p->br->lock);
|
||||
ret = brport_attr->store(p, val);
|
||||
spin_unlock_bh(&p->br->lock);
|
||||
if (ret == 0)
|
||||
ret = count;
|
||||
}
|
||||
rtnl_unlock();
|
||||
}
|
||||
#else
|
||||
printk("%s: xxx writing port parms not supported yet!\n",
|
||||
dp_name(p->dp));
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct sysfs_ops brport_sysfs_ops = {
|
||||
.show = brport_show,
|
||||
.store = brport_store,
|
||||
};
|
||||
|
||||
static void release_nbp(struct kobject *kobj)
|
||||
{
|
||||
struct net_bridge_port *p
|
||||
= container_of(kobj, struct net_bridge_port, kobj);
|
||||
kfree(p);
|
||||
}
|
||||
|
||||
struct kobj_type brport_ktype = {
|
||||
.sysfs_ops = &brport_sysfs_ops,
|
||||
.release = release_nbp
|
||||
};
|
||||
|
||||
/*
|
||||
* Add sysfs entries to ethernet device added to a bridge.
|
||||
* Creates a brport subdirectory with bridge attributes.
|
||||
* Puts symlink in bridge's brport subdirectory
|
||||
*/
|
||||
int brc_sysfs_add_if(struct net_bridge_port *p)
|
||||
{
|
||||
struct datapath *dp = p->dp;
|
||||
struct brport_attribute **a;
|
||||
int err;
|
||||
|
||||
kobject_init(&p->kobj);
|
||||
kobject_set_name(&p->kobj, SYSFS_BRIDGE_PORT_ATTR);
|
||||
p->kobj.ktype = &brport_ktype;
|
||||
p->kobj.kset = NULL;
|
||||
p->kobj.parent = &(p->dev->class_dev.kobj);
|
||||
|
||||
err = kobject_add(&p->kobj);
|
||||
if (err)
|
||||
goto err_put;
|
||||
|
||||
err = sysfs_create_link(&p->kobj,
|
||||
&dp->ports[ODPP_LOCAL]->dev->class_dev.kobj,
|
||||
SYSFS_BRIDGE_PORT_LINK);
|
||||
if (err)
|
||||
goto err_del;
|
||||
|
||||
for (a = brport_attrs; *a; ++a) {
|
||||
err = sysfs_create_file(&p->kobj, &((*a)->attr));
|
||||
if (err)
|
||||
goto err_del;
|
||||
}
|
||||
|
||||
err = sysfs_create_link(&dp->ifobj, &p->kobj, p->dev->name);
|
||||
if (err)
|
||||
goto err_del;
|
||||
|
||||
kobject_uevent(&p->kobj, KOBJ_ADD);
|
||||
|
||||
return err;
|
||||
|
||||
err_del:
|
||||
kobject_del(&p->kobj);
|
||||
err_put:
|
||||
kobject_put(&p->kobj);
|
||||
return err;
|
||||
}
|
||||
|
||||
int brc_sysfs_del_if(struct net_bridge_port *p)
|
||||
{
|
||||
struct net_device *dev = p->dev;
|
||||
|
||||
kobject_uevent(&p->kobj, KOBJ_REMOVE);
|
||||
kobject_del(&p->kobj);
|
||||
|
||||
dev_put(dev);
|
||||
|
||||
kobject_put(&p->kobj);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* SUPPORT_SYSFS */
|
519
datapath/brcompat.c
Normal file
519
datapath/brcompat.c
Normal file
@ -0,0 +1,519 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/if_bridge.h>
|
||||
#include <linux/rculist.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <net/genetlink.h>
|
||||
|
||||
#include "compat.h"
|
||||
#include "openvswitch/brcompat-netlink.h"
|
||||
#include "brc_procfs.h"
|
||||
#include "brc_sysfs.h"
|
||||
#include "datapath.h"
|
||||
#include "dp_dev.h"
|
||||
|
||||
static struct genl_family brc_genl_family;
|
||||
static struct genl_multicast_group brc_mc_group;
|
||||
|
||||
/* Time to wait for ovs-vswitchd to respond to a datapath action, in
|
||||
* jiffies. */
|
||||
#define BRC_TIMEOUT (HZ * 5)
|
||||
|
||||
/* Mutex to serialize ovs-brcompatd callbacks. (Some callbacks naturally hold
|
||||
* br_ioctl_mutex, others hold rtnl_lock, but we can't take the former
|
||||
* ourselves and we don't want to hold the latter over a potentially long
|
||||
* period of time.) */
|
||||
static DEFINE_MUTEX(brc_serial);
|
||||
|
||||
/* Userspace communication. */
|
||||
static DEFINE_SPINLOCK(brc_lock); /* Ensure atomic access to these vars. */
|
||||
static DECLARE_COMPLETION(brc_done); /* Userspace signaled operation done? */
|
||||
static int brc_err; /* Error code from userspace. */
|
||||
static u32 brc_seq; /* Sequence number for current op. */
|
||||
|
||||
static int brc_send_command(const char *bridge, const char *port, int op);
|
||||
|
||||
static int
|
||||
get_dp_ifindices(int *indices, int num)
|
||||
{
|
||||
int i, index = 0;
|
||||
|
||||
rcu_read_lock();
|
||||
for (i=0; i < ODP_MAX && index < num; i++) {
|
||||
struct datapath *dp = get_dp(i);
|
||||
if (!dp)
|
||||
continue;
|
||||
indices[index++] = dp->ports[ODPP_LOCAL]->dev->ifindex;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
static void
|
||||
get_port_ifindices(struct datapath *dp, int *ifindices, int num)
|
||||
{
|
||||
struct net_bridge_port *p;
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu (p, &dp->port_list, node) {
|
||||
if (p->port_no < num)
|
||||
ifindices[p->port_no] = p->dev->ifindex;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static int brc_add_del_bridge(char __user *uname, int add)
|
||||
{
|
||||
char name[IFNAMSIZ];
|
||||
|
||||
if (copy_from_user(name, uname, IFNAMSIZ))
|
||||
return -EFAULT;
|
||||
|
||||
name[IFNAMSIZ - 1] = 0;
|
||||
return brc_send_command(name, NULL,
|
||||
add ? BRC_GENL_C_DP_ADD : BRC_GENL_C_DP_DEL);
|
||||
}
|
||||
|
||||
static int brc_get_bridges(int __user *uindices, int n)
|
||||
{
|
||||
int *indices;
|
||||
int ret;
|
||||
|
||||
if (n >= 2048)
|
||||
return -ENOMEM;
|
||||
|
||||
indices = kcalloc(n, sizeof(int), GFP_KERNEL);
|
||||
if (indices == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
n = get_dp_ifindices(indices, n);
|
||||
|
||||
ret = copy_to_user(uindices, indices, n * sizeof(int)) ? -EFAULT : n;
|
||||
|
||||
kfree(indices);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Legacy deviceless bridge ioctl's. Called with br_ioctl_mutex. */
|
||||
static int
|
||||
old_deviceless(void __user *uarg)
|
||||
{
|
||||
unsigned long args[3];
|
||||
|
||||
if (copy_from_user(args, uarg, sizeof(args)))
|
||||
return -EFAULT;
|
||||
|
||||
switch (args[0]) {
|
||||
case BRCTL_GET_BRIDGES:
|
||||
return brc_get_bridges((int __user *)args[1], args[2]);
|
||||
|
||||
case BRCTL_ADD_BRIDGE:
|
||||
return brc_add_del_bridge((void __user *)args[1], 1);
|
||||
case BRCTL_DEL_BRIDGE:
|
||||
return brc_add_del_bridge((void __user *)args[1], 0);
|
||||
}
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* Called with the br_ioctl_mutex. */
|
||||
static int
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23)
|
||||
brc_ioctl_deviceless_stub(unsigned int cmd, void __user *uarg)
|
||||
#else
|
||||
brc_ioctl_deviceless_stub(struct net *net, unsigned int cmd, void __user *uarg)
|
||||
#endif
|
||||
{
|
||||
switch (cmd) {
|
||||
case SIOCGIFBR:
|
||||
case SIOCSIFBR:
|
||||
return old_deviceless(uarg);
|
||||
|
||||
case SIOCBRADDBR:
|
||||
return brc_add_del_bridge(uarg, 1);
|
||||
case SIOCBRDELBR:
|
||||
return brc_add_del_bridge(uarg, 0);
|
||||
}
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int
|
||||
brc_add_del_port(struct net_device *dev, int port_ifindex, int add)
|
||||
{
|
||||
struct net_device *port;
|
||||
char dev_name[IFNAMSIZ], port_name[IFNAMSIZ];
|
||||
int err;
|
||||
|
||||
port = __dev_get_by_index(&init_net, port_ifindex);
|
||||
if (!port)
|
||||
return -EINVAL;
|
||||
|
||||
/* Save name of dev and port because there's a race between the
|
||||
* rtnl_unlock() and the brc_send_command(). */
|
||||
strcpy(dev_name, dev->name);
|
||||
strcpy(port_name, port->name);
|
||||
|
||||
rtnl_unlock();
|
||||
err = brc_send_command(dev_name, port_name,
|
||||
add ? BRC_GENL_C_PORT_ADD : BRC_GENL_C_PORT_DEL);
|
||||
rtnl_lock();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
brc_get_bridge_info(struct net_device *dev, struct __bridge_info __user *ub)
|
||||
{
|
||||
struct __bridge_info b;
|
||||
u64 id = 0;
|
||||
int i;
|
||||
|
||||
memset(&b, 0, sizeof(struct __bridge_info));
|
||||
|
||||
for (i=0; i<ETH_ALEN; i++)
|
||||
id |= (u64)dev->dev_addr[i] << (8*(ETH_ALEN-1 - i));
|
||||
b.bridge_id = cpu_to_be64(id);
|
||||
b.stp_enabled = 0;
|
||||
|
||||
if (copy_to_user(ub, &b, sizeof(struct __bridge_info)))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
brc_get_port_list(struct net_device *dev, int __user *uindices, int num)
|
||||
{
|
||||
struct dp_dev *dp_dev = netdev_priv(dev);
|
||||
struct datapath *dp = dp_dev->dp;
|
||||
int *indices;
|
||||
|
||||
if (num < 0)
|
||||
return -EINVAL;
|
||||
if (num == 0)
|
||||
num = 256;
|
||||
if (num > DP_MAX_PORTS)
|
||||
num = DP_MAX_PORTS;
|
||||
|
||||
indices = kcalloc(num, sizeof(int), GFP_KERNEL);
|
||||
if (indices == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
get_port_ifindices(dp, indices, num);
|
||||
if (copy_to_user(uindices, indices, num * sizeof(int)))
|
||||
num = -EFAULT;
|
||||
kfree(indices);
|
||||
return num;
|
||||
}
|
||||
|
||||
/* Legacy ioctl's through SIOCDEVPRIVATE. Called with rtnl_lock. */
|
||||
static int
|
||||
old_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
|
||||
{
|
||||
unsigned long args[4];
|
||||
|
||||
if (copy_from_user(args, rq->ifr_data, sizeof(args)))
|
||||
return -EFAULT;
|
||||
|
||||
switch (args[0]) {
|
||||
case BRCTL_ADD_IF:
|
||||
return brc_add_del_port(dev, args[1], 1);
|
||||
case BRCTL_DEL_IF:
|
||||
return brc_add_del_port(dev, args[1], 0);
|
||||
|
||||
case BRCTL_GET_BRIDGE_INFO:
|
||||
return brc_get_bridge_info(dev, (struct __bridge_info __user *)args[1]);
|
||||
|
||||
case BRCTL_GET_PORT_LIST:
|
||||
return brc_get_port_list(dev, (int __user *)args[1], args[2]);
|
||||
}
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* Called with the rtnl_lock. */
|
||||
static int
|
||||
brc_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
|
||||
{
|
||||
int err;
|
||||
|
||||
switch (cmd) {
|
||||
case SIOCDEVPRIVATE:
|
||||
err = old_dev_ioctl(dev, rq, cmd);
|
||||
break;
|
||||
|
||||
case SIOCBRADDIF:
|
||||
return brc_add_del_port(dev, rq->ifr_ifindex, 1);
|
||||
case SIOCBRDELIF:
|
||||
return brc_add_del_port(dev, rq->ifr_ifindex, 0);
|
||||
|
||||
default:
|
||||
err = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static struct genl_family brc_genl_family = {
|
||||
.id = GENL_ID_GENERATE,
|
||||
.hdrsize = 0,
|
||||
.name = BRC_GENL_FAMILY_NAME,
|
||||
.version = 1,
|
||||
.maxattr = BRC_GENL_A_MAX,
|
||||
};
|
||||
|
||||
static int brc_genl_query(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
int err = -EINVAL;
|
||||
struct sk_buff *ans_skb;
|
||||
void *data;
|
||||
|
||||
ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
||||
if (!ans_skb)
|
||||
return -ENOMEM;
|
||||
|
||||
data = genlmsg_put_reply(ans_skb, info, &brc_genl_family,
|
||||
0, BRC_GENL_C_QUERY_MC);
|
||||
if (data == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
NLA_PUT_U32(ans_skb, BRC_GENL_A_MC_GROUP, brc_mc_group.id);
|
||||
|
||||
genlmsg_end(ans_skb, data);
|
||||
return genlmsg_reply(ans_skb, info);
|
||||
|
||||
err:
|
||||
nla_put_failure:
|
||||
kfree_skb(ans_skb);
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct genl_ops brc_genl_ops_query_dp = {
|
||||
.cmd = BRC_GENL_C_QUERY_MC,
|
||||
.flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privelege. */
|
||||
.policy = NULL,
|
||||
.doit = brc_genl_query,
|
||||
.dumpit = NULL
|
||||
};
|
||||
|
||||
/* Attribute policy: what each attribute may contain. */
|
||||
static struct nla_policy brc_genl_policy[BRC_GENL_A_MAX + 1] = {
|
||||
[BRC_GENL_A_ERR_CODE] = { .type = NLA_U32 },
|
||||
[BRC_GENL_A_PROC_DIR] = { .type = NLA_NUL_STRING },
|
||||
[BRC_GENL_A_PROC_NAME] = { .type = NLA_NUL_STRING },
|
||||
[BRC_GENL_A_PROC_DATA] = { .type = NLA_NUL_STRING },
|
||||
};
|
||||
|
||||
static int
|
||||
brc_genl_dp_result(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
unsigned long int flags;
|
||||
int err;
|
||||
|
||||
if (!info->attrs[BRC_GENL_A_ERR_CODE])
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&brc_lock, flags);
|
||||
if (brc_seq == info->snd_seq) {
|
||||
brc_err = nla_get_u32(info->attrs[BRC_GENL_A_ERR_CODE]);
|
||||
complete(&brc_done);
|
||||
err = 0;
|
||||
} else {
|
||||
err = -ESTALE;
|
||||
}
|
||||
spin_unlock_irqrestore(&brc_lock, flags);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct genl_ops brc_genl_ops_dp_result = {
|
||||
.cmd = BRC_GENL_C_DP_RESULT,
|
||||
.flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privelege. */
|
||||
.policy = brc_genl_policy,
|
||||
.doit = brc_genl_dp_result,
|
||||
.dumpit = NULL
|
||||
};
|
||||
|
||||
static struct genl_ops brc_genl_ops_set_proc = {
|
||||
.cmd = BRC_GENL_C_SET_PROC,
|
||||
.flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privelege. */
|
||||
.policy = brc_genl_policy,
|
||||
.doit = brc_genl_set_proc,
|
||||
.dumpit = NULL
|
||||
};
|
||||
|
||||
static int brc_send_command(const char *bridge, const char *port, int op)
|
||||
{
|
||||
unsigned long int flags;
|
||||
struct sk_buff *skb;
|
||||
void *data;
|
||||
int error;
|
||||
|
||||
mutex_lock(&brc_serial);
|
||||
|
||||
/* Increment sequence number first, so that we ignore any replies
|
||||
* to stale requests. */
|
||||
spin_lock_irqsave(&brc_lock, flags);
|
||||
brc_seq++;
|
||||
INIT_COMPLETION(brc_done);
|
||||
spin_unlock_irqrestore(&brc_lock, flags);
|
||||
|
||||
/* Compose message. */
|
||||
skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
|
||||
error = -ENOMEM;
|
||||
if (skb == NULL)
|
||||
goto exit_unlock;
|
||||
data = genlmsg_put(skb, 0, brc_seq, &brc_genl_family, 0, op);
|
||||
|
||||
NLA_PUT_STRING(skb, BRC_GENL_A_DP_NAME, bridge);
|
||||
if (port)
|
||||
NLA_PUT_STRING(skb, BRC_GENL_A_PORT_NAME, port);
|
||||
|
||||
genlmsg_end(skb, data);
|
||||
|
||||
/* Send message. */
|
||||
error = genlmsg_multicast(skb, 0, brc_mc_group.id, GFP_KERNEL);
|
||||
if (error < 0)
|
||||
goto exit_unlock;
|
||||
|
||||
/* Wait for reply. */
|
||||
error = -ETIMEDOUT;
|
||||
if (!wait_for_completion_timeout(&brc_done, BRC_TIMEOUT))
|
||||
goto exit_unlock;
|
||||
|
||||
error = -brc_err;
|
||||
goto exit_unlock;
|
||||
|
||||
nla_put_failure:
|
||||
kfree_skb(skb);
|
||||
exit_unlock:
|
||||
mutex_unlock(&brc_serial);
|
||||
return error;
|
||||
}
|
||||
|
||||
int brc_add_dp(struct datapath *dp)
|
||||
{
|
||||
if (!try_module_get(THIS_MODULE))
|
||||
return -ENODEV;
|
||||
#ifdef SUPPORT_SYSFS
|
||||
brc_sysfs_add_dp(dp);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int brc_del_dp(struct datapath *dp)
|
||||
{
|
||||
#ifdef SUPPORT_SYSFS
|
||||
brc_sysfs_del_dp(dp);
|
||||
#endif
|
||||
module_put(THIS_MODULE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
__init brc_init(void)
|
||||
{
|
||||
int i;
|
||||
int err;
|
||||
|
||||
printk("Open vSwitch Bridge Compatibility, built "__DATE__" "__TIME__"\n");
|
||||
|
||||
rcu_read_lock();
|
||||
for (i=0; i<ODP_MAX; i++) {
|
||||
if (get_dp(i)) {
|
||||
rcu_read_unlock();
|
||||
printk(KERN_EMERG "brcompat: no datapaths may exist!\n");
|
||||
return -EEXIST;
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
/* Set the bridge ioctl handler */
|
||||
brioctl_set(brc_ioctl_deviceless_stub);
|
||||
|
||||
/* Set the openvswitch_mod device ioctl handler */
|
||||
dp_ioctl_hook = brc_dev_ioctl;
|
||||
|
||||
/* Register hooks for datapath adds and deletes */
|
||||
dp_add_dp_hook = brc_add_dp;
|
||||
dp_del_dp_hook = brc_del_dp;
|
||||
|
||||
/* Register hooks for interface adds and deletes */
|
||||
#ifdef SUPPORT_SYSFS
|
||||
dp_add_if_hook = brc_sysfs_add_if;
|
||||
dp_del_if_hook = brc_sysfs_del_if;
|
||||
#endif
|
||||
|
||||
/* Randomize the initial sequence number. This is not a security
|
||||
* feature; it only helps avoid crossed wires between userspace and
|
||||
* the kernel when the module is unloaded and reloaded. */
|
||||
brc_seq = net_random();
|
||||
|
||||
/* Register generic netlink family to communicate changes to
|
||||
* userspace. */
|
||||
err = genl_register_family(&brc_genl_family);
|
||||
if (err)
|
||||
goto error;
|
||||
|
||||
err = genl_register_ops(&brc_genl_family, &brc_genl_ops_query_dp);
|
||||
if (err != 0)
|
||||
goto err_unregister;
|
||||
|
||||
err = genl_register_ops(&brc_genl_family, &brc_genl_ops_dp_result);
|
||||
if (err != 0)
|
||||
goto err_unregister;
|
||||
|
||||
err = genl_register_ops(&brc_genl_family, &brc_genl_ops_set_proc);
|
||||
if (err != 0)
|
||||
goto err_unregister;
|
||||
|
||||
strcpy(brc_mc_group.name, "brcompat");
|
||||
err = genl_register_mc_group(&brc_genl_family, &brc_mc_group);
|
||||
if (err < 0)
|
||||
goto err_unregister;
|
||||
|
||||
return 0;
|
||||
|
||||
err_unregister:
|
||||
genl_unregister_family(&brc_genl_family);
|
||||
error:
|
||||
printk(KERN_EMERG "brcompat: failed to install!");
|
||||
return err;
|
||||
}
|
||||
|
||||
static void
|
||||
brc_cleanup(void)
|
||||
{
|
||||
/* Unregister hooks for datapath adds and deletes */
|
||||
dp_add_dp_hook = NULL;
|
||||
dp_del_dp_hook = NULL;
|
||||
|
||||
/* Unregister hooks for interface adds and deletes */
|
||||
dp_add_if_hook = NULL;
|
||||
dp_del_if_hook = NULL;
|
||||
|
||||
/* Unregister ioctl hooks */
|
||||
dp_ioctl_hook = NULL;
|
||||
brioctl_set(NULL);
|
||||
|
||||
genl_unregister_family(&brc_genl_family);
|
||||
brc_procfs_exit();
|
||||
}
|
||||
|
||||
module_init(brc_init);
|
||||
module_exit(brc_cleanup);
|
||||
|
||||
MODULE_DESCRIPTION("Open vSwitch bridge compatibility");
|
||||
MODULE_AUTHOR("Nicira Networks");
|
||||
MODULE_LICENSE("GPL");
|
17
datapath/compat.h
Normal file
17
datapath/compat.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef COMPAT_H
|
||||
#define COMPAT_H 1
|
||||
|
||||
#include <linux/version.h>
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
|
||||
|
||||
#include "compat26.h"
|
||||
|
||||
#else
|
||||
|
||||
#include "compat24.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* compat.h */
|
1611
datapath/datapath.c
Normal file
1611
datapath/datapath.c
Normal file
File diff suppressed because it is too large
Load Diff
139
datapath/datapath.h
Normal file
139
datapath/datapath.h
Normal file
@ -0,0 +1,139 @@
|
||||
/* Interface exported by openvswitch_mod. */
|
||||
|
||||
#ifndef DATAPATH_H
|
||||
#define DATAPATH_H 1
|
||||
|
||||
#include <asm/page.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include "flow.h"
|
||||
#include "brc_sysfs.h"
|
||||
|
||||
struct sk_buff;
|
||||
|
||||
/* Mask for the priority bits in a vlan header. If we ever merge upstream
|
||||
* then this should go into include/linux/if_vlan.h. */
|
||||
#define VLAN_PCP_MASK 0xe000
|
||||
|
||||
#define DP_MAX_PORTS 256
|
||||
#define DP_MAX_GROUPS 16
|
||||
|
||||
#define DP_L2_BITS (PAGE_SHIFT - ilog2(sizeof(struct sw_flow*)))
|
||||
#define DP_L2_SIZE (1 << DP_L2_BITS)
|
||||
#define DP_L2_SHIFT 0
|
||||
|
||||
#define DP_L1_BITS (PAGE_SHIFT - ilog2(sizeof(struct sw_flow**)))
|
||||
#define DP_L1_SIZE (1 << DP_L1_BITS)
|
||||
#define DP_L1_SHIFT DP_L2_BITS
|
||||
|
||||
#define DP_MAX_BUCKETS (DP_L1_SIZE * DP_L2_SIZE)
|
||||
|
||||
struct dp_table {
|
||||
unsigned int n_buckets;
|
||||
struct sw_flow ***flows[2];
|
||||
struct rcu_head rcu;
|
||||
};
|
||||
|
||||
#define DP_N_QUEUES 2
|
||||
#define DP_MAX_QUEUE_LEN 100
|
||||
|
||||
struct dp_stats_percpu {
|
||||
u64 n_frags;
|
||||
u64 n_hit;
|
||||
u64 n_missed;
|
||||
u64 n_lost;
|
||||
};
|
||||
|
||||
struct dp_port_group {
|
||||
struct rcu_head rcu;
|
||||
int n_ports;
|
||||
u16 ports[];
|
||||
};
|
||||
|
||||
struct datapath {
|
||||
struct mutex mutex;
|
||||
int dp_idx;
|
||||
|
||||
#ifdef SUPPORT_SYSFS
|
||||
struct kobject ifobj;
|
||||
#endif
|
||||
|
||||
int drop_frags;
|
||||
|
||||
/* Queued data. */
|
||||
struct sk_buff_head queues[DP_N_QUEUES];
|
||||
wait_queue_head_t waitqueue;
|
||||
|
||||
/* Flow table. */
|
||||
unsigned int n_flows;
|
||||
struct dp_table *table;
|
||||
|
||||
/* Port groups. */
|
||||
struct dp_port_group *groups[DP_MAX_GROUPS];
|
||||
|
||||
/* Switch ports. */
|
||||
unsigned int n_ports;
|
||||
struct net_bridge_port *ports[DP_MAX_PORTS];
|
||||
struct list_head port_list; /* All ports, including local_port. */
|
||||
|
||||
/* Stats. */
|
||||
struct dp_stats_percpu *stats_percpu;
|
||||
};
|
||||
|
||||
struct net_bridge_port {
|
||||
u16 port_no;
|
||||
struct datapath *dp;
|
||||
struct net_device *dev;
|
||||
#ifdef SUPPORT_SYSFS
|
||||
struct kobject kobj;
|
||||
#endif
|
||||
struct list_head node; /* Element in datapath.ports. */
|
||||
};
|
||||
|
||||
extern struct notifier_block dp_device_notifier;
|
||||
extern int (*dp_ioctl_hook)(struct net_device *dev, struct ifreq *rq, int cmd);
|
||||
extern int (*dp_add_dp_hook)(struct datapath *dp);
|
||||
extern int (*dp_del_dp_hook)(struct datapath *dp);
|
||||
extern int (*dp_add_if_hook)(struct net_bridge_port *p);
|
||||
extern int (*dp_del_if_hook)(struct net_bridge_port *p);
|
||||
|
||||
/* Flow table. */
|
||||
struct dp_table *dp_table_create(unsigned int n_buckets);
|
||||
void dp_table_destroy(struct dp_table *, int free_flows);
|
||||
struct sw_flow *dp_table_lookup(struct dp_table *, const struct odp_flow_key *);
|
||||
struct sw_flow **dp_table_lookup_for_insert(struct dp_table *, const struct odp_flow_key *);
|
||||
int dp_table_delete(struct dp_table *, struct sw_flow *);
|
||||
int dp_table_expand(struct datapath *);
|
||||
int dp_table_flush(struct datapath *);
|
||||
int dp_table_foreach(struct dp_table *table,
|
||||
int (*callback)(struct sw_flow *flow, void *aux),
|
||||
void *aux);
|
||||
|
||||
void dp_process_received_packet(struct sk_buff *, struct net_bridge_port *);
|
||||
int dp_del_port(struct net_bridge_port *, struct list_head *);
|
||||
int dp_output_port(struct datapath *, struct sk_buff *, int out_port,
|
||||
int ignore_no_fwd);
|
||||
int dp_output_control(struct datapath *, struct sk_buff *, int, u32 arg);
|
||||
void dp_set_origin(struct datapath *, u16, struct sk_buff *);
|
||||
|
||||
struct datapath *get_dp(int dp_idx);
|
||||
|
||||
static inline const char *dp_name(const struct datapath *dp)
|
||||
{
|
||||
return dp->ports[ODPP_LOCAL]->dev->name;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_XEN
|
||||
int skb_checksum_setup(struct sk_buff *skb);
|
||||
#else
|
||||
static inline int skb_checksum_setup(struct sk_buff *skb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* datapath.h */
|
210
datapath/dp_dev.c
Normal file
210
datapath/dp_dev.c
Normal file
@ -0,0 +1,210 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include "datapath.h"
|
||||
#include "dp_dev.h"
|
||||
|
||||
struct datapath *dp_dev_get_dp(struct net_device *netdev)
|
||||
{
|
||||
return dp_dev_priv(netdev)->dp;
|
||||
}
|
||||
EXPORT_SYMBOL(dp_dev_get_dp);
|
||||
|
||||
static struct net_device_stats *dp_dev_get_stats(struct net_device *netdev)
|
||||
{
|
||||
struct dp_dev *dp_dev = dp_dev_priv(netdev);
|
||||
return &dp_dev->stats;
|
||||
}
|
||||
|
||||
int dp_dev_recv(struct net_device *netdev, struct sk_buff *skb)
|
||||
{
|
||||
struct dp_dev *dp_dev = dp_dev_priv(netdev);
|
||||
int len;
|
||||
len = skb->len;
|
||||
skb->pkt_type = PACKET_HOST;
|
||||
skb->protocol = eth_type_trans(skb, netdev);
|
||||
if (in_interrupt())
|
||||
netif_rx(skb);
|
||||
else
|
||||
netif_rx_ni(skb);
|
||||
netdev->last_rx = jiffies;
|
||||
dp_dev->stats.rx_packets++;
|
||||
dp_dev->stats.rx_bytes += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
static int dp_dev_mac_addr(struct net_device *dev, void *p)
|
||||
{
|
||||
struct sockaddr *addr = p;
|
||||
|
||||
if (!is_valid_ether_addr(addr->sa_data))
|
||||
return -EADDRNOTAVAIL;
|
||||
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dp_dev_xmit(struct sk_buff *skb, struct net_device *netdev)
|
||||
{
|
||||
struct dp_dev *dp_dev = dp_dev_priv(netdev);
|
||||
|
||||
/* By orphaning 'skb' we will screw up socket accounting slightly, but
|
||||
* the effect is limited to the device queue length. If we don't
|
||||
* do this, then the sk_buff will be destructed eventually, but it is
|
||||
* harder to predict when. */
|
||||
skb_orphan(skb);
|
||||
|
||||
/* We are going to modify 'skb', by sticking it on &dp_dev->xmit_queue,
|
||||
* so we need to have our own clone. (At any rate, fwd_port_input()
|
||||
* will need its own clone, so there's no benefit to queuing any other
|
||||
* way.) */
|
||||
skb = skb_share_check(skb, GFP_ATOMIC);
|
||||
if (!skb)
|
||||
return 0;
|
||||
|
||||
dp_dev->stats.tx_packets++;
|
||||
dp_dev->stats.tx_bytes += skb->len;
|
||||
|
||||
if (skb_queue_len(&dp_dev->xmit_queue) >= netdev->tx_queue_len) {
|
||||
/* Queue overflow. Stop transmitter. */
|
||||
netif_stop_queue(netdev);
|
||||
|
||||
/* We won't see all dropped packets individually, so overrun
|
||||
* error is appropriate. */
|
||||
dp_dev->stats.tx_fifo_errors++;
|
||||
}
|
||||
skb_queue_tail(&dp_dev->xmit_queue, skb);
|
||||
netdev->trans_start = jiffies;
|
||||
|
||||
schedule_work(&dp_dev->xmit_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dp_dev_do_xmit(struct work_struct *work)
|
||||
{
|
||||
struct dp_dev *dp_dev = container_of(work, struct dp_dev, xmit_work);
|
||||
struct datapath *dp = dp_dev->dp;
|
||||
struct sk_buff *skb;
|
||||
|
||||
while ((skb = skb_dequeue(&dp_dev->xmit_queue)) != NULL) {
|
||||
skb_reset_mac_header(skb);
|
||||
rcu_read_lock_bh();
|
||||
dp_process_received_packet(skb, dp->ports[dp_dev->port_no]);
|
||||
rcu_read_unlock_bh();
|
||||
}
|
||||
netif_wake_queue(dp_dev->dev);
|
||||
}
|
||||
|
||||
static int dp_dev_open(struct net_device *netdev)
|
||||
{
|
||||
netif_start_queue(netdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dp_dev_stop(struct net_device *netdev)
|
||||
{
|
||||
netif_stop_queue(netdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dp_getinfo(struct net_device *netdev, struct ethtool_drvinfo *info)
|
||||
{
|
||||
struct dp_dev *dp_dev = dp_dev_priv(netdev);
|
||||
strcpy(info->driver, "openvswitch");
|
||||
sprintf(info->bus_info, "%d", dp_dev->dp->dp_idx);
|
||||
}
|
||||
|
||||
static struct ethtool_ops dp_ethtool_ops = {
|
||||
.get_drvinfo = dp_getinfo,
|
||||
.get_link = ethtool_op_get_link,
|
||||
.get_sg = ethtool_op_get_sg,
|
||||
.get_tx_csum = ethtool_op_get_tx_csum,
|
||||
.get_tso = ethtool_op_get_tso,
|
||||
};
|
||||
|
||||
static void
|
||||
do_setup(struct net_device *netdev)
|
||||
{
|
||||
ether_setup(netdev);
|
||||
|
||||
netdev->do_ioctl = dp_ioctl_hook;
|
||||
netdev->get_stats = dp_dev_get_stats;
|
||||
netdev->hard_start_xmit = dp_dev_xmit;
|
||||
netdev->open = dp_dev_open;
|
||||
SET_ETHTOOL_OPS(netdev, &dp_ethtool_ops);
|
||||
netdev->stop = dp_dev_stop;
|
||||
netdev->tx_queue_len = 100;
|
||||
netdev->set_mac_address = dp_dev_mac_addr;
|
||||
|
||||
netdev->flags = IFF_BROADCAST | IFF_MULTICAST;
|
||||
|
||||
random_ether_addr(netdev->dev_addr);
|
||||
|
||||
/* Set the OUI to the Nicira one. */
|
||||
netdev->dev_addr[0] = 0x00;
|
||||
netdev->dev_addr[1] = 0x23;
|
||||
netdev->dev_addr[2] = 0x20;
|
||||
|
||||
/* Set the top bits to indicate random Nicira address. */
|
||||
netdev->dev_addr[3] |= 0xc0;
|
||||
}
|
||||
|
||||
/* Create a datapath device associated with 'dp'. If 'dp_name' is null,
|
||||
* the device name will be of the form 'of<dp_idx>'. Returns the new device or
|
||||
* an error code.
|
||||
*
|
||||
* Called with RTNL lock and dp_mutex. */
|
||||
struct net_device *dp_dev_create(struct datapath *dp, const char *dp_name, int port_no)
|
||||
{
|
||||
struct dp_dev *dp_dev;
|
||||
struct net_device *netdev;
|
||||
char dev_name[IFNAMSIZ];
|
||||
int err;
|
||||
|
||||
if (dp_name) {
|
||||
if (strlen(dp_name) >= IFNAMSIZ)
|
||||
return ERR_PTR(-EINVAL);
|
||||
strncpy(dev_name, dp_name, sizeof(dev_name));
|
||||
} else
|
||||
snprintf(dev_name, sizeof dev_name, "of%d", dp->dp_idx);
|
||||
|
||||
netdev = alloc_netdev(sizeof(struct dp_dev), dev_name, do_setup);
|
||||
if (!netdev)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
err = register_netdevice(netdev);
|
||||
if (err) {
|
||||
free_netdev(netdev);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
dp_dev = dp_dev_priv(netdev);
|
||||
dp_dev->dp = dp;
|
||||
dp_dev->port_no = port_no;
|
||||
dp_dev->dev = netdev;
|
||||
skb_queue_head_init(&dp_dev->xmit_queue);
|
||||
INIT_WORK(&dp_dev->xmit_work, dp_dev_do_xmit);
|
||||
return netdev;
|
||||
}
|
||||
|
||||
/* Called with RTNL lock and dp_mutex.*/
|
||||
void dp_dev_destroy(struct net_device *netdev)
|
||||
{
|
||||
struct dp_dev *dp_dev = dp_dev_priv(netdev);
|
||||
|
||||
netif_tx_disable(netdev);
|
||||
synchronize_net();
|
||||
skb_queue_purge(&dp_dev->xmit_queue);
|
||||
unregister_netdevice(netdev);
|
||||
}
|
||||
|
||||
int is_dp_dev(struct net_device *netdev)
|
||||
{
|
||||
return netdev->open == dp_dev_open;
|
||||
}
|
||||
EXPORT_SYMBOL(is_dp_dev);
|
27
datapath/dp_dev.h
Normal file
27
datapath/dp_dev.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef DP_DEV_H
|
||||
#define DP_DEV_H 1
|
||||
|
||||
struct dp_dev {
|
||||
struct datapath *dp;
|
||||
int port_no;
|
||||
|
||||
struct net_device *dev;
|
||||
struct net_device_stats stats;
|
||||
struct sk_buff_head xmit_queue;
|
||||
struct work_struct xmit_work;
|
||||
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
static inline struct dp_dev *dp_dev_priv(struct net_device *netdev)
|
||||
{
|
||||
return netdev_priv(netdev);
|
||||
}
|
||||
|
||||
struct net_device *dp_dev_create(struct datapath *, const char *, int port_no);
|
||||
void dp_dev_destroy(struct net_device *);
|
||||
int dp_dev_recv(struct net_device *, struct sk_buff *);
|
||||
int is_dp_dev(struct net_device *);
|
||||
struct datapath *dp_dev_get_dp(struct net_device *);
|
||||
|
||||
#endif /* dp_dev.h */
|
29
datapath/dp_notify.c
Normal file
29
datapath/dp_notify.c
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Distributed under the terms of the GNU GPL version 2.
|
||||
* Copyright (c) 2007, 2008, 2009 Nicira Networks.
|
||||
*/
|
||||
|
||||
/* Handle changes to managed devices */
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
#include "datapath.h"
|
||||
|
||||
|
||||
static int dp_device_event(struct notifier_block *unused, unsigned long event,
|
||||
void *ptr)
|
||||
{
|
||||
struct net_device *dev = ptr;
|
||||
struct net_bridge_port *p = dev->br_port;
|
||||
if (event == NETDEV_UNREGISTER && p) {
|
||||
struct datapath *dp = p->dp;
|
||||
mutex_lock(&dp->mutex);
|
||||
dp_del_port(p, NULL);
|
||||
mutex_unlock(&dp->mutex);
|
||||
}
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
struct notifier_block dp_device_notifier = {
|
||||
.notifier_call = dp_device_event
|
||||
};
|
301
datapath/flow.c
Normal file
301
datapath/flow.c
Normal file
@ -0,0 +1,301 @@
|
||||
/*
|
||||
* Distributed under the terms of the GNU GPL version 2.
|
||||
* Copyright (c) 2007, 2008, 2009 Nicira Networks.
|
||||
*/
|
||||
|
||||
#include "flow.h"
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/if_vlan.h>
|
||||
#include <net/llc_pdu.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/llc.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/udp.h>
|
||||
#include <linux/icmp.h>
|
||||
#include <net/ip.h>
|
||||
|
||||
#include "compat.h"
|
||||
|
||||
struct kmem_cache *flow_cache;
|
||||
|
||||
static inline int iphdr_ok(struct sk_buff *skb)
|
||||
{
|
||||
int nh_ofs = skb_network_offset(skb);
|
||||
if (skb->len >= nh_ofs + sizeof(struct iphdr)) {
|
||||
int ip_len = ip_hdrlen(skb);
|
||||
return (ip_len >= sizeof(struct iphdr)
|
||||
&& pskb_may_pull(skb, nh_ofs + ip_len));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int tcphdr_ok(struct sk_buff *skb)
|
||||
{
|
||||
int th_ofs = skb_transport_offset(skb);
|
||||
if (pskb_may_pull(skb, th_ofs + sizeof(struct tcphdr))) {
|
||||
int tcp_len = tcp_hdrlen(skb);
|
||||
return (tcp_len >= sizeof(struct tcphdr)
|
||||
&& skb->len >= th_ofs + tcp_len);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int udphdr_ok(struct sk_buff *skb)
|
||||
{
|
||||
int th_ofs = skb_transport_offset(skb);
|
||||
return pskb_may_pull(skb, th_ofs + sizeof(struct udphdr));
|
||||
}
|
||||
|
||||
static inline int icmphdr_ok(struct sk_buff *skb)
|
||||
{
|
||||
int th_ofs = skb_transport_offset(skb);
|
||||
return pskb_may_pull(skb, th_ofs + sizeof(struct icmphdr));
|
||||
}
|
||||
|
||||
#define TCP_FLAGS_OFFSET 13
|
||||
#define TCP_FLAG_MASK 0x3f
|
||||
|
||||
static inline struct ovs_tcphdr *ovs_tcp_hdr(const struct sk_buff *skb)
|
||||
{
|
||||
return (struct ovs_tcphdr *)skb_transport_header(skb);
|
||||
}
|
||||
|
||||
void flow_used(struct sw_flow *flow, struct sk_buff *skb)
|
||||
{
|
||||
unsigned long flags;
|
||||
u8 tcp_flags = 0;
|
||||
|
||||
if (flow->key.dl_type == htons(ETH_P_IP) && iphdr_ok(skb)) {
|
||||
struct iphdr *nh = ip_hdr(skb);
|
||||
flow->ip_tos = nh->tos;
|
||||
if (flow->key.nw_proto == IPPROTO_TCP && tcphdr_ok(skb)) {
|
||||
u8 *tcp = (u8 *)tcp_hdr(skb);
|
||||
tcp_flags = *(tcp + TCP_FLAGS_OFFSET) & TCP_FLAG_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&flow->lock, flags);
|
||||
getnstimeofday(&flow->used);
|
||||
flow->packet_count++;
|
||||
flow->byte_count += skb->len;
|
||||
flow->tcp_flags |= tcp_flags;
|
||||
spin_unlock_irqrestore(&flow->lock, flags);
|
||||
}
|
||||
|
||||
struct sw_flow_actions *flow_actions_alloc(size_t n_actions)
|
||||
{
|
||||
struct sw_flow_actions *sfa;
|
||||
|
||||
if (n_actions > (PAGE_SIZE - sizeof *sfa) / sizeof(union odp_action))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
sfa = kmalloc(sizeof *sfa + n_actions * sizeof(union odp_action),
|
||||
GFP_KERNEL);
|
||||
if (!sfa)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
sfa->n_actions = n_actions;
|
||||
return sfa;
|
||||
}
|
||||
|
||||
|
||||
/* Frees 'flow' immediately. */
|
||||
void flow_free(struct sw_flow *flow)
|
||||
{
|
||||
if (unlikely(!flow))
|
||||
return;
|
||||
kfree(flow->sf_acts);
|
||||
kmem_cache_free(flow_cache, flow);
|
||||
}
|
||||
|
||||
/* RCU callback used by flow_deferred_free. */
|
||||
static void rcu_free_flow_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_free_flow_callback);
|
||||
}
|
||||
|
||||
/* RCU callback used by flow_deferred_free_acts. */
|
||||
static void rcu_free_acts_callback(struct rcu_head *rcu)
|
||||
{
|
||||
struct sw_flow_actions *sf_acts = container_of(rcu,
|
||||
struct sw_flow_actions, rcu);
|
||||
kfree(sf_acts);
|
||||
}
|
||||
|
||||
/* Schedules 'sf_acts' 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_acts(struct sw_flow_actions *sf_acts)
|
||||
{
|
||||
call_rcu(&sf_acts->rcu, rcu_free_acts_callback);
|
||||
}
|
||||
|
||||
#define SNAP_OUI_LEN 3
|
||||
|
||||
struct eth_snap_hdr
|
||||
{
|
||||
struct ethhdr eth;
|
||||
u8 dsap; /* Always 0xAA */
|
||||
u8 ssap; /* Always 0xAA */
|
||||
u8 ctrl;
|
||||
u8 oui[SNAP_OUI_LEN];
|
||||
u16 ethertype;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
static int is_snap(const struct eth_snap_hdr *esh)
|
||||
{
|
||||
return (esh->dsap == LLC_SAP_SNAP
|
||||
&& esh->ssap == LLC_SAP_SNAP
|
||||
&& !memcmp(esh->oui, "\0\0\0", 3));
|
||||
}
|
||||
|
||||
/* Parses the Ethernet frame in 'skb', which was received on 'in_port',
|
||||
* and initializes 'key' to match. Returns 1 if 'skb' contains an IP
|
||||
* fragment, 0 otherwise. */
|
||||
int flow_extract(struct sk_buff *skb, u16 in_port, struct odp_flow_key *key)
|
||||
{
|
||||
struct ethhdr *eth;
|
||||
struct eth_snap_hdr *esh;
|
||||
int retval = 0;
|
||||
int nh_ofs;
|
||||
|
||||
memset(key, 0, sizeof *key);
|
||||
key->dl_vlan = htons(ODP_VLAN_NONE);
|
||||
key->in_port = in_port;
|
||||
|
||||
if (skb->len < sizeof *eth)
|
||||
return 0;
|
||||
if (!pskb_may_pull(skb, skb->len >= 64 ? 64 : skb->len)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
skb_reset_mac_header(skb);
|
||||
eth = eth_hdr(skb);
|
||||
esh = (struct eth_snap_hdr *) eth;
|
||||
nh_ofs = sizeof *eth;
|
||||
if (likely(ntohs(eth->h_proto) >= ODP_DL_TYPE_ETH2_CUTOFF))
|
||||
key->dl_type = eth->h_proto;
|
||||
else if (skb->len >= sizeof *esh && is_snap(esh)) {
|
||||
key->dl_type = esh->ethertype;
|
||||
nh_ofs = sizeof *esh;
|
||||
} else {
|
||||
key->dl_type = htons(ODP_DL_TYPE_NOT_ETH_TYPE);
|
||||
if (skb->len >= nh_ofs + sizeof(struct llc_pdu_un)) {
|
||||
nh_ofs += sizeof(struct llc_pdu_un);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for a VLAN tag */
|
||||
if (key->dl_type == htons(ETH_P_8021Q) &&
|
||||
skb->len >= nh_ofs + sizeof(struct vlan_hdr)) {
|
||||
struct vlan_hdr *vh = (struct vlan_hdr*)(skb->data + nh_ofs);
|
||||
key->dl_type = vh->h_vlan_encapsulated_proto;
|
||||
key->dl_vlan = vh->h_vlan_TCI & htons(VLAN_VID_MASK);
|
||||
nh_ofs += sizeof(struct vlan_hdr);
|
||||
}
|
||||
memcpy(key->dl_src, eth->h_source, ETH_ALEN);
|
||||
memcpy(key->dl_dst, eth->h_dest, ETH_ALEN);
|
||||
skb_set_network_header(skb, nh_ofs);
|
||||
|
||||
/* Network layer. */
|
||||
if (key->dl_type == htons(ETH_P_IP) && iphdr_ok(skb)) {
|
||||
struct iphdr *nh = ip_hdr(skb);
|
||||
int th_ofs = nh_ofs + nh->ihl * 4;
|
||||
key->nw_src = nh->saddr;
|
||||
key->nw_dst = nh->daddr;
|
||||
key->nw_proto = nh->protocol;
|
||||
skb_set_transport_header(skb, th_ofs);
|
||||
|
||||
/* Transport layer. */
|
||||
if (!(nh->frag_off & htons(IP_MF | IP_OFFSET))) {
|
||||
if (key->nw_proto == IPPROTO_TCP) {
|
||||
if (tcphdr_ok(skb)) {
|
||||
struct tcphdr *tcp = tcp_hdr(skb);
|
||||
key->tp_src = tcp->source;
|
||||
key->tp_dst = tcp->dest;
|
||||
} else {
|
||||
/* Avoid tricking other code into
|
||||
* thinking that this packet has an L4
|
||||
* header. */
|
||||
key->nw_proto = 0;
|
||||
}
|
||||
} else if (key->nw_proto == IPPROTO_UDP) {
|
||||
if (udphdr_ok(skb)) {
|
||||
struct udphdr *udp = udp_hdr(skb);
|
||||
key->tp_src = udp->source;
|
||||
key->tp_dst = udp->dest;
|
||||
} else {
|
||||
/* Avoid tricking other code into
|
||||
* thinking that this packet has an L4
|
||||
* header. */
|
||||
key->nw_proto = 0;
|
||||
}
|
||||
} else if (key->nw_proto == IPPROTO_ICMP) {
|
||||
if (icmphdr_ok(skb)) {
|
||||
struct icmphdr *icmp = icmp_hdr(skb);
|
||||
/* The ICMP type and code fields use the 16-bit
|
||||
* transport port fields, so we need to store them
|
||||
* in 16-bit network byte order. */
|
||||
key->tp_src = htons(icmp->type);
|
||||
key->tp_dst = htons(icmp->code);
|
||||
} else {
|
||||
/* Avoid tricking other code into
|
||||
* thinking that this packet has an L4
|
||||
* header. */
|
||||
key->nw_proto = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
retval = 1;
|
||||
}
|
||||
} else {
|
||||
skb_reset_transport_header(skb);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
void print_flow(const struct odp_flow_key *key)
|
||||
{
|
||||
#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
|
||||
#define MAC_ARG(x) ((u8*)(x))[0],((u8*)(x))[1],((u8*)(x))[2],((u8*)(x))[3],((u8*)(x))[4],((u8*)(x))[5]
|
||||
printk("port%04x:vlan%d mac"MAC_FMT"->"MAC_FMT" "
|
||||
"type%04x proto%d ip%x->%x port%d->%d\n",
|
||||
key->in_port, ntohs(key->dl_vlan),
|
||||
MAC_ARG(key->dl_src), MAC_ARG(key->dl_dst),
|
||||
ntohs(key->dl_type), key->nw_proto,
|
||||
key->nw_src, key->nw_dst,
|
||||
ntohs(key->tp_src), ntohs(key->tp_dst));
|
||||
}
|
49
datapath/flow.h
Normal file
49
datapath/flow.h
Normal file
@ -0,0 +1,49 @@
|
||||
#ifndef FLOW_H
|
||||
#define FLOW_H 1
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/gfp.h>
|
||||
|
||||
#include "openvswitch/datapath-protocol.h"
|
||||
|
||||
struct sk_buff;
|
||||
|
||||
struct sw_flow_actions {
|
||||
struct rcu_head rcu;
|
||||
unsigned int n_actions;
|
||||
union odp_action actions[];
|
||||
};
|
||||
|
||||
struct sw_flow {
|
||||
struct rcu_head rcu;
|
||||
struct odp_flow_key key;
|
||||
struct sw_flow_actions *sf_acts;
|
||||
|
||||
struct timespec used; /* Last used time. */
|
||||
|
||||
u8 ip_tos; /* IP TOS value. */
|
||||
|
||||
spinlock_t lock; /* Lock for values below. */
|
||||
u64 packet_count; /* Number of packets matched. */
|
||||
u64 byte_count; /* Number of bytes matched. */
|
||||
u8 tcp_flags; /* Union of seen TCP flags. */
|
||||
};
|
||||
|
||||
extern struct kmem_cache *flow_cache;
|
||||
|
||||
struct sw_flow_actions *flow_actions_alloc(size_t n_actions);
|
||||
void flow_free(struct sw_flow *);
|
||||
void flow_deferred_free(struct sw_flow *);
|
||||
void flow_deferred_free_acts(struct sw_flow_actions *);
|
||||
int flow_extract(struct sk_buff *, u16 in_port, struct odp_flow_key *);
|
||||
void flow_used(struct sw_flow *, struct sk_buff *);
|
||||
|
||||
void print_flow(const struct odp_flow_key *);
|
||||
|
||||
int flow_init(void);
|
||||
void flow_exit(void);
|
||||
|
||||
#endif /* flow.h */
|
20
datapath/linux-2.6/.gitignore
vendored
Normal file
20
datapath/linux-2.6/.gitignore
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
/Kbuild
|
||||
/Makefile
|
||||
/Makefile.main
|
||||
/actions.c
|
||||
/brcompat.c
|
||||
/brc_sysfs_dp.c
|
||||
/brc_sysfs_if.c
|
||||
/datapath.c
|
||||
/dp_dev.c
|
||||
/dp_notify.c
|
||||
/flow.c
|
||||
/genetlink-brcompat.c
|
||||
/genetlink-openvswitch.c
|
||||
/kcompat.h
|
||||
/linux-2.6
|
||||
/modules.order
|
||||
/random32.c
|
||||
/table.c
|
||||
/tmp
|
||||
/veth.c
|
34
datapath/linux-2.6/Kbuild.in
Normal file
34
datapath/linux-2.6/Kbuild.in
Normal file
@ -0,0 +1,34 @@
|
||||
# -*- makefile -*-
|
||||
export builddir = @abs_builddir@
|
||||
export srcdir = @abs_srcdir@
|
||||
export top_srcdir = @abs_top_srcdir@
|
||||
export VERSION = @VERSION@
|
||||
export BUILDNR = @BUILDNR@
|
||||
|
||||
include $(srcdir)/../Modules.mk
|
||||
include $(srcdir)/Modules.mk
|
||||
|
||||
EXTRA_CFLAGS := -DVERSION=\"$(VERSION)\"
|
||||
EXTRA_CFLAGS += -I$(srcdir)/..
|
||||
EXTRA_CFLAGS += -I$(builddir)/..
|
||||
EXTRA_CFLAGS += -I$(top_srcdir)/include
|
||||
ifeq '$(BUILDNR)' '0'
|
||||
EXTRA_CFLAGS += -DBUILDNR=\"\"
|
||||
else
|
||||
EXTRA_CFLAGS += -DBUILDNR=\"+build$(BUILDNR)\"
|
||||
endif
|
||||
EXTRA_CFLAGS += -g
|
||||
EXTRA_CFLAGS += -include $(builddir)/kcompat.h
|
||||
|
||||
# These include directories have to go before -I$(KSRC)/include.
|
||||
# NOSTDINC_FLAGS just happens to be a variable that goes in the
|
||||
# right place, even though it's conceptually incorrect.
|
||||
NOSTDINC_FLAGS += -I$(srcdir)/compat-2.6 -I$(srcdir)/compat-2.6/include
|
||||
|
||||
obj-m := $(patsubst %,%_mod.o,$(build_modules))
|
||||
|
||||
define module_template
|
||||
$(1)_mod-y = $$(notdir $$(patsubst %.c,%.o,$($(1)_sources)))
|
||||
endef
|
||||
|
||||
$(foreach module,$(build_modules),$(eval $(call module_template,$(module))))
|
9
datapath/linux-2.6/Makefile.in
Normal file
9
datapath/linux-2.6/Makefile.in
Normal file
@ -0,0 +1,9 @@
|
||||
ifeq ($(KERNELRELEASE),)
|
||||
# We're being called directly by running make in this directory.
|
||||
include Makefile.main
|
||||
else
|
||||
# We're being included by the Linux kernel build system
|
||||
include Kbuild
|
||||
endif
|
||||
|
||||
|
82
datapath/linux-2.6/Makefile.main.in
Normal file
82
datapath/linux-2.6/Makefile.main.in
Normal file
@ -0,0 +1,82 @@
|
||||
# -*- makefile -*-
|
||||
export builddir = @abs_builddir@
|
||||
export srcdir = @abs_srcdir@
|
||||
export top_srcdir = @abs_top_srcdir@
|
||||
export KSRC = @KSRC26@
|
||||
export VERSION = @VERSION@
|
||||
export BUILD_VETH = @BUILD_VETH@
|
||||
|
||||
include $(srcdir)/../Modules.mk
|
||||
include $(srcdir)/Modules.mk
|
||||
|
||||
default: $(build_links)
|
||||
|
||||
$(foreach s,$(sort $(foreach m,$(build_modules),$($(m)_sources))), \
|
||||
$(eval $(notdir $(s)): ; ln -s $(srcdir)/../$(s) $@))
|
||||
|
||||
distclean: clean
|
||||
rm -f kcompat.h
|
||||
distdir: clean
|
||||
install:
|
||||
all: default
|
||||
check: all
|
||||
clean:
|
||||
rm -f *.o *.ko *_mod.* Module.symvers *.cmd kcompat.h.new
|
||||
for d in $(build_links); do if test -h $$d; then rm $$d; fi; done
|
||||
|
||||
ifneq ($(KSRC),)
|
||||
|
||||
ifeq (/lib/modules/$(shell uname -r)/source, $(KSRC))
|
||||
KOBJ := /lib/modules/$(shell uname -r)/build
|
||||
else
|
||||
KOBJ := $(KSRC)
|
||||
endif
|
||||
|
||||
ifneq ($(shell grep -c 'PATCHLEVEL = 6' $(KSRC)/Makefile),1)
|
||||
$(error Linux kernel source in $(KSRC) not 2.6)
|
||||
endif
|
||||
|
||||
VERSION_FILE := $(KOBJ)/include/linux/version.h
|
||||
ifeq (,$(wildcard $(VERSION_FILE)))
|
||||
$(error Linux kernel source not configured - missing version.h)
|
||||
endif
|
||||
|
||||
CONFIG_FILE := $(KSRC)/include/linux/autoconf.h
|
||||
ifeq (,$(wildcard $(CONFIG_FILE)))
|
||||
$(error Linux kernel source not configured - missing autoconf.h)
|
||||
endif
|
||||
|
||||
default:
|
||||
$(MAKE) -C $(KSRC) M=$(builddir) modules
|
||||
endif
|
||||
|
||||
# Much of the kernel build system in this file is derived from Intel's
|
||||
# e1000 distribution, with the following license:
|
||||
|
||||
################################################################################
|
||||
#
|
||||
# Intel PRO/1000 Linux driver
|
||||
# Copyright(c) 1999 - 2007, 2009 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
|
||||
#
|
||||
################################################################################
|
50
datapath/linux-2.6/Modules.mk
Normal file
50
datapath/linux-2.6/Modules.mk
Normal file
@ -0,0 +1,50 @@
|
||||
openvswitch_sources += \
|
||||
linux-2.6/compat-2.6/genetlink-openvswitch.c \
|
||||
linux-2.6/compat-2.6/random32.c
|
||||
openvswitch_headers += \
|
||||
linux-2.6/compat-2.6/compat26.h \
|
||||
linux-2.6/compat-2.6/include/asm-generic/bug.h \
|
||||
linux-2.6/compat-2.6/include/linux/dmi.h \
|
||||
linux-2.6/compat-2.6/include/linux/err.h \
|
||||
linux-2.6/compat-2.6/include/linux/icmp.h \
|
||||
linux-2.6/compat-2.6/include/linux/if_arp.h \
|
||||
linux-2.6/compat-2.6/include/linux/ip.h \
|
||||
linux-2.6/compat-2.6/include/linux/ipv6.h \
|
||||
linux-2.6/compat-2.6/include/linux/jiffies.h \
|
||||
linux-2.6/compat-2.6/include/linux/kernel.h \
|
||||
linux-2.6/compat-2.6/include/linux/log2.h \
|
||||
linux-2.6/compat-2.6/include/linux/lockdep.h \
|
||||
linux-2.6/compat-2.6/include/linux/mutex.h \
|
||||
linux-2.6/compat-2.6/include/linux/netdevice.h \
|
||||
linux-2.6/compat-2.6/include/linux/netfilter_bridge.h \
|
||||
linux-2.6/compat-2.6/include/linux/netfilter_ipv4.h \
|
||||
linux-2.6/compat-2.6/include/linux/netlink.h \
|
||||
linux-2.6/compat-2.6/include/linux/percpu.h \
|
||||
linux-2.6/compat-2.6/include/linux/random.h \
|
||||
linux-2.6/compat-2.6/include/linux/rculist.h \
|
||||
linux-2.6/compat-2.6/include/linux/rtnetlink.h \
|
||||
linux-2.6/compat-2.6/include/linux/skbuff.h \
|
||||
linux-2.6/compat-2.6/include/linux/tcp.h \
|
||||
linux-2.6/compat-2.6/include/linux/timer.h \
|
||||
linux-2.6/compat-2.6/include/linux/types.h \
|
||||
linux-2.6/compat-2.6/include/linux/udp.h \
|
||||
linux-2.6/compat-2.6/include/linux/workqueue.h \
|
||||
linux-2.6/compat-2.6/include/net/checksum.h \
|
||||
linux-2.6/compat-2.6/include/net/genetlink.h \
|
||||
linux-2.6/compat-2.6/include/net/netlink.h
|
||||
|
||||
both_modules += brcompat
|
||||
brcompat_sources = \
|
||||
linux-2.6/compat-2.6/genetlink-brcompat.c \
|
||||
brcompat.c \
|
||||
brc_procfs.c \
|
||||
brc_sysfs_dp.c \
|
||||
brc_sysfs_if.c
|
||||
brcompat_headers = \
|
||||
brc_procfs.h \
|
||||
brc_sysfs.h
|
||||
|
||||
dist_modules += veth
|
||||
build_modules += $(if $(BUILD_VETH),veth)
|
||||
veth_sources = linux-2.6/compat-2.6/veth.c
|
||||
veth_headers =
|
37
datapath/linux-2.6/compat-2.6/compat26.h
Normal file
37
datapath/linux-2.6/compat-2.6/compat26.h
Normal file
@ -0,0 +1,37 @@
|
||||
#ifndef __COMPAT26_H
|
||||
#define __COMPAT26_H 1
|
||||
|
||||
#include <linux/version.h>
|
||||
|
||||
#if defined(CONFIG_PREEMPT) && LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,21)
|
||||
#error "CONFIG_PREEMPT is broken with 2.6.x before 2.6.21--see commit 4498121ca3, \"[NET]: Handle disabled preemption in gfp_any()\""
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23)
|
||||
/*----------------------------------------------------------------------------
|
||||
* In 2.6.24, a namespace argument became required for dev_get_by_name. */
|
||||
|
||||
#define dev_get_by_name(net, name) \
|
||||
dev_get_by_name((name))
|
||||
|
||||
#define dev_get_by_index(net, ifindex) \
|
||||
dev_get_by_index((ifindex))
|
||||
|
||||
#define __dev_get_by_name(net, name) \
|
||||
__dev_get_by_name((name))
|
||||
|
||||
#define __dev_get_by_index(net, ifindex) \
|
||||
__dev_get_by_index((ifindex))
|
||||
|
||||
#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 */
|
20
datapath/linux-2.6/compat-2.6/genetlink-brcompat.c
Normal file
20
datapath/linux-2.6/compat-2.6/genetlink-brcompat.c
Normal file
@ -0,0 +1,20 @@
|
||||
#include "net/genetlink.h"
|
||||
|
||||
#include <linux/version.h>
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
|
||||
|
||||
/* We fix grp->id to 32 so that it doesn't collide with any of the multicast
|
||||
* groups selected by openvswitch_mod, which uses groups 16 through 31.
|
||||
* Collision isn't fatal--multicast listeners should check that the family is
|
||||
* the one that they want and discard others--but it wastes time and memory to
|
||||
* receive unwanted messages. */
|
||||
int genl_register_mc_group(struct genl_family *family,
|
||||
struct genl_multicast_group *grp)
|
||||
{
|
||||
grp->id = 32;
|
||||
grp->family = family;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* kernel < 2.6.23 */
|
22
datapath/linux-2.6/compat-2.6/genetlink-openvswitch.c
Normal file
22
datapath/linux-2.6/compat-2.6/genetlink-openvswitch.c
Normal file
@ -0,0 +1,22 @@
|
||||
#include "net/genetlink.h"
|
||||
|
||||
#include <linux/version.h>
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
|
||||
|
||||
/* We use multicast groups 16 through 31 to avoid colliding with the multicast
|
||||
* group selected by brcompat_mod, which uses groups 32. Collision isn't
|
||||
* fatal--multicast listeners should check that the family is the one that they
|
||||
* want and discard others--but it wastes time and memory to receive unwanted
|
||||
* messages. */
|
||||
int genl_register_mc_group(struct genl_family *family,
|
||||
struct genl_multicast_group *grp)
|
||||
{
|
||||
/* This code is called single-threaded. */
|
||||
static unsigned int next_id = 0;
|
||||
grp->id = next_id++ % 16 + 16;
|
||||
grp->family = family;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* kernel < 2.6.23 */
|
19
datapath/linux-2.6/compat-2.6/include/asm-generic/bug.h
Normal file
19
datapath/linux-2.6/compat-2.6/include/asm-generic/bug.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef __ASM_GENERIC_BUG_WRAPPER_H
|
||||
#define __ASM_GENERIC_BUG_WRAPPER_H
|
||||
|
||||
#include_next <asm-generic/bug.h>
|
||||
|
||||
#ifndef WARN_ON_ONCE
|
||||
#define WARN_ON_ONCE(condition) ({ \
|
||||
static int __warned; \
|
||||
int __ret_warn_once = !!(condition); \
|
||||
\
|
||||
if (unlikely(__ret_warn_once) && !__warned) { \
|
||||
WARN_ON(1); \
|
||||
__warned = 1; \
|
||||
} \
|
||||
unlikely(__ret_warn_once); \
|
||||
})
|
||||
#endif
|
||||
|
||||
#endif
|
11
datapath/linux-2.6/compat-2.6/include/linux/cpumask.h
Normal file
11
datapath/linux-2.6/compat-2.6/include/linux/cpumask.h
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef __LINUX_CPUMASK_WRAPPER_H
|
||||
#define __LINUX_CPUMASK_WRAPPER_H
|
||||
|
||||
#include_next <linux/cpumask.h>
|
||||
|
||||
/* for_each_cpu was renamed for_each_possible_cpu in 2.6.18. */
|
||||
#ifndef for_each_possible_cpu
|
||||
#define for_each_possible_cpu for_each_cpu
|
||||
#endif
|
||||
|
||||
#endif /* linux/cpumask.h wrapper */
|
114
datapath/linux-2.6/compat-2.6/include/linux/dmi.h
Normal file
114
datapath/linux-2.6/compat-2.6/include/linux/dmi.h
Normal file
@ -0,0 +1,114 @@
|
||||
#ifndef __LINUX_DMI_WRAPPER_H
|
||||
#define __LINUX_DMI_WRAPPER_H 1
|
||||
|
||||
#include <linux/version.h>
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
|
||||
|
||||
#include_next <linux/dmi.h>
|
||||
|
||||
#else /* linux version >= 2.6.23 */
|
||||
|
||||
#ifndef __DMI_H__
|
||||
#define __DMI_H__
|
||||
|
||||
#include <linux/list.h>
|
||||
|
||||
enum dmi_field {
|
||||
DMI_NONE,
|
||||
DMI_BIOS_VENDOR,
|
||||
DMI_BIOS_VERSION,
|
||||
DMI_BIOS_DATE,
|
||||
DMI_SYS_VENDOR,
|
||||
DMI_PRODUCT_NAME,
|
||||
DMI_PRODUCT_VERSION,
|
||||
DMI_PRODUCT_SERIAL,
|
||||
DMI_PRODUCT_UUID,
|
||||
DMI_BOARD_VENDOR,
|
||||
DMI_BOARD_NAME,
|
||||
DMI_BOARD_VERSION,
|
||||
DMI_BOARD_SERIAL,
|
||||
DMI_BOARD_ASSET_TAG,
|
||||
DMI_CHASSIS_VENDOR,
|
||||
DMI_CHASSIS_TYPE,
|
||||
DMI_CHASSIS_VERSION,
|
||||
DMI_CHASSIS_SERIAL,
|
||||
DMI_CHASSIS_ASSET_TAG,
|
||||
DMI_STRING_MAX,
|
||||
};
|
||||
|
||||
enum dmi_device_type {
|
||||
DMI_DEV_TYPE_ANY = 0,
|
||||
DMI_DEV_TYPE_OTHER,
|
||||
DMI_DEV_TYPE_UNKNOWN,
|
||||
DMI_DEV_TYPE_VIDEO,
|
||||
DMI_DEV_TYPE_SCSI,
|
||||
DMI_DEV_TYPE_ETHERNET,
|
||||
DMI_DEV_TYPE_TOKENRING,
|
||||
DMI_DEV_TYPE_SOUND,
|
||||
DMI_DEV_TYPE_IPMI = -1,
|
||||
DMI_DEV_TYPE_OEM_STRING = -2
|
||||
};
|
||||
|
||||
struct dmi_header {
|
||||
u8 type;
|
||||
u8 length;
|
||||
u16 handle;
|
||||
};
|
||||
|
||||
/*
|
||||
* DMI callbacks for problem boards
|
||||
*/
|
||||
struct dmi_strmatch {
|
||||
u8 slot;
|
||||
char *substr;
|
||||
};
|
||||
|
||||
struct dmi_system_id {
|
||||
int (*callback)(struct dmi_system_id *);
|
||||
const char *ident;
|
||||
struct dmi_strmatch matches[4];
|
||||
void *driver_data;
|
||||
};
|
||||
|
||||
#define DMI_MATCH(a, b) { a, b }
|
||||
|
||||
struct dmi_device {
|
||||
struct list_head list;
|
||||
int type;
|
||||
const char *name;
|
||||
void *device_data; /* Type specific data */
|
||||
};
|
||||
|
||||
/* No CONFIG_DMI before 2.6.16 */
|
||||
#if defined(CONFIG_DMI) || defined(CONFIG_X86_32)
|
||||
|
||||
extern int dmi_check_system(struct dmi_system_id *list);
|
||||
extern char * dmi_get_system_info(int field);
|
||||
extern struct dmi_device * dmi_find_device(int type, const char *name,
|
||||
struct dmi_device *from);
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
|
||||
extern void dmi_scan_machine(void);
|
||||
#endif
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
|
||||
extern int dmi_get_year(int field);
|
||||
#endif
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
|
||||
extern int dmi_name_in_vendors(char *str);
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
static inline int dmi_check_system(struct dmi_system_id *list) { return 0; }
|
||||
static inline char * dmi_get_system_info(int field) { return NULL; }
|
||||
static inline struct dmi_device * dmi_find_device(int type, const char *name,
|
||||
struct dmi_device *from) { return NULL; }
|
||||
static inline int dmi_get_year(int year) { return 0; }
|
||||
static inline int dmi_name_in_vendors(char *s) { return 0; }
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* __DMI_H__ */
|
||||
|
||||
#endif /* linux kernel < 2.6.22 */
|
||||
|
||||
#endif
|
21
datapath/linux-2.6/compat-2.6/include/linux/err.h
Normal file
21
datapath/linux-2.6/compat-2.6/include/linux/err.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef __LINUX_ERR_WRAPPER_H
|
||||
#define __LINUX_ERR_WRAPPER_H 1
|
||||
|
||||
#include_next <linux/err.h>
|
||||
|
||||
#ifndef HAVE_ERR_CAST
|
||||
/**
|
||||
* ERR_CAST - Explicitly cast an error-valued pointer to another pointer type
|
||||
* @ptr: The pointer to cast.
|
||||
*
|
||||
* Explicitly cast an error-valued pointer to another pointer type in such a
|
||||
* way as to make it clear that's what's going on.
|
||||
*/
|
||||
static inline void *ERR_CAST(const void *ptr)
|
||||
{
|
||||
/* cast away the const */
|
||||
return (void *) ptr;
|
||||
}
|
||||
#endif /* HAVE_ERR_CAST */
|
||||
|
||||
#endif
|
13
datapath/linux-2.6/compat-2.6/include/linux/icmp.h
Normal file
13
datapath/linux-2.6/compat-2.6/include/linux/icmp.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef __LINUX_ICMP_WRAPPER_H
|
||||
#define __LINUX_ICMP_WRAPPER_H 1
|
||||
|
||||
#include_next <linux/icmp.h>
|
||||
|
||||
#ifndef HAVE_SKBUFF_HEADER_HELPERS
|
||||
static inline struct icmphdr *icmp_hdr(const struct sk_buff *skb)
|
||||
{
|
||||
return (struct icmphdr *)skb_transport_header(skb);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
15
datapath/linux-2.6/compat-2.6/include/linux/if_arp.h
Normal file
15
datapath/linux-2.6/compat-2.6/include/linux/if_arp.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef __LINUX_IF_ARP_WRAPPER_H
|
||||
#define __LINUX_IF_ARP_WRAPPER_H 1
|
||||
|
||||
#include_next <linux/if_arp.h>
|
||||
|
||||
#ifndef HAVE_SKBUFF_HEADER_HELPERS
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
static inline struct arphdr *arp_hdr(const struct sk_buff *skb)
|
||||
{
|
||||
return (struct arphdr *)skb_network_header(skb);
|
||||
}
|
||||
#endif /* !HAVE_SKBUFF_HEADER_HELPERS */
|
||||
|
||||
#endif
|
18
datapath/linux-2.6/compat-2.6/include/linux/ip.h
Normal file
18
datapath/linux-2.6/compat-2.6/include/linux/ip.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef __LINUX_IP_WRAPPER_H
|
||||
#define __LINUX_IP_WRAPPER_H 1
|
||||
|
||||
#include_next <linux/ip.h>
|
||||
|
||||
#ifndef HAVE_SKBUFF_HEADER_HELPERS
|
||||
static inline struct iphdr *ip_hdr(const struct sk_buff *skb)
|
||||
{
|
||||
return (struct iphdr *)skb_network_header(skb);
|
||||
}
|
||||
|
||||
static inline unsigned int ip_hdrlen(const struct sk_buff *skb)
|
||||
{
|
||||
return ip_hdr(skb)->ihl * 4;
|
||||
}
|
||||
#endif /* !HAVE_SKBUFF_HEADER_HELPERS */
|
||||
|
||||
#endif
|
13
datapath/linux-2.6/compat-2.6/include/linux/ipv6.h
Normal file
13
datapath/linux-2.6/compat-2.6/include/linux/ipv6.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef __LINUX_IPV6_WRAPPER_H
|
||||
#define __LINUX_IPV6_WRAPPER_H 1
|
||||
|
||||
#include_next <linux/ipv6.h>
|
||||
|
||||
#ifndef HAVE_SKBUFF_HEADER_HELPERS
|
||||
static inline struct ipv6hdr *ipv6_hdr(const struct sk_buff *skb)
|
||||
{
|
||||
return (struct ipv6hdr *)skb_network_header(skb);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
26
datapath/linux-2.6/compat-2.6/include/linux/jiffies.h
Normal file
26
datapath/linux-2.6/compat-2.6/include/linux/jiffies.h
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef __LINUX_JIFFIES_WRAPPER_H
|
||||
#define __LINUX_JIFFIES_WRAPPER_H 1
|
||||
|
||||
#include_next <linux/jiffies.h>
|
||||
|
||||
#include <linux/version.h>
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
|
||||
|
||||
/* Same as above, but does so with platform independent 64bit types.
|
||||
* These must be used when utilizing jiffies_64 (i.e. return value of
|
||||
* get_jiffies_64() */
|
||||
#define time_after64(a,b) \
|
||||
(typecheck(__u64, a) && \
|
||||
typecheck(__u64, b) && \
|
||||
((__s64)(b) - (__s64)(a) < 0))
|
||||
#define time_before64(a,b) time_after64(b,a)
|
||||
|
||||
#define time_after_eq64(a,b) \
|
||||
(typecheck(__u64, a) && \
|
||||
typecheck(__u64, b) && \
|
||||
((__s64)(a) - (__s64)(b) >= 0))
|
||||
#define time_before_eq64(a,b) time_after_eq64(b,a)
|
||||
|
||||
#endif /* linux kernel < 2.6.19 */
|
||||
|
||||
#endif
|
9
datapath/linux-2.6/compat-2.6/include/linux/kernel.h
Normal file
9
datapath/linux-2.6/compat-2.6/include/linux/kernel.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef __KERNEL_H_WRAPPER
|
||||
#define __KERNEL_H_WRAPPER 1
|
||||
|
||||
#include_next <linux/kernel.h>
|
||||
#ifndef HAVE_LOG2_H
|
||||
#include <linux/log2.h>
|
||||
#endif
|
||||
|
||||
#endif /* linux/kernel.h */
|
450
datapath/linux-2.6/compat-2.6/include/linux/lockdep.h
Normal file
450
datapath/linux-2.6/compat-2.6/include/linux/lockdep.h
Normal file
@ -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 */
|
17
datapath/linux-2.6/compat-2.6/include/linux/log2.h
Normal file
17
datapath/linux-2.6/compat-2.6/include/linux/log2.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef __LINUX_LOG2_WRAPPER
|
||||
#define __LINUX_LOG2_WRAPPER
|
||||
|
||||
#ifdef HAVE_LOG2_H
|
||||
#include_next <linux/log2.h>
|
||||
#else
|
||||
/* This is very stripped down because log2.h has far too many dependencies. */
|
||||
|
||||
extern __attribute__((const, noreturn))
|
||||
int ____ilog2_NaN(void);
|
||||
|
||||
#define ilog2(n) ((n) == 4 ? 2 : \
|
||||
(n) == 8 ? 3 : \
|
||||
____ilog2_NaN())
|
||||
#endif
|
||||
|
||||
#endif
|
59
datapath/linux-2.6/compat-2.6/include/linux/mutex.h
Normal file
59
datapath/linux-2.6/compat-2.6/include/linux/mutex.h
Normal file
@ -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
|
35
datapath/linux-2.6/compat-2.6/include/linux/netdevice.h
Normal file
35
datapath/linux-2.6/compat-2.6/include/linux/netdevice.h
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef __LINUX_NETDEVICE_WRAPPER_H
|
||||
#define __LINUX_NETDEVICE_WRAPPER_H 1
|
||||
|
||||
#include_next <linux/netdevice.h>
|
||||
|
||||
struct net;
|
||||
|
||||
#ifndef to_net_dev
|
||||
#define to_net_dev(class) container_of(class, struct net_device, class_dev)
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
|
||||
static inline
|
||||
struct net *dev_net(const struct net_device *dev)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif /* linux kernel < 2.6.26 */
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
|
||||
#define proc_net init_net.proc_net
|
||||
#endif
|
||||
|
||||
#ifndef for_each_netdev
|
||||
/* Linux before 2.6.22 didn't have for_each_netdev at all. */
|
||||
#define for_each_netdev(net, d) for (d = dev_base; d; d = d->next)
|
||||
#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
|
||||
/* Linux 2.6.24 added a network namespace pointer to the macro. */
|
||||
#undef for_each_netdev
|
||||
#define for_each_netdev(net,d) list_for_each_entry(d, &dev_base_head, dev_list)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif
|
@ -0,0 +1,24 @@
|
||||
#ifndef __LINUX_NETFILTER_BRIDGE_WRAPPER_H
|
||||
#define __LINUX_NETFILTER_BRIDGE_WRAPPER_H
|
||||
|
||||
#include_next <linux/netfilter_bridge.h>
|
||||
|
||||
#include <linux/version.h>
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
|
||||
|
||||
#include <linux/if_vlan.h>
|
||||
#include <linux/if_pppox.h>
|
||||
|
||||
static inline unsigned int nf_bridge_encap_header_len(const struct sk_buff *skb)
|
||||
{
|
||||
switch (skb->protocol) {
|
||||
case __constant_htons(ETH_P_8021Q):
|
||||
return VLAN_HLEN;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* linux version < 2.6.22 */
|
||||
|
||||
#endif
|
19
datapath/linux-2.6/compat-2.6/include/linux/netfilter_ipv4.h
Normal file
19
datapath/linux-2.6/compat-2.6/include/linux/netfilter_ipv4.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef __LINUX_NETFILTER_IPV4_WRAPPER_H
|
||||
#define __LINUX_NETFILTER_IPV4_WRAPPER_H 1
|
||||
|
||||
#include_next <linux/netfilter_ipv4.h>
|
||||
|
||||
#include <linux/version.h>
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#define NF_INET_PRE_ROUTING NF_IP_PRE_ROUTING
|
||||
#define NF_INET_POST_ROUTING NF_IP_POST_ROUTING
|
||||
#define NF_INET_FORWARD NF_IP_FORWARD
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* linux kernel < 2.6.25 */
|
||||
|
||||
#endif
|
24
datapath/linux-2.6/compat-2.6/include/linux/netlink.h
Normal file
24
datapath/linux-2.6/compat-2.6/include/linux/netlink.h
Normal file
@ -0,0 +1,24 @@
|
||||
#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>
|
||||
|
||||
#ifndef NLMSG_DEFAULT_SIZE
|
||||
#define NLMSG_DEFAULT_SIZE (NLMSG_GOODSIZE - NLMSG_HDRLEN)
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
|
||||
#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
|
10
datapath/linux-2.6/compat-2.6/include/linux/percpu.h
Normal file
10
datapath/linux-2.6/compat-2.6/include/linux/percpu.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef __LINUX_PERCPU_H_WRAPPER
|
||||
#define __LINUX_PERCPU_H_WRAPPER 1
|
||||
|
||||
#include_next <linux/percpu.h>
|
||||
|
||||
#ifndef percpu_ptr
|
||||
#define percpu_ptr per_cpu_ptr
|
||||
#endif
|
||||
|
||||
#endif /* linux/percpu.h wrapper */
|
17
datapath/linux-2.6/compat-2.6/include/linux/random.h
Normal file
17
datapath/linux-2.6/compat-2.6/include/linux/random.h
Normal file
@ -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
|
12
datapath/linux-2.6/compat-2.6/include/linux/rculist.h
Normal file
12
datapath/linux-2.6/compat-2.6/include/linux/rculist.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef __LINUX_RCULIST_WRAPPER_H
|
||||
#define __LINUX_RCULIST_WRAPPER_H
|
||||
|
||||
#include <linux/version.h>
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
|
||||
#include_next <linux/rculist.h>
|
||||
#else
|
||||
/* Prior to 2.6.26, the contents of rculist.h were part of list.h. */
|
||||
#include <linux/list.h>
|
||||
#endif
|
||||
|
||||
#endif
|
29
datapath/linux-2.6/compat-2.6/include/linux/rtnetlink.h
Normal file
29
datapath/linux-2.6/compat-2.6/include/linux/rtnetlink.h
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef __RTNETLINK_WRAPPER_H
|
||||
#define __RTNETLINK_WRAPPER_H 1
|
||||
|
||||
#include_next <linux/rtnetlink.h>
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
|
||||
static inline int rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid,
|
||||
u32 group, struct nlmsghdr *nlh, gfp_t flags)
|
||||
{
|
||||
BUG_ON(nlh); /* not implemented */
|
||||
if (group) {
|
||||
/* errors reported via destination sk->sk_err */
|
||||
nlmsg_multicast(rtnl, skb, 0, group);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void rtnl_set_sk_err(struct net *net, u32 group, int error)
|
||||
{
|
||||
netlink_set_err(rtnl, 0, group, error);
|
||||
}
|
||||
#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
|
||||
#define rtnl_notify(skb, net, pid, group, nlh, flags) \
|
||||
((void) (net), rtnl_notify(skb, pid, group, nlh, flags))
|
||||
#define rtnl_set_sk_err(net, group, error) \
|
||||
((void) (net), rtnl_set_sk_err(group, error))
|
||||
#endif /* linux kernel < 2.6.25 */
|
||||
|
||||
#endif /* linux/rtnetlink.h wrapper */
|
170
datapath/linux-2.6/compat-2.6/include/linux/skbuff.h
Normal file
170
datapath/linux-2.6/compat-2.6/include/linux/skbuff.h
Normal file
@ -0,0 +1,170 @@
|
||||
#ifndef __LINUX_SKBUFF_WRAPPER_H
|
||||
#define __LINUX_SKBUFF_WRAPPER_H 1
|
||||
|
||||
#include_next <linux/skbuff.h>
|
||||
|
||||
#include <linux/version.h>
|
||||
|
||||
#ifndef HAVE_SKB_COPY_FROM_LINEAR_DATA_OFFSET
|
||||
static inline void skb_copy_from_linear_data_offset(const struct sk_buff *skb,
|
||||
const int offset, void *to,
|
||||
const unsigned int len)
|
||||
{
|
||||
memcpy(to, skb->data + offset, len);
|
||||
}
|
||||
|
||||
static inline void skb_copy_to_linear_data_offset(struct sk_buff *skb,
|
||||
const int offset,
|
||||
const void *from,
|
||||
const unsigned int len)
|
||||
{
|
||||
memcpy(skb->data + offset, from, len);
|
||||
}
|
||||
|
||||
#endif /* !HAVE_SKB_COPY_FROM_LINEAR_DATA_OFFSET */
|
||||
|
||||
/*
|
||||
* The networking layer reserves some headroom in skb data (via
|
||||
* dev_alloc_skb). This is used to avoid having to reallocate skb data when
|
||||
* the header has to grow. In the default case, if the header has to grow
|
||||
* 16 bytes or less we avoid the reallocation.
|
||||
*
|
||||
* Unfortunately this headroom changes the DMA alignment of the resulting
|
||||
* network packet. As for NET_IP_ALIGN, this unaligned DMA is expensive
|
||||
* on some architectures. An architecture can override this value,
|
||||
* perhaps setting it to a cacheline in size (since that will maintain
|
||||
* cacheline alignment of the DMA). It must be a power of 2.
|
||||
*
|
||||
* Various parts of the networking layer expect at least 16 bytes of
|
||||
* headroom, you should not reduce this.
|
||||
*/
|
||||
#ifndef NET_SKB_PAD
|
||||
#define NET_SKB_PAD 16
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
|
||||
static inline int __skb_cow(struct sk_buff *skb, unsigned int headroom,
|
||||
int cloned)
|
||||
{
|
||||
int delta = 0;
|
||||
|
||||
if (headroom < NET_SKB_PAD)
|
||||
headroom = NET_SKB_PAD;
|
||||
if (headroom > skb_headroom(skb))
|
||||
delta = headroom - skb_headroom(skb);
|
||||
|
||||
if (delta || cloned)
|
||||
return pskb_expand_head(skb, ALIGN(delta, NET_SKB_PAD), 0,
|
||||
GFP_ATOMIC);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int skb_cow_head(struct sk_buff *skb, unsigned int headroom)
|
||||
{
|
||||
return __skb_cow(skb, headroom, skb_header_cloned(skb));
|
||||
}
|
||||
#endif /* linux < 2.6.23 */
|
||||
|
||||
|
||||
#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
|
||||
|
||||
|
||||
#ifndef CHECKSUM_PARTIAL
|
||||
/* 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
|
||||
#endif
|
||||
#ifndef CHECKSUM_COMPLETE
|
||||
#define CHECKSUM_COMPLETE CHECKSUM_HW
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MAC_RAW
|
||||
#define mac_header mac.raw
|
||||
#define network_header nh.raw
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_SKBUFF_HEADER_HELPERS
|
||||
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_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_reset_mac_header(struct sk_buff *skb)
|
||||
{
|
||||
skb->mac_header = 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 int skb_network_offset(const struct sk_buff *skb)
|
||||
{
|
||||
return skb_network_header(skb) - skb->data;
|
||||
}
|
||||
|
||||
static inline void skb_copy_to_linear_data(struct sk_buff *skb,
|
||||
const void *from,
|
||||
const unsigned int len)
|
||||
{
|
||||
memcpy(skb->data, from, len);
|
||||
}
|
||||
#endif /* !HAVE_SKBUFF_HEADER_HELPERS */
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
|
||||
#warning "TSO/UFO not supported on kernels earlier than 2.6.18"
|
||||
|
||||
static inline int skb_is_gso(const struct sk_buff *skb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline struct sk_buff *skb_gso_segment(struct sk_buff *skb,
|
||||
int features)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif /* before 2.6.18 */
|
||||
|
||||
#endif
|
18
datapath/linux-2.6/compat-2.6/include/linux/tcp.h
Normal file
18
datapath/linux-2.6/compat-2.6/include/linux/tcp.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef __LINUX_TCP_WRAPPER_H
|
||||
#define __LINUX_TCP_WRAPPER_H 1
|
||||
|
||||
#include_next <linux/tcp.h>
|
||||
|
||||
#ifndef HAVE_SKBUFF_HEADER_HELPERS
|
||||
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;
|
||||
}
|
||||
#endif /* !HAVE_SKBUFF_HEADER_HELPERS */
|
||||
|
||||
#endif
|
96
datapath/linux-2.6/compat-2.6/include/linux/timer.h
Normal file
96
datapath/linux-2.6/compat-2.6/include/linux/timer.h
Normal file
@ -0,0 +1,96 @@
|
||||
#ifndef __LINUX_TIMER_WRAPPER_H
|
||||
#define __LINUX_TIMER_WRAPPER_H 1
|
||||
|
||||
#include_next <linux/timer.h>
|
||||
|
||||
#include <linux/version.h>
|
||||
|
||||
#ifndef RHEL_RELEASE_VERSION
|
||||
#define RHEL_RELEASE_VERSION(X,Y) ( 0 )
|
||||
#endif
|
||||
#if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)) && \
|
||||
(!defined(RHEL_RELEASE_CODE) || \
|
||||
(RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(5,1))))
|
||||
|
||||
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
|
14
datapath/linux-2.6/compat-2.6/include/linux/types.h
Normal file
14
datapath/linux-2.6/compat-2.6/include/linux/types.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef __LINUX_TYPES_WRAPPER_H
|
||||
#define __LINUX_TYPES_WRAPPER_H 1
|
||||
|
||||
#include_next <linux/types.h>
|
||||
|
||||
#include <linux/version.h>
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
|
||||
|
||||
typedef __u16 __bitwise __sum16;
|
||||
typedef __u32 __bitwise __wsum;
|
||||
|
||||
#endif /* linux kernel < 2.6.20 */
|
||||
|
||||
#endif
|
13
datapath/linux-2.6/compat-2.6/include/linux/udp.h
Normal file
13
datapath/linux-2.6/compat-2.6/include/linux/udp.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef __LINUX_UDP_WRAPPER_H
|
||||
#define __LINUX_UDP_WRAPPER_H 1
|
||||
|
||||
#include_next <linux/udp.h>
|
||||
|
||||
#ifndef HAVE_SKBUFF_HEADER_HELPERS
|
||||
static inline struct udphdr *udp_hdr(const struct sk_buff *skb)
|
||||
{
|
||||
return (struct udphdr *)skb_transport_header(skb);
|
||||
}
|
||||
#endif /* HAVE_SKBUFF_HEADER_HELPERS */
|
||||
|
||||
#endif
|
42
datapath/linux-2.6/compat-2.6/include/linux/workqueue.h
Normal file
42
datapath/linux-2.6/compat-2.6/include/linux/workqueue.h
Normal file
@ -0,0 +1,42 @@
|
||||
#ifndef __LINUX_WORKQUEUE_WRAPPER_H
|
||||
#define __LINUX_WORKQUEUE_WRAPPER_H 1
|
||||
|
||||
#include_next <linux/workqueue.h>
|
||||
|
||||
#include <linux/version.h>
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
|
||||
|
||||
#ifdef __KERNEL__
|
||||
/*
|
||||
* initialize a work-struct's func and data pointers:
|
||||
*/
|
||||
#undef PREPARE_WORK
|
||||
#define PREPARE_WORK(_work, _func) \
|
||||
do { \
|
||||
(_work)->func = (void(*)(void*)) _func; \
|
||||
(_work)->data = _work; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* initialize all of a work-struct:
|
||||
*/
|
||||
#undef INIT_WORK
|
||||
#define INIT_WORK(_work, _func) \
|
||||
do { \
|
||||
INIT_LIST_HEAD(&(_work)->entry); \
|
||||
(_work)->pending = 0; \
|
||||
PREPARE_WORK((_work), (_func)); \
|
||||
init_timer(&(_work)->timer); \
|
||||
} while (0)
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* linux kernel < 2.6.20 */
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
|
||||
/* There is no equivalent to cancel_work_sync() so just flush all
|
||||
* pending work. */
|
||||
#define cancel_work_sync(_work) flush_scheduled_work()
|
||||
#endif
|
||||
|
||||
#endif
|
16
datapath/linux-2.6/compat-2.6/include/net/checksum.h
Normal file
16
datapath/linux-2.6/compat-2.6/include/net/checksum.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef __NET_CHECKSUM_WRAPPER_H
|
||||
#define __NET_CHECKSUM_WRAPPER_H 1
|
||||
|
||||
#include_next <net/checksum.h>
|
||||
|
||||
#include <linux/version.h>
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
|
||||
|
||||
static inline __wsum csum_unfold(__sum16 n)
|
||||
{
|
||||
return (__force __wsum)n;
|
||||
}
|
||||
|
||||
#endif /* linux kernel < 2.6.20 */
|
||||
|
||||
#endif /* checksum.h */
|
123
datapath/linux-2.6/compat-2.6/include/net/genetlink.h
Normal file
123
datapath/linux-2.6/compat-2.6/include/net/genetlink.h
Normal file
@ -0,0 +1,123 @@
|
||||
#ifndef __NET_GENERIC_NETLINK_WRAPPER_H
|
||||
#define __NET_GENERIC_NETLINK_WRAPPER_H 1
|
||||
|
||||
|
||||
#include <linux/netlink.h>
|
||||
#include_next <net/genetlink.h>
|
||||
|
||||
#include <linux/version.h>
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
|
||||
|
||||
#include <linux/genetlink.h>
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* In 2.6.23, registering of multicast groups was added. Our compatability
|
||||
* layer just supports registering a single group, since that's all we
|
||||
* need.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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;
|
||||
};
|
||||
|
||||
int genl_register_mc_group(struct genl_family *family,
|
||||
struct genl_multicast_group *grp);
|
||||
#endif /* linux kernel < 2.6.23 */
|
||||
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
|
||||
/**
|
||||
* 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));
|
||||
}
|
||||
|
||||
#define genlmsg_multicast(s, p, g, f) \
|
||||
genlmsg_multicast_flags((s), (p), (g), (f))
|
||||
|
||||
static inline int genlmsg_multicast_flags(struct sk_buff *skb, u32 pid,
|
||||
unsigned int group, gfp_t flags)
|
||||
{
|
||||
int err;
|
||||
|
||||
NETLINK_CB(skb).dst_group = group;
|
||||
|
||||
err = netlink_broadcast(genl_sock, skb, pid, group, flags);
|
||||
if (err > 0)
|
||||
err = 0;
|
||||
|
||||
return err;
|
||||
}
|
||||
#endif /* linux kernel < 2.6.19 */
|
||||
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
|
||||
|
||||
#define genlmsg_put(skb, p, seq, fam, flg, c) \
|
||||
genlmsg_put((skb), (p), (seq), (fam)->id, (fam)->hdrsize, \
|
||||
(flg), (c), (fam)->version)
|
||||
|
||||
/**
|
||||
* 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_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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 /* linux kernel < 2.6.20 */
|
||||
|
||||
#endif /* genetlink.h */
|
22
datapath/linux-2.6/compat-2.6/include/net/netlink.h
Normal file
22
datapath/linux-2.6/compat-2.6/include/net/netlink.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef __NET_NETLINK_WRAPPER_H
|
||||
#define __NET_NETLINK_WRAPPER_H 1
|
||||
|
||||
#include_next <net/netlink.h>
|
||||
|
||||
#ifndef HAVE_NLA_NUL_STRING
|
||||
#define NLA_NUL_STRING NLA_STRING
|
||||
|
||||
static inline int VERIFY_NUL_STRING(struct nlattr *attr)
|
||||
{
|
||||
return (!attr || (nla_len(attr)
|
||||
&& memchr(nla_data(attr), '\0', nla_len(attr)))
|
||||
? 0 : EINVAL);
|
||||
}
|
||||
#else
|
||||
static inline int VERIFY_NUL_STRING(struct nlattr *attr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* !HAVE_NLA_NUL_STRING */
|
||||
|
||||
#endif /* net/netlink.h */
|
144
datapath/linux-2.6/compat-2.6/random32.c
Normal file
144
datapath/linux-2.6/compat-2.6/random32.c
Normal file
@ -0,0 +1,144 @@
|
||||
#include <linux/version.h>
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
|
||||
|
||||
/*
|
||||
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/smp.h>
|
||||
|
||||
#include "compat26.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()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#endif /* kernel < 2.6.19 */
|
537
datapath/linux-2.6/compat-2.6/veth.c
Normal file
537
datapath/linux-2.6/compat-2.6/veth.c
Normal file
@ -0,0 +1,537 @@
|
||||
/* veth driver port to Linux 2.6.18 */
|
||||
|
||||
/*
|
||||
* drivers/net/veth.c
|
||||
*
|
||||
* Copyright (C) 2007, 2009 OpenVZ http://openvz.org, SWsoft Inc
|
||||
*
|
||||
* Author: Pavel Emelianov <xemul@openvz.org>
|
||||
* Ethtool interface from: Eric W. Biederman <ebiederm@xmission.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/etherdevice.h>
|
||||
|
||||
#include <net/dst.h>
|
||||
#include <net/xfrm.h>
|
||||
|
||||
#define DRV_NAME "veth"
|
||||
#define DRV_VERSION "1.0"
|
||||
|
||||
struct veth_net_stats {
|
||||
unsigned long rx_packets;
|
||||
unsigned long tx_packets;
|
||||
unsigned long rx_bytes;
|
||||
unsigned long tx_bytes;
|
||||
unsigned long tx_dropped;
|
||||
};
|
||||
|
||||
struct veth_priv {
|
||||
struct net_device *peer;
|
||||
struct net_device *dev;
|
||||
struct list_head list;
|
||||
struct veth_net_stats *stats;
|
||||
unsigned ip_summed;
|
||||
struct net_device_stats dev_stats;
|
||||
};
|
||||
|
||||
static LIST_HEAD(veth_list);
|
||||
|
||||
/*
|
||||
* ethtool interface
|
||||
*/
|
||||
|
||||
static struct {
|
||||
const char string[ETH_GSTRING_LEN];
|
||||
} ethtool_stats_keys[] = {
|
||||
{ "peer_ifindex" },
|
||||
};
|
||||
|
||||
static int veth_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
|
||||
{
|
||||
cmd->supported = 0;
|
||||
cmd->advertising = 0;
|
||||
cmd->speed = SPEED_10000;
|
||||
cmd->duplex = DUPLEX_FULL;
|
||||
cmd->port = PORT_TP;
|
||||
cmd->phy_address = 0;
|
||||
cmd->transceiver = XCVR_INTERNAL;
|
||||
cmd->autoneg = AUTONEG_DISABLE;
|
||||
cmd->maxtxpkt = 0;
|
||||
cmd->maxrxpkt = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void veth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
|
||||
{
|
||||
strcpy(info->driver, DRV_NAME);
|
||||
strcpy(info->version, DRV_VERSION);
|
||||
strcpy(info->fw_version, "N/A");
|
||||
}
|
||||
|
||||
static void veth_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
|
||||
{
|
||||
switch(stringset) {
|
||||
case ETH_SS_STATS:
|
||||
memcpy(buf, ðtool_stats_keys, sizeof(ethtool_stats_keys));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void veth_get_ethtool_stats(struct net_device *dev,
|
||||
struct ethtool_stats *stats, u64 *data)
|
||||
{
|
||||
struct veth_priv *priv;
|
||||
|
||||
priv = netdev_priv(dev);
|
||||
data[0] = priv->peer->ifindex;
|
||||
}
|
||||
|
||||
static u32 veth_get_rx_csum(struct net_device *dev)
|
||||
{
|
||||
struct veth_priv *priv;
|
||||
|
||||
priv = netdev_priv(dev);
|
||||
return priv->ip_summed == CHECKSUM_UNNECESSARY;
|
||||
}
|
||||
|
||||
static int veth_set_rx_csum(struct net_device *dev, u32 data)
|
||||
{
|
||||
struct veth_priv *priv;
|
||||
|
||||
priv = netdev_priv(dev);
|
||||
priv->ip_summed = data ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 veth_get_tx_csum(struct net_device *dev)
|
||||
{
|
||||
return (dev->features & NETIF_F_NO_CSUM) != 0;
|
||||
}
|
||||
|
||||
static int veth_set_tx_csum(struct net_device *dev, u32 data)
|
||||
{
|
||||
if (data)
|
||||
dev->features |= NETIF_F_NO_CSUM;
|
||||
else
|
||||
dev->features &= ~NETIF_F_NO_CSUM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ethtool_ops veth_ethtool_ops = {
|
||||
.get_settings = veth_get_settings,
|
||||
.get_drvinfo = veth_get_drvinfo,
|
||||
.get_link = ethtool_op_get_link,
|
||||
.get_rx_csum = veth_get_rx_csum,
|
||||
.set_rx_csum = veth_set_rx_csum,
|
||||
.get_tx_csum = veth_get_tx_csum,
|
||||
.set_tx_csum = veth_set_tx_csum,
|
||||
.get_sg = ethtool_op_get_sg,
|
||||
.set_sg = ethtool_op_set_sg,
|
||||
.get_strings = veth_get_strings,
|
||||
.get_ethtool_stats = veth_get_ethtool_stats,
|
||||
};
|
||||
|
||||
/*
|
||||
* xmit
|
||||
*/
|
||||
|
||||
static int veth_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
struct net_device *rcv = NULL;
|
||||
struct veth_priv *priv, *rcv_priv;
|
||||
struct veth_net_stats *stats;
|
||||
int length, cpu;
|
||||
|
||||
skb_orphan(skb);
|
||||
|
||||
priv = netdev_priv(dev);
|
||||
rcv = priv->peer;
|
||||
rcv_priv = netdev_priv(rcv);
|
||||
|
||||
cpu = smp_processor_id();
|
||||
stats = per_cpu_ptr(priv->stats, cpu);
|
||||
|
||||
if (!(rcv->flags & IFF_UP))
|
||||
goto outf;
|
||||
|
||||
skb->dev = rcv;
|
||||
skb->pkt_type = PACKET_HOST;
|
||||
skb->protocol = eth_type_trans(skb, rcv);
|
||||
if (dev->features & NETIF_F_NO_CSUM)
|
||||
skb->ip_summed = rcv_priv->ip_summed;
|
||||
|
||||
dst_release(skb->dst);
|
||||
skb->dst = NULL;
|
||||
secpath_reset(skb);
|
||||
nf_reset(skb);
|
||||
|
||||
length = skb->len;
|
||||
|
||||
stats->tx_bytes += length;
|
||||
stats->tx_packets++;
|
||||
|
||||
stats = per_cpu_ptr(rcv_priv->stats, cpu);
|
||||
stats->rx_bytes += length;
|
||||
stats->rx_packets++;
|
||||
|
||||
netif_rx(skb);
|
||||
return 0;
|
||||
|
||||
outf:
|
||||
kfree_skb(skb);
|
||||
stats->tx_dropped++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* general routines
|
||||
*/
|
||||
|
||||
static struct net_device_stats *veth_get_stats(struct net_device *dev)
|
||||
{
|
||||
struct veth_priv *priv;
|
||||
struct net_device_stats *dev_stats;
|
||||
int cpu;
|
||||
struct veth_net_stats *stats;
|
||||
|
||||
priv = netdev_priv(dev);
|
||||
dev_stats = &priv->dev_stats;
|
||||
|
||||
dev_stats->rx_packets = 0;
|
||||
dev_stats->tx_packets = 0;
|
||||
dev_stats->rx_bytes = 0;
|
||||
dev_stats->tx_bytes = 0;
|
||||
dev_stats->tx_dropped = 0;
|
||||
|
||||
for_each_online_cpu(cpu) {
|
||||
stats = per_cpu_ptr(priv->stats, cpu);
|
||||
|
||||
dev_stats->rx_packets += stats->rx_packets;
|
||||
dev_stats->tx_packets += stats->tx_packets;
|
||||
dev_stats->rx_bytes += stats->rx_bytes;
|
||||
dev_stats->tx_bytes += stats->tx_bytes;
|
||||
dev_stats->tx_dropped += stats->tx_dropped;
|
||||
}
|
||||
|
||||
return dev_stats;
|
||||
}
|
||||
|
||||
static int veth_open(struct net_device *dev)
|
||||
{
|
||||
struct veth_priv *priv;
|
||||
|
||||
priv = netdev_priv(dev);
|
||||
if (priv->peer == NULL)
|
||||
return -ENOTCONN;
|
||||
|
||||
if (priv->peer->flags & IFF_UP) {
|
||||
netif_carrier_on(dev);
|
||||
netif_carrier_on(priv->peer);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int veth_dev_init(struct net_device *dev)
|
||||
{
|
||||
struct veth_net_stats *stats;
|
||||
struct veth_priv *priv;
|
||||
|
||||
stats = alloc_percpu(struct veth_net_stats);
|
||||
if (stats == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
priv = netdev_priv(dev);
|
||||
priv->stats = stats;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void veth_dev_free(struct net_device *dev)
|
||||
{
|
||||
struct veth_priv *priv;
|
||||
|
||||
priv = netdev_priv(dev);
|
||||
free_percpu(priv->stats);
|
||||
free_netdev(dev);
|
||||
}
|
||||
|
||||
static void veth_setup(struct net_device *dev)
|
||||
{
|
||||
ether_setup(dev);
|
||||
|
||||
dev->hard_start_xmit = veth_xmit;
|
||||
dev->get_stats = veth_get_stats;
|
||||
dev->open = veth_open;
|
||||
dev->ethtool_ops = &veth_ethtool_ops;
|
||||
dev->features |= NETIF_F_LLTX;
|
||||
dev->init = veth_dev_init;
|
||||
dev->destructor = veth_dev_free;
|
||||
}
|
||||
|
||||
static void veth_change_state(struct net_device *dev)
|
||||
{
|
||||
struct net_device *peer;
|
||||
struct veth_priv *priv;
|
||||
|
||||
priv = netdev_priv(dev);
|
||||
peer = priv->peer;
|
||||
|
||||
if (netif_carrier_ok(peer)) {
|
||||
if (!netif_carrier_ok(dev))
|
||||
netif_carrier_on(dev);
|
||||
} else {
|
||||
if (netif_carrier_ok(dev))
|
||||
netif_carrier_off(dev);
|
||||
}
|
||||
}
|
||||
|
||||
static int veth_device_event(struct notifier_block *unused,
|
||||
unsigned long event, void *ptr)
|
||||
{
|
||||
struct net_device *dev = ptr;
|
||||
|
||||
if (dev->open != veth_open)
|
||||
goto out;
|
||||
|
||||
switch (event) {
|
||||
case NETDEV_CHANGE:
|
||||
veth_change_state(dev);
|
||||
break;
|
||||
}
|
||||
out:
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static struct notifier_block veth_notifier_block __read_mostly = {
|
||||
.notifier_call = veth_device_event,
|
||||
};
|
||||
|
||||
/*
|
||||
* netlink interface
|
||||
*/
|
||||
|
||||
static int veth_newlink(const char *devname, const char *peername)
|
||||
{
|
||||
int err;
|
||||
const char *names[2];
|
||||
struct net_device *devs[2];
|
||||
int i;
|
||||
|
||||
names[0] = devname;
|
||||
names[1] = peername;
|
||||
devs[0] = devs[1] = NULL;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
struct net_device *dev;
|
||||
|
||||
err = -ENOMEM;
|
||||
devs[i] = alloc_netdev(sizeof(struct veth_priv),
|
||||
names[i], veth_setup);
|
||||
if (!devs[i]) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
dev = devs[i];
|
||||
|
||||
if (strchr(dev->name, '%')) {
|
||||
err = dev_alloc_name(dev, dev->name);
|
||||
if (err < 0)
|
||||
goto err;
|
||||
}
|
||||
random_ether_addr(dev->dev_addr);
|
||||
|
||||
err = register_netdevice(dev);
|
||||
if (err < 0)
|
||||
goto err;
|
||||
|
||||
netif_carrier_off(dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* tie the devices together
|
||||
*/
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
struct veth_priv *priv = netdev_priv(devs[i]);
|
||||
priv->dev = devs[i];
|
||||
priv->peer = devs[!i];
|
||||
if (!i)
|
||||
list_add(&priv->list, &veth_list);
|
||||
else
|
||||
INIT_LIST_HEAD(&priv->list);
|
||||
}
|
||||
return 0;
|
||||
|
||||
err:
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (devs[i]) {
|
||||
if (devs[i]->reg_state != NETREG_UNINITIALIZED)
|
||||
unregister_netdevice(devs[i]);
|
||||
else
|
||||
free_netdev(devs[i]);
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static void veth_dellink(struct net_device *dev)
|
||||
{
|
||||
struct veth_priv *priv;
|
||||
struct net_device *peer;
|
||||
|
||||
priv = netdev_priv(dev);
|
||||
peer = priv->peer;
|
||||
|
||||
if (!list_empty(&priv->list))
|
||||
list_del(&priv->list);
|
||||
|
||||
priv = netdev_priv(peer);
|
||||
if (!list_empty(&priv->list))
|
||||
list_del(&priv->list);
|
||||
|
||||
unregister_netdevice(dev);
|
||||
unregister_netdevice(peer);
|
||||
}
|
||||
|
||||
/*
|
||||
* sysfs
|
||||
*/
|
||||
|
||||
/*
|
||||
* "show" function for the veth_pairs attribute.
|
||||
* The class parameter is ignored.
|
||||
*/
|
||||
static ssize_t veth_show_veth_pairs(struct class *cls, char *buffer)
|
||||
{
|
||||
int res = 0;
|
||||
struct veth_priv *priv;
|
||||
|
||||
list_for_each_entry(priv, &veth_list, list) {
|
||||
if (res > (PAGE_SIZE - (IFNAMSIZ * 2 + 1))) {
|
||||
/* not enough space for another interface name */
|
||||
if ((PAGE_SIZE - res) > 10)
|
||||
res = PAGE_SIZE - 10;
|
||||
res += sprintf(buffer + res, "++more++");
|
||||
break;
|
||||
}
|
||||
res += sprintf(buffer + res, "%s,%s ",
|
||||
priv->dev->name, priv->peer->name);
|
||||
}
|
||||
res += sprintf(buffer + res, "\n");
|
||||
res++;
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* "store" function for the veth_pairs attribute. This is what
|
||||
* creates and deletes veth pairs.
|
||||
*
|
||||
* The class parameter is ignored.
|
||||
*
|
||||
*/
|
||||
static ssize_t veth_store_veth_pairs(struct class *cls, const char *buffer,
|
||||
size_t count)
|
||||
{
|
||||
int c = *buffer++;
|
||||
int retval;
|
||||
printk("1\n");
|
||||
if (c == '+') {
|
||||
char devname[IFNAMSIZ + 1] = "";
|
||||
char peername[IFNAMSIZ + 1] = "";
|
||||
char *comma = strchr(buffer, ',');
|
||||
printk("2\n");
|
||||
if (!comma)
|
||||
goto err_no_cmd;
|
||||
strncat(devname, buffer,
|
||||
min_t(int, sizeof devname, comma - buffer));
|
||||
strncat(peername, comma + 1,
|
||||
min_t(int, sizeof peername, strcspn(comma + 1, "\n")));
|
||||
printk("3 '%s' '%s'\n", devname, peername);
|
||||
if (!dev_valid_name(devname) || !dev_valid_name(peername))
|
||||
goto err_no_cmd;
|
||||
printk("4\n");
|
||||
rtnl_lock();
|
||||
retval = veth_newlink(devname, peername);
|
||||
rtnl_unlock();
|
||||
return retval ? retval : count;
|
||||
} else if (c == '-') {
|
||||
struct net_device *dev;
|
||||
|
||||
rtnl_lock();
|
||||
dev = dev_get_by_name(buffer);
|
||||
if (!dev)
|
||||
retval = -ENODEV;
|
||||
else if (dev->init != veth_dev_init)
|
||||
retval = -EINVAL;
|
||||
else {
|
||||
veth_dellink(dev);
|
||||
retval = count;
|
||||
}
|
||||
rtnl_unlock();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
err_no_cmd:
|
||||
printk(KERN_ERR DRV_NAME ": no command found in veth_pairs. Use +ifname,peername or -ifname.\n");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
/* class attribute for veth_pairs file. This ends up in /sys/class/net */
|
||||
static CLASS_ATTR(veth_pairs, S_IWUSR | S_IRUGO,
|
||||
veth_show_veth_pairs, veth_store_veth_pairs);
|
||||
|
||||
static struct class *netdev_class;
|
||||
|
||||
/*
|
||||
* Initialize sysfs. This sets up the veth_pairs file in
|
||||
* /sys/class/net.
|
||||
*/
|
||||
int veth_create_sysfs(void)
|
||||
{
|
||||
struct net_device *dev = dev_get_by_name("lo");
|
||||
if (!dev)
|
||||
return -ESRCH;
|
||||
netdev_class = dev->class_dev.class;
|
||||
if (!netdev_class)
|
||||
return -ENODEV;
|
||||
|
||||
return class_create_file(netdev_class, &class_attr_veth_pairs);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove /sys/class/net/veth_pairs.
|
||||
*/
|
||||
void veth_destroy_sysfs(void)
|
||||
{
|
||||
class_remove_file(netdev_class, &class_attr_veth_pairs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* init/fini
|
||||
*/
|
||||
|
||||
static __init int veth_init(void)
|
||||
{
|
||||
int retval = veth_create_sysfs();
|
||||
if (retval)
|
||||
return retval;
|
||||
register_netdevice_notifier(&veth_notifier_block);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __exit void veth_exit(void)
|
||||
{
|
||||
unregister_netdevice_notifier(&veth_notifier_block);
|
||||
}
|
||||
|
||||
module_init(veth_init);
|
||||
module_exit(veth_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Virtual Ethernet Tunnel");
|
||||
MODULE_LICENSE("GPL v2");
|
1408
datapath/linux-2.6/config/config-linux-2.6.23-rc9-kvm
Normal file
1408
datapath/linux-2.6/config/config-linux-2.6.23-rc9-kvm
Normal file
File diff suppressed because it is too large
Load Diff
240
datapath/table.c
Normal file
240
datapath/table.c
Normal file
@ -0,0 +1,240 @@
|
||||
#include "flow.h"
|
||||
#include "datapath.h"
|
||||
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/jhash.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <asm/pgtable.h>
|
||||
|
||||
static void free_table(struct sw_flow ***flows, unsigned int n_buckets,
|
||||
int free_flows)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < n_buckets >> DP_L1_BITS; i++) {
|
||||
struct sw_flow **l2 = flows[i];
|
||||
if (free_flows) {
|
||||
unsigned int j;
|
||||
for (j = 0; j < DP_L1_SIZE; j++) {
|
||||
if (l2[j])
|
||||
flow_free(l2[j]);
|
||||
}
|
||||
}
|
||||
free_page((unsigned long)l2);
|
||||
}
|
||||
kfree(flows);
|
||||
}
|
||||
|
||||
static struct sw_flow ***alloc_table(unsigned int n_buckets)
|
||||
{
|
||||
struct sw_flow ***flows;
|
||||
unsigned int i;
|
||||
|
||||
flows = kmalloc((n_buckets >> DP_L1_BITS) * sizeof(struct sw_flow**),
|
||||
GFP_KERNEL);
|
||||
if (!flows)
|
||||
return NULL;
|
||||
for (i = 0; i < n_buckets >> DP_L1_BITS; i++) {
|
||||
flows[i] = (struct sw_flow **)get_zeroed_page(GFP_KERNEL);
|
||||
if (!flows[i]) {
|
||||
free_table(flows, i << DP_L1_BITS, 0);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return flows;
|
||||
}
|
||||
|
||||
struct dp_table *dp_table_create(unsigned int n_buckets)
|
||||
{
|
||||
struct dp_table *table;
|
||||
|
||||
table = kzalloc(sizeof *table, GFP_KERNEL);
|
||||
if (!table)
|
||||
goto err;
|
||||
|
||||
table->n_buckets = n_buckets;
|
||||
table->flows[0] = alloc_table(n_buckets);
|
||||
if (!table[0].flows)
|
||||
goto err_free_tables;
|
||||
|
||||
table->flows[1] = alloc_table(n_buckets);
|
||||
if (!table->flows[1])
|
||||
goto err_free_flows0;
|
||||
|
||||
return table;
|
||||
|
||||
err_free_flows0:
|
||||
free_table(table->flows[0], table->n_buckets, 0);
|
||||
err_free_tables:
|
||||
kfree(table);
|
||||
err:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void dp_table_destroy(struct dp_table *table, int free_flows)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 2; i++)
|
||||
free_table(table->flows[i], table->n_buckets, free_flows);
|
||||
kfree(table);
|
||||
}
|
||||
|
||||
static struct sw_flow **find_bucket(struct dp_table *table,
|
||||
struct sw_flow ***flows, u32 hash)
|
||||
{
|
||||
unsigned int l1 = (hash & (table->n_buckets - 1)) >> DP_L1_SHIFT;
|
||||
unsigned int l2 = hash & ((1 << DP_L2_BITS) - 1);
|
||||
return &flows[l1][l2];
|
||||
}
|
||||
|
||||
static struct sw_flow *lookup_table(struct dp_table *table,
|
||||
struct sw_flow ***flows, u32 hash,
|
||||
const struct odp_flow_key *key)
|
||||
{
|
||||
struct sw_flow **bucket = find_bucket(table, flows, hash);
|
||||
struct sw_flow *flow = rcu_dereference(*bucket);
|
||||
if (flow && !memcmp(&flow->key, key, sizeof(struct odp_flow_key)))
|
||||
return flow;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static u32 flow_hash0(const struct odp_flow_key *key)
|
||||
{
|
||||
return jhash2((u32*)key, sizeof *key / sizeof(u32), 0xaaaaaaaa);
|
||||
}
|
||||
|
||||
static u32 flow_hash1(const struct odp_flow_key *key)
|
||||
{
|
||||
return jhash2((u32*)key, sizeof *key / sizeof(u32), 0x55555555);
|
||||
}
|
||||
|
||||
static void find_buckets(struct dp_table *table,
|
||||
const struct odp_flow_key *key,
|
||||
struct sw_flow **buckets[2])
|
||||
{
|
||||
buckets[0] = find_bucket(table, table->flows[0], flow_hash0(key));
|
||||
buckets[1] = find_bucket(table, table->flows[1], flow_hash1(key));
|
||||
}
|
||||
|
||||
struct sw_flow *dp_table_lookup(struct dp_table *table,
|
||||
const struct odp_flow_key *key)
|
||||
{
|
||||
struct sw_flow *flow;
|
||||
flow = lookup_table(table, table->flows[0], flow_hash0(key), key);
|
||||
if (!flow)
|
||||
flow = lookup_table(table, table->flows[1],
|
||||
flow_hash1(key), key);
|
||||
return flow;
|
||||
}
|
||||
|
||||
int dp_table_foreach(struct dp_table *table,
|
||||
int (*callback)(struct sw_flow *flow, void *aux),
|
||||
void *aux)
|
||||
{
|
||||
unsigned int i, j, k;
|
||||
for (i = 0; i < 2; i++) {
|
||||
for (j = 0; j < table->n_buckets >> DP_L1_BITS; j++) {
|
||||
struct sw_flow **l2 = table->flows[i][j];
|
||||
for (k = 0; k < DP_L1_SIZE; k++) {
|
||||
struct sw_flow *flow = rcu_dereference(l2[k]);
|
||||
if (flow) {
|
||||
int error = callback(flow, aux);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int insert_flow(struct sw_flow *flow, void *new_table_)
|
||||
{
|
||||
struct dp_table *new_table = new_table_;
|
||||
struct sw_flow **buckets[2];
|
||||
int i;
|
||||
|
||||
find_buckets(new_table, &flow->key, buckets);
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (!*buckets[i]) {
|
||||
rcu_assign_pointer(*buckets[i], flow);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
WARN_ON_ONCE(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dp_free_table_rcu(struct rcu_head *rcu)
|
||||
{
|
||||
struct dp_table *table = container_of(rcu, struct dp_table, rcu);
|
||||
dp_table_destroy(table, 0);
|
||||
}
|
||||
|
||||
int dp_table_expand(struct datapath *dp)
|
||||
{
|
||||
struct dp_table *old_table = rcu_dereference(dp->table);
|
||||
struct dp_table *new_table = dp_table_create(old_table->n_buckets * 2);
|
||||
if (!new_table)
|
||||
return -ENOMEM;
|
||||
dp_table_foreach(old_table, insert_flow, new_table);
|
||||
rcu_assign_pointer(dp->table, new_table);
|
||||
call_rcu(&old_table->rcu, dp_free_table_rcu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dp_free_table_and_flows_rcu(struct rcu_head *rcu)
|
||||
{
|
||||
struct dp_table *table = container_of(rcu, struct dp_table, rcu);
|
||||
dp_table_destroy(table, 1);
|
||||
}
|
||||
|
||||
int dp_table_flush(struct datapath *dp)
|
||||
{
|
||||
struct dp_table *old_table = rcu_dereference(dp->table);
|
||||
struct dp_table *new_table = dp_table_create(DP_L1_SIZE);
|
||||
if (!new_table)
|
||||
return -ENOMEM;
|
||||
rcu_assign_pointer(dp->table, new_table);
|
||||
call_rcu(&old_table->rcu, dp_free_table_and_flows_rcu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct sw_flow **
|
||||
dp_table_lookup_for_insert(struct dp_table *table,
|
||||
const struct odp_flow_key *target)
|
||||
{
|
||||
struct sw_flow **buckets[2];
|
||||
struct sw_flow **empty_bucket = NULL;
|
||||
int i;
|
||||
|
||||
find_buckets(table, target, buckets);
|
||||
for (i = 0; i < 2; i++) {
|
||||
struct sw_flow *f = rcu_dereference(*buckets[i]);
|
||||
if (f) {
|
||||
if (!memcmp(&f->key, target, sizeof(struct odp_flow_key)))
|
||||
return buckets[i];
|
||||
} else if (!empty_bucket)
|
||||
empty_bucket = buckets[i];
|
||||
}
|
||||
return empty_bucket;
|
||||
}
|
||||
|
||||
int dp_table_delete(struct dp_table *table, struct sw_flow *target)
|
||||
{
|
||||
struct sw_flow **buckets[2];
|
||||
int i;
|
||||
|
||||
find_buckets(table, &target->key, buckets);
|
||||
for (i = 0; i < 2; i++) {
|
||||
struct sw_flow *flow = rcu_dereference(*buckets[i]);
|
||||
if (flow == target) {
|
||||
rcu_assign_pointer(*buckets[i], NULL);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -ENOENT;
|
||||
}
|
19
debian/.gitignore
vendored
Normal file
19
debian/.gitignore
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
*.debhelper
|
||||
*.debhelper.log
|
||||
*.substvars
|
||||
/control
|
||||
/corekeeper
|
||||
/files
|
||||
/nicira-switch
|
||||
/openvswitch
|
||||
/openvswitch-common
|
||||
/openvswitch-common.copyright
|
||||
/openvswitch-controller
|
||||
/openvswitch-datapath-source
|
||||
/openvswitch-dbg
|
||||
/openvswitch-monitor
|
||||
/openvswitch-pki
|
||||
/openvswitch-pki-server
|
||||
/openvswitch-switch
|
||||
/openvswitch-switch-config
|
||||
/openvswitch-switch.copyright
|
50
debian/automake.mk
vendored
Normal file
50
debian/automake.mk
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
EXTRA_DIST += \
|
||||
debian/changelog \
|
||||
debian/commands/reconfigure \
|
||||
debian/commands/update \
|
||||
debian/compat \
|
||||
debian/control \
|
||||
debian/control.modules.in \
|
||||
debian/copyright \
|
||||
debian/corekeeper.cron.daily \
|
||||
debian/corekeeper.init \
|
||||
debian/dirs \
|
||||
debian/ovs-switch-setup \
|
||||
debian/ovs-switch-setup.8 \
|
||||
debian/openvswitch-common.dirs \
|
||||
debian/openvswitch-common.install \
|
||||
debian/openvswitch-common.manpages \
|
||||
debian/openvswitch-controller.README.Debian \
|
||||
debian/openvswitch-controller.default \
|
||||
debian/openvswitch-controller.dirs \
|
||||
debian/openvswitch-controller.init \
|
||||
debian/openvswitch-controller.install \
|
||||
debian/openvswitch-controller.manpages \
|
||||
debian/openvswitch-controller.postinst \
|
||||
debian/openvswitch-datapath-module-_KVERS_.postinst.modules.in \
|
||||
debian/openvswitch-datapath-source.README.Debian \
|
||||
debian/openvswitch-datapath-source.copyright \
|
||||
debian/openvswitch-datapath-source.dirs \
|
||||
debian/openvswitch-datapath-source.install \
|
||||
debian/openvswitch-pki-server.apache2 \
|
||||
debian/openvswitch-pki-server.dirs \
|
||||
debian/openvswitch-pki-server.install \
|
||||
debian/openvswitch-pki-server.postinst \
|
||||
debian/openvswitch-pki.postinst \
|
||||
debian/openvswitch-switch-config.dirs \
|
||||
debian/openvswitch-switch-config.install \
|
||||
debian/openvswitch-switch-config.manpages \
|
||||
debian/openvswitch-switch-config.overrides \
|
||||
debian/openvswitch-switch-config.templates \
|
||||
debian/openvswitch-switch.README.Debian \
|
||||
debian/openvswitch-switch.dirs \
|
||||
debian/openvswitch-switch.init \
|
||||
debian/openvswitch-switch.install \
|
||||
debian/openvswitch-switch.logrotate \
|
||||
debian/openvswitch-switch.manpages \
|
||||
debian/openvswitch-switch.postinst \
|
||||
debian/openvswitch-switch.postrm \
|
||||
debian/openvswitch-switch.template \
|
||||
debian/po/POTFILES.in \
|
||||
debian/po/templates.pot \
|
||||
debian/rules
|
5
debian/changelog
vendored
Normal file
5
debian/changelog
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
openvswitch (0.90.0) unstable; urgency=low
|
||||
|
||||
* Development version.
|
||||
|
||||
-- Open vSwitch developers <ovs-dev@openvswitch.org> Mon, 19 Nov 2007 14:57:52 -0800
|
128
debian/commands/reconfigure
vendored
Executable file
128
debian/commands/reconfigure
vendored
Executable file
@ -0,0 +1,128 @@
|
||||
#! /usr/bin/perl
|
||||
|
||||
use POSIX;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
my $default = '/etc/default/openvswitch-switch';
|
||||
|
||||
my (%config) = load_config($default);
|
||||
if (@ARGV) {
|
||||
foreach my $arg (@ARGV) {
|
||||
my ($key, $value) = $arg =~ /^([^=]+)=(.*)/
|
||||
or die "bad argument '$arg'\n";
|
||||
if ($value ne '') {
|
||||
$config{$key} = $value;
|
||||
} else {
|
||||
delete $config{$key};
|
||||
}
|
||||
}
|
||||
save_config($default, %config);
|
||||
}
|
||||
print "$_=$config{$_}\n" foreach sort(keys(%config));
|
||||
|
||||
sub load_config {
|
||||
my ($file) = @_;
|
||||
|
||||
# Get the list of the variables that the shell sets automatically.
|
||||
my (%auto_vars) = read_vars("set -a && env");
|
||||
|
||||
# Get the variables from $default.
|
||||
my (%config) = read_vars("set -a && . '$default' && env");
|
||||
|
||||
# Subtract.
|
||||
delete @config{keys %auto_vars};
|
||||
|
||||
return %config;
|
||||
}
|
||||
|
||||
sub read_vars {
|
||||
my ($cmd) = @_;
|
||||
local @ENV;
|
||||
if (!open(VARS, '-|', $cmd)) {
|
||||
print STDERR "$cmd: failed to execute: $!\n";
|
||||
return ();
|
||||
}
|
||||
my (%config);
|
||||
while (<VARS>) {
|
||||
my ($var, $value) = /^([^=]+)=(.*)$/ or next;
|
||||
$config{$var} = $value;
|
||||
}
|
||||
close(VARS);
|
||||
return %config;
|
||||
}
|
||||
|
||||
sub shell_escape {
|
||||
local $_ = $_[0];
|
||||
if ($_ eq '') {
|
||||
return '""';
|
||||
} elsif (m&^[-a-zA-Z0-9:./%^_+,]*$&) {
|
||||
return $_;
|
||||
} else {
|
||||
s/'/'\\''/;
|
||||
return "'$_'";
|
||||
}
|
||||
}
|
||||
|
||||
sub shell_assign {
|
||||
my ($var, $value) = @_;
|
||||
return $var . '=' . shell_escape($value);
|
||||
}
|
||||
|
||||
sub save_config {
|
||||
my ($file, %config) = @_;
|
||||
my (@lines);
|
||||
if (open(FILE, '<', $file)) {
|
||||
@lines = <FILE>;
|
||||
chomp @lines;
|
||||
close(FILE);
|
||||
}
|
||||
|
||||
# Replace all existing variable assignments.
|
||||
for (my ($i) = 0; $i <= $#lines; $i++) {
|
||||
local $_ = $lines[$i];
|
||||
my ($var, $value) = /^\s*([^=#]+)=(.*)$/ or next;
|
||||
if (exists($config{$var})) {
|
||||
$lines[$i] = shell_assign($var, $config{$var});
|
||||
delete $config{$var};
|
||||
} else {
|
||||
$lines[$i] = "#$lines[$i]";
|
||||
}
|
||||
}
|
||||
|
||||
# Find a place to put any remaining variable assignments.
|
||||
VAR:
|
||||
for my $var (keys(%config)) {
|
||||
my $assign = shell_assign($var, $config{$var});
|
||||
|
||||
# Replace the last commented-out variable assignment to $var, if any.
|
||||
for (my ($i) = $#lines; $i >= 0; $i--) {
|
||||
local $_ = $lines[$i];
|
||||
if (/^\s*#\s*$var=/) {
|
||||
$lines[$i] = $assign;
|
||||
next VAR;
|
||||
}
|
||||
}
|
||||
|
||||
# Find a place to add the var: after the final commented line
|
||||
# just after a line that contains "$var:".
|
||||
for (my ($i) = 0; $i <= $#lines; $i++) {
|
||||
if ($lines[$i] =~ /^\s*#\s*$var:/) {
|
||||
for (my ($j) = $i + 1; $j <= $#lines; $j++) {
|
||||
if ($lines[$j] !~ /^\s*#/) {
|
||||
splice(@lines, $j, 0, $assign);
|
||||
next VAR;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Just append it.
|
||||
push(@lines, $assign);
|
||||
}
|
||||
|
||||
open(NEWFILE, '>', "$file.tmp") or die "$file.tmp: create: $!\n";
|
||||
print NEWFILE join('', map("$_\n", @lines));
|
||||
close(NEWFILE);
|
||||
rename("$file.tmp", $file) or die "$file.tmp: rename to $file: $!\n";
|
||||
}
|
4
debian/commands/update
vendored
Executable file
4
debian/commands/update
vendored
Executable file
@ -0,0 +1,4 @@
|
||||
#! /bin/sh
|
||||
set -e
|
||||
apt-get update -qy
|
||||
apt-get upgrade -qy
|
1
debian/compat
vendored
Normal file
1
debian/compat
vendored
Normal file
@ -0,0 +1 @@
|
||||
5
|
143
debian/control
vendored
Normal file
143
debian/control
vendored
Normal file
@ -0,0 +1,143 @@
|
||||
Source: openvswitch
|
||||
Section: net
|
||||
Priority: extra
|
||||
Maintainer: Open vSwitch developers <ovs-dev@openvswitch.org>
|
||||
Build-Depends: debhelper (>= 5), autoconf (>= 2.60), automake1.10, libssl-dev, pkg-config (>= 0.21), po-debconf, bzip2, openssl, libncurses5-dev, libpcre3-dev
|
||||
Standards-Version: 3.7.3
|
||||
|
||||
Package: openvswitch-datapath-source
|
||||
Architecture: all
|
||||
Depends: module-assistant, bzip2, debhelper (>= 5.0.37)
|
||||
Suggests: openvswitch-switch
|
||||
Description: Source code for Open vSwitch datapath Linux module
|
||||
This package provides the Open vSwitch datapath module source code
|
||||
that is needed by openvswitch-switch. The kernel module can be built
|
||||
from it using module-assistant or make-kpkg. README.Debian in this
|
||||
package provides further instructions.
|
||||
.
|
||||
Open vSwitch is a software-based Ethernet switch targeted at virtual
|
||||
servers.
|
||||
|
||||
Package: openvswitch-common
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, openssl
|
||||
Description: Open vSwitch common components
|
||||
openvswitch-common provides components required by both openvswitch-switch
|
||||
and openvswitch-controller.
|
||||
.
|
||||
Open vSwitch is a software-based Ethernet switch targeted at virtual
|
||||
servers.
|
||||
|
||||
Package: openvswitch-switch
|
||||
Architecture: any
|
||||
Suggests: openvswitch-datapath-module
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, openvswitch-common, dhcp3-client, module-init-tools, dmidecode, procps, debianutils
|
||||
Description: Open vSwitch switch implementations
|
||||
openvswitch-switch provides the userspace components and utilities for
|
||||
the Open vSwitch kernel-based switch.
|
||||
.
|
||||
Open vSwitch is a software-based Ethernet switch targeted at virtual
|
||||
servers.
|
||||
|
||||
Package: openvswitch-switch-config
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, openvswitch-switch, libwww-perl, libdigest-sha1-perl
|
||||
Description: Open vSwitch switch implementations
|
||||
openvswitch-switch-config provides a utility for interactively configuring
|
||||
the Open vSwitch switch provided in the openvswitch-switch package.
|
||||
.
|
||||
Open vSwitch is a software-based Ethernet switch targeted at virtual
|
||||
servers.
|
||||
|
||||
Package: openvswitch-switchui
|
||||
Architecture: any
|
||||
Recommends: openvswitch-switch
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, console-tools
|
||||
Description: Monitoring utility for OpenFlow switches
|
||||
The ovs-switchui utility included in this package provides a
|
||||
"front-panel display" to allow administrators to view the status of
|
||||
an OpenFlow switch at a glance.
|
||||
.
|
||||
The ezio-term utility, also included, provides a VT100-compatible
|
||||
terminal interface for EZIO3 (aka MTB-134) 16x2 LCD displays found on
|
||||
server appliances made by Portwell. It allows ovs-switchui to work
|
||||
with such displays.
|
||||
|
||||
Package: openvswitch-pki
|
||||
Architecture: all
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, openvswitch-common
|
||||
Description: Open vSwitch public key infrastructure
|
||||
openvswitch-pki provides PKI (public key infrastructure) support for
|
||||
Open vSwitch switches and controllers, reducing the risk of
|
||||
man-in-the-middle attacks on the Open vSwitch network infrastructure.
|
||||
.
|
||||
Open vSwitch is a software-based Ethernet switch targeted at virtual
|
||||
servers.
|
||||
|
||||
Package: openvswitch-pki-server
|
||||
Architecture: all
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}, openvswitch-pki, apache2
|
||||
Description: Open vSwitch public key infrastructure (HTTP server support)
|
||||
openvswitch-pki-server provides HTTP access to the Open vSwitch PKI (public
|
||||
key infrastructure) maintained on the local machine by the
|
||||
openvswitch-pki package. This HTTP access is needed for secure and
|
||||
convenient OpenFlow switch setup using the ovs-switch-setup program
|
||||
in the openvswitch-switch package.
|
||||
.
|
||||
Open vSwitch is a software-based Ethernet switch targeted at virtual
|
||||
servers.
|
||||
|
||||
Package: openvswitch-controller
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, openvswitch-common, openvswitch-pki
|
||||
Description: Open vSwitch controller implementation
|
||||
The Open vSwitch controller enables OpenFlow switches that connect to it
|
||||
to act as MAC-learning Ethernet switches.
|
||||
.
|
||||
Open vSwitch is a software-based Ethernet switch targeted at virtual
|
||||
servers.
|
||||
|
||||
Package: corekeeper
|
||||
Architecture: all
|
||||
Depends: tmpreaper
|
||||
Description: Core file centralizer and reaper
|
||||
The corekeeper package configures the system to dump all core files to
|
||||
/var/log/core. It also deletes core files older than 7 days.
|
||||
|
||||
Package: openvswitch-dbg
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}
|
||||
Description: Debug symbols for Open vSwitch packages
|
||||
This package contains the debug symbols for all the other openvswitch-*
|
||||
packages. Install it to debug one of them or to examine a core dump
|
||||
produced by one of them.
|
||||
|
||||
Package: openvswitch-monitor
|
||||
Architecture: any
|
||||
Recommends: openvswitch-switch
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
||||
Description: Monitor utility for Open vSwitch switches
|
||||
The ovs-monitor utility included in this package monitors the secure
|
||||
channel and datapath. If either become unresponsive, the switch is
|
||||
rebooted.
|
||||
|
||||
Package: openvswitch-wdt
|
||||
Architecture: any
|
||||
Recommends: openvswitch-switch
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
||||
Description: Watchdog utility for Open vSwitch switches
|
||||
The ovs-wdt program included in this package manages the hardware
|
||||
watchdog timer in switches based on the Portwell NAR-5520 hardware.
|
||||
|
||||
Package: nicira-switch
|
||||
Architecture: all
|
||||
Depends:
|
||||
openvswitch-common (= ${source:Version}),
|
||||
openvswitch-switch (= ${source:Version}),
|
||||
openvswitch-switchui (= ${source:Version}),
|
||||
openvswitch-datapath-module (= ${source:Version}),
|
||||
corekeeper, openvswitch-monitor, openvswitch-wdt
|
||||
Description: Metapackage for installing a Nicira Open vSwitch switch
|
||||
Installing this package will install everything needed for a Nicira
|
||||
Portwell-based Open vSwitch switch, including monitoring and the switch UI.
|
||||
|
20
debian/control.modules.in
vendored
Normal file
20
debian/control.modules.in
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
Source: openvswitch
|
||||
Section: net
|
||||
Priority: extra
|
||||
Maintainer: Open vSwitch developers <ovs-dev@openvswitch.org>
|
||||
Build-Depends: debhelper (>= 5.0.37)
|
||||
Standards-Version: 3.7.3
|
||||
|
||||
Package: openvswitch-datapath-module-_KVERS_
|
||||
Architecture: any
|
||||
Recommends: kernel-image-_KVERS_, openvswitch-switch
|
||||
Provides: openvswitch-datapath-module
|
||||
Description: Open vSwitch Linux datapath kernel module
|
||||
This package contains the Open vSwitch loadable datapath kernel modules for
|
||||
the kernel-image-_KVERS_ package.
|
||||
.
|
||||
If you compiled a custom kernel, you will most likely need to compile
|
||||
a custom version of this module as well. The
|
||||
openvswitch-datapath-source package has been provided for this
|
||||
purpose. Refer to README.Debian provided in that package for further
|
||||
instructions.
|
21
debian/copyright
vendored
Normal file
21
debian/copyright
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
Upstream Authors:
|
||||
|
||||
Nicira Networks
|
||||
|
||||
Copyright:
|
||||
|
||||
Copyright (C) 2008 Nicira Networks.
|
||||
|
||||
License:
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
5
debian/corekeeper.cron.daily
vendored
Executable file
5
debian/corekeeper.cron.daily
vendored
Executable file
@ -0,0 +1,5 @@
|
||||
#! /bin/sh
|
||||
|
||||
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
|
||||
|
||||
tmpreaper 7d --mtime --all /var/log/core
|
63
debian/corekeeper.init
vendored
Executable file
63
debian/corekeeper.init
vendored
Executable file
@ -0,0 +1,63 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Example init.d script with LSB support.
|
||||
#
|
||||
# Please read this init.d carefully and modify the sections to
|
||||
# adjust it to the program you want to run.
|
||||
#
|
||||
# Copyright (c) 2007 Javier Fernandez-Sanguino <jfs@debian.org>
|
||||
#
|
||||
# This is free software; you may 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,
|
||||
# or (at your option) any later version.
|
||||
#
|
||||
# This 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 with
|
||||
# the Debian operating system, in /usr/share/common-licenses/GPL; if
|
||||
# not, write to the Free Software Foundation, Inc., 59 Temple Place,
|
||||
# Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
### BEGIN INIT INFO
|
||||
# Provides: corekeeper
|
||||
# Required-Start:
|
||||
# Required-Stop:
|
||||
# Should-Start: $syslog
|
||||
# Should-Stop:
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: Configure core file dump location
|
||||
### END INIT INFO
|
||||
|
||||
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
|
||||
|
||||
. /lib/lsb/init-functions
|
||||
|
||||
set -e
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
log_daemon_msg "Initializing core dump location..."
|
||||
if echo "/var/log/core/core.%e.%t" > /proc/sys/kernel/core_pattern
|
||||
then
|
||||
log_progress_msg "success"
|
||||
log_end_msg 0
|
||||
exit 0
|
||||
else
|
||||
log_end_msg 1
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
stop|restart|force-reload|status|reload)
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
N=/etc/init.d/$NAME
|
||||
echo "Usage: $N {start|stop|restart|force-reload|status}" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
2
debian/dirs
vendored
Normal file
2
debian/dirs
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
usr/bin
|
||||
usr/sbin
|
1
debian/openvswitch-common.dirs
vendored
Normal file
1
debian/openvswitch-common.dirs
vendored
Normal file
@ -0,0 +1 @@
|
||||
var/log/openvswitch
|
3
debian/openvswitch-common.install
vendored
Normal file
3
debian/openvswitch-common.install
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
_debian/utilities/ovs-appctl usr/sbin
|
||||
_debian/utilities/ovs-parse-leaks usr/bin
|
||||
_debian/utilities/ovs-pki usr/sbin
|
2
debian/openvswitch-common.manpages
vendored
Normal file
2
debian/openvswitch-common.manpages
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
_debian/utilities/ovs-appctl.8
|
||||
_debian/utilities/ovs-pki.8
|
12
debian/openvswitch-controller.README.Debian
vendored
Normal file
12
debian/openvswitch-controller.README.Debian
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
README.Debian for openvswitch-controller
|
||||
-------------------------------------
|
||||
|
||||
* To (re)configure the controller, edit /etc/default/openvswitch-controller
|
||||
and run "/etc/init.d/openvswitch-controller restart".
|
||||
|
||||
* To enable OpenFlow switches to automatically discover the location
|
||||
of the controller, you must install and configure a DHCP server.
|
||||
The secchan(8) manpage (found in the openvswitch-switch package) gives
|
||||
a working example configuration file for the ISC DHCP server.
|
||||
|
||||
-- Ben Pfaff <blp@nicira.com>, Mon, 11 May 2009 13:26:38 -0700
|
29
debian/openvswitch-controller.default
vendored
Normal file
29
debian/openvswitch-controller.default
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
# This is a POSIX shell fragment -*- sh -*-
|
||||
|
||||
# LISTEN: What OpenFlow connection methods should the controller listen on?
|
||||
#
|
||||
# This is a space-delimited list of connection methods:
|
||||
#
|
||||
# * "pssl:[PORT]": Listen for SSL connections on the specified PORT
|
||||
# (default: 6633). The private key, certificate, and CA certificate
|
||||
# must be specified below.
|
||||
#
|
||||
# * "pctp:[PORT]": Listen for TCP connections on the specified PORT
|
||||
# (default: 6633). Not recommended for security reasons.
|
||||
#
|
||||
LISTEN="pssl:"
|
||||
|
||||
# PRIVKEY: Name of file containing controller's private key.
|
||||
# Required if SSL enabled.
|
||||
PRIVKEY=/etc/openvswitch-controller/privkey.pem
|
||||
|
||||
# CERT: Name of file containing certificate for private key.
|
||||
# Required if SSL enabled.
|
||||
CERT=/etc/openvswitch-controller/cert.pem
|
||||
|
||||
# CACERT: Name of file containing switch CA certificate.
|
||||
# Required if SSL enabled.
|
||||
CACERT=/etc/openvswitch-controller/cacert.pem
|
||||
|
||||
# Additional options to pass to controller, e.g. "--hub"
|
||||
DAEMON_OPTS=""
|
1
debian/openvswitch-controller.dirs
vendored
Normal file
1
debian/openvswitch-controller.dirs
vendored
Normal file
@ -0,0 +1 @@
|
||||
etc/openvswitch-controller
|
269
debian/openvswitch-controller.init
vendored
Executable file
269
debian/openvswitch-controller.init
vendored
Executable file
@ -0,0 +1,269 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2007, 2009 Javier Fernandez-Sanguino <jfs@debian.org>
|
||||
#
|
||||
# This is free software; you may 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,
|
||||
# or (at your option) any later version.
|
||||
#
|
||||
# This 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 with
|
||||
# the Debian operating system, in /usr/share/common-licenses/GPL; if
|
||||
# not, write to the Free Software Foundation, Inc., 59 Temple Place,
|
||||
# Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
### BEGIN INIT INFO
|
||||
# Provides: openvswitch-controller
|
||||
# Required-Start: $network $local_fs
|
||||
# Required-Stop:
|
||||
# Should-Start: $named
|
||||
# Should-Stop:
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: Open vSwitch controller
|
||||
### END INIT INFO
|
||||
|
||||
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
|
||||
|
||||
DAEMON=/usr/sbin/controller # Introduce the server's location here
|
||||
NAME=ovs-controller # Introduce the short server's name here
|
||||
DESC=ovs-controller # Introduce a short description here
|
||||
LOGDIR=/var/log/openvswitch # Log directory to use
|
||||
|
||||
PIDFILE=/var/run/$NAME.pid
|
||||
|
||||
test -x $DAEMON || exit 0
|
||||
|
||||
. /lib/lsb/init-functions
|
||||
|
||||
# Default options, these can be overriden by the information
|
||||
# at /etc/default/$NAME
|
||||
DAEMON_OPTS="" # Additional options given to the server
|
||||
|
||||
DODTIME=10 # Time to wait for the server to die, in seconds
|
||||
# If this value is set too low you might not
|
||||
# let some servers to die gracefully and
|
||||
# 'restart' will not work
|
||||
|
||||
LOGFILE=$LOGDIR/$NAME.log # Server logfile
|
||||
#DAEMONUSER= # User to run the daemons as. If this value
|
||||
# is set start-stop-daemon will chuid the server
|
||||
|
||||
# Include defaults if available
|
||||
default=/etc/default/openvswitch-controller
|
||||
if [ -f $default ] ; then
|
||||
. $default
|
||||
fi
|
||||
|
||||
# Check that the user exists (if we set a user)
|
||||
# Does the user exist?
|
||||
if [ -n "$DAEMONUSER" ] ; then
|
||||
if getent passwd | grep -q "^$DAEMONUSER:"; then
|
||||
# Obtain the uid and gid
|
||||
DAEMONUID=`getent passwd |grep "^$DAEMONUSER:" | awk -F : '{print $3}'`
|
||||
DAEMONGID=`getent passwd |grep "^$DAEMONUSER:" | awk -F : '{print $4}'`
|
||||
else
|
||||
log_failure_msg "The user $DAEMONUSER, required to run $NAME does not exist."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
set -e
|
||||
|
||||
running_pid() {
|
||||
# Check if a given process pid's cmdline matches a given name
|
||||
pid=$1
|
||||
name=$2
|
||||
[ -z "$pid" ] && return 1
|
||||
[ ! -d /proc/$pid ] && return 1
|
||||
cmd=`cat /proc/$pid/cmdline | tr "\000" "\n"|head -n 1 |cut -d : -f 1`
|
||||
# Is this the expected server
|
||||
[ "$cmd" != "$name" ] && return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
running() {
|
||||
# Check if the process is running looking at /proc
|
||||
# (works for all users)
|
||||
|
||||
# No pidfile, probably no daemon present
|
||||
[ ! -f "$PIDFILE" ] && return 1
|
||||
pid=`cat $PIDFILE`
|
||||
running_pid $pid $DAEMON || return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
start_server() {
|
||||
if [ -z "$LISTEN" ]; then
|
||||
echo "$default: No connection methods configured, controller disabled" >&2
|
||||
exit 0
|
||||
fi
|
||||
|
||||
SSL_OPTS=
|
||||
case $LISTEN in
|
||||
*ssl*)
|
||||
: ${PRIVKEY:=/etc/openvswitch-controller/privkey.pem}
|
||||
: ${CERT:=/etc/openvswitch-controller/cert.pem}
|
||||
: ${CACERT:=/etc/openvswitch-controller/cacert.pem}
|
||||
if test ! -e "$PRIVKEY" || test ! -e "$CERT" ||
|
||||
test ! -e "$CACERT"; then
|
||||
if test ! -e "$PRIVKEY"; then
|
||||
echo "$PRIVKEY: private key missing" >&2
|
||||
fi
|
||||
if test ! -e "$CERT"; then
|
||||
echo "$CERT: certificate for private key missing" >&2
|
||||
fi
|
||||
if test ! -e "$CACERT"; then
|
||||
echo "$CACERT: CA certificate missing" >&2
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
SSL_OPTS="--private-key=$PRIVKEY --certificate=$CERT --ca-cert=$CACERT"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Start the process using the wrapper
|
||||
if [ -z "$DAEMONUSER" ] ; then
|
||||
start-stop-daemon --start --pidfile $PIDFILE \
|
||||
--exec $DAEMON -- --detach --pidfile=$PIDFILE \
|
||||
$LISTEN $DAEMON_OPTS $SSL_OPTS
|
||||
errcode=$?
|
||||
else
|
||||
# if we are using a daemonuser then change the user id
|
||||
start-stop-daemon --start --quiet --pidfile $PIDFILE \
|
||||
--chuid $DAEMONUSER --exec $DAEMON -- \
|
||||
--detach --pidfile=$PIDFILE $LISTEN $DAEMON_OPTS \
|
||||
$SSL_OPTS
|
||||
errcode=$?
|
||||
fi
|
||||
return $errcode
|
||||
}
|
||||
|
||||
stop_server() {
|
||||
# Stop the process using the wrapper
|
||||
if [ -z "$DAEMONUSER" ] ; then
|
||||
start-stop-daemon --stop --quiet --pidfile $PIDFILE \
|
||||
--exec $DAEMON
|
||||
errcode=$?
|
||||
else
|
||||
# if we are using a daemonuser then look for process that match
|
||||
start-stop-daemon --stop --quiet --pidfile $PIDFILE \
|
||||
--user $DAEMONUSER --exec $DAEMON
|
||||
errcode=$?
|
||||
fi
|
||||
|
||||
return $errcode
|
||||
}
|
||||
|
||||
reload_server() {
|
||||
[ ! -f "$PIDFILE" ] && return 1
|
||||
pid=`cat $PIDFILE` # This is the daemon's pid
|
||||
# Send a SIGHUP
|
||||
kill -1 $pid
|
||||
return $?
|
||||
}
|
||||
|
||||
force_stop() {
|
||||
# Force the process to die killing it manually
|
||||
[ ! -e "$PIDFILE" ] && return
|
||||
if running ; then
|
||||
kill -15 $pid
|
||||
# Is it really dead?
|
||||
sleep "$DIETIME"s
|
||||
if running ; then
|
||||
kill -9 $pid
|
||||
sleep "$DIETIME"s
|
||||
if running ; then
|
||||
echo "Cannot kill $NAME (pid=$pid)!"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
rm -f $PIDFILE
|
||||
}
|
||||
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
log_daemon_msg "Starting $DESC " "$NAME"
|
||||
# Check if it's running first
|
||||
if running ; then
|
||||
log_progress_msg "apparently already running"
|
||||
log_end_msg 0
|
||||
exit 0
|
||||
fi
|
||||
if start_server && running ; then
|
||||
# It's ok, the server started and is running
|
||||
log_end_msg 0
|
||||
else
|
||||
# Either we could not start it or it is not running
|
||||
# after we did
|
||||
# NOTE: Some servers might die some time after they start,
|
||||
# this code does not try to detect this and might give
|
||||
# a false positive (use 'status' for that)
|
||||
log_end_msg 1
|
||||
fi
|
||||
;;
|
||||
stop)
|
||||
log_daemon_msg "Stopping $DESC" "$NAME"
|
||||
if running ; then
|
||||
# Only stop the server if we see it running
|
||||
stop_server
|
||||
log_end_msg $?
|
||||
else
|
||||
# If it's not running don't do anything
|
||||
log_progress_msg "apparently not running"
|
||||
log_end_msg 0
|
||||
exit 0
|
||||
fi
|
||||
;;
|
||||
force-stop)
|
||||
# First try to stop gracefully the program
|
||||
$0 stop
|
||||
if running; then
|
||||
# If it's still running try to kill it more forcefully
|
||||
log_daemon_msg "Stopping (force) $DESC" "$NAME"
|
||||
force_stop
|
||||
log_end_msg $?
|
||||
fi
|
||||
;;
|
||||
restart|force-reload)
|
||||
log_daemon_msg "Restarting $DESC" "$NAME"
|
||||
stop_server
|
||||
# Wait some sensible amount, some server need this
|
||||
[ -n "$DIETIME" ] && sleep $DIETIME
|
||||
start_server
|
||||
running
|
||||
log_end_msg $?
|
||||
;;
|
||||
status)
|
||||
|
||||
log_daemon_msg "Checking status of $DESC" "$NAME"
|
||||
if running ; then
|
||||
log_progress_msg "running"
|
||||
log_end_msg 0
|
||||
else
|
||||
log_progress_msg "apparently not running"
|
||||
log_end_msg 1
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
# Use this if the daemon cannot reload
|
||||
reload)
|
||||
log_warning_msg "Reloading $NAME daemon: not implemented, as the daemon"
|
||||
log_warning_msg "cannot re-read the config file (use restart)."
|
||||
;;
|
||||
*)
|
||||
N=/etc/init.d/$NAME
|
||||
echo "Usage: $N {start|stop|force-stop|restart|force-reload|status}" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
1
debian/openvswitch-controller.install
vendored
Normal file
1
debian/openvswitch-controller.install
vendored
Normal file
@ -0,0 +1 @@
|
||||
_debian/utilities/ovs-controller usr/sbin
|
1
debian/openvswitch-controller.manpages
vendored
Normal file
1
debian/openvswitch-controller.manpages
vendored
Normal file
@ -0,0 +1 @@
|
||||
_debian/utilities/ovs-controller.8
|
52
debian/openvswitch-controller.postinst
vendored
Executable file
52
debian/openvswitch-controller.postinst
vendored
Executable file
@ -0,0 +1,52 @@
|
||||
#!/bin/sh
|
||||
# postinst script for openvswitch-controller
|
||||
#
|
||||
# see: dh_installdeb(1)
|
||||
|
||||
set -e
|
||||
|
||||
# summary of how this script can be called:
|
||||
# * <postinst> `configure' <most-recently-configured-version>
|
||||
# * <old-postinst> `abort-upgrade' <new version>
|
||||
# * <conflictor's-postinst> `abort-remove' `in-favour' <package>
|
||||
# <new-version>
|
||||
# * <postinst> `abort-remove'
|
||||
# * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
|
||||
# <failed-install-package> <version> `removing'
|
||||
# <conflicting-package> <version>
|
||||
# for details, see http://www.debian.org/doc/debian-policy/ or
|
||||
# the debian-policy package
|
||||
|
||||
|
||||
case "$1" in
|
||||
configure)
|
||||
cd /etc/openvswitch-controller
|
||||
if ! test -e cacert.pem; then
|
||||
ln -s /usr/share/openvswitch/pki/switchca/cacert.pem cacert.pem
|
||||
fi
|
||||
if ! test -e privkey.pem || ! test -e cert.pem; then
|
||||
oldumask=$(umask)
|
||||
umask 077
|
||||
ovs-pki req+sign tmp controller >/dev/null
|
||||
mv tmp-privkey.pem privkey.pem
|
||||
mv tmp-cert.pem cert.pem
|
||||
mv tmp-req.pem req.pem
|
||||
chmod go+r cert.pem req.pem
|
||||
umask $oldumask
|
||||
fi
|
||||
;;
|
||||
|
||||
abort-upgrade|abort-remove|abort-deconfigure)
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "postinst called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
#DEBHELPER#
|
||||
|
||||
exit 0
|
||||
|
||||
|
25
debian/openvswitch-datapath-module-_KVERS_.postinst.modules.in
vendored
Executable file
25
debian/openvswitch-datapath-module-_KVERS_.postinst.modules.in
vendored
Executable file
@ -0,0 +1,25 @@
|
||||
#!/bin/sh
|
||||
# postinst script for #PACKAGE#
|
||||
#
|
||||
# see: dh_installdeb(1)
|
||||
|
||||
set -e
|
||||
|
||||
depmod -a
|
||||
|
||||
#DEBHELPER#
|
||||
|
||||
# If the switch is running, restart it. This ensures that we are using the
|
||||
# latest kernel module, because the init script will unload and reload the
|
||||
# module.
|
||||
#
|
||||
# (Ideally we'd only want to do this if this package corresponds to the
|
||||
# running kernel, but I don't know a reliable way to check.)
|
||||
INIT=/etc/init.d/openvswitch-switch
|
||||
if test -x $INIT && $INIT status; then
|
||||
$INIT restart || true
|
||||
fi
|
||||
|
||||
exit 0
|
||||
|
||||
|
31
debian/openvswitch-datapath-source.README.Debian
vendored
Normal file
31
debian/openvswitch-datapath-source.README.Debian
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
Open vSwitch for Debian
|
||||
----------------------
|
||||
|
||||
* How do I build this module the Debian way?
|
||||
|
||||
- Building with module-assistant:
|
||||
|
||||
$ module-assistant auto-install openvswitch
|
||||
or
|
||||
$ m-a a-i openvswitch
|
||||
|
||||
If kernel source or headers are in a non-standard directory, add
|
||||
the option -k /path/to/kernel/source with the correct path.
|
||||
|
||||
- Building with make-kpkg
|
||||
|
||||
$ cd /usr/src/
|
||||
$ tar jxvf openvswitch.tar.bz2
|
||||
$ cd /usr/src/kernel-source-2.6.9
|
||||
$ make-kpkg --added-modules=openvswitch modules
|
||||
|
||||
- Building without make-kpkg
|
||||
|
||||
$ cd /usr/src/
|
||||
$ tar jxvf openvswitch.tar.bz2
|
||||
$ cd modules/openvswitch
|
||||
$ fakeroot debian/rules kdist_image
|
||||
|
||||
If you run this as root, fakeroot is not needed.
|
||||
|
||||
-- Ben Pfaff <blp@nicira.com>, Mon, 11 May 2009 13:27:50 -0700
|
15
debian/openvswitch-datapath-source.copyright
vendored
Normal file
15
debian/openvswitch-datapath-source.copyright
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
Upstream Authors:
|
||||
|
||||
Nicira Networks
|
||||
|
||||
Copyright:
|
||||
|
||||
Copyright (C) 2008 Nicira Networks
|
||||
|
||||
License:
|
||||
|
||||
Files in the datapath/ and its sub-directories are covered under the GNU
|
||||
General Public License Version 2.
|
||||
|
||||
On Debian systems, the complete text of the GNU General
|
||||
Public License can be found in `/usr/share/common-licenses/GPL'.
|
1
debian/openvswitch-datapath-source.dirs
vendored
Normal file
1
debian/openvswitch-datapath-source.dirs
vendored
Normal file
@ -0,0 +1 @@
|
||||
usr/src/modules/openvswitch-datapath/debian
|
6
debian/openvswitch-datapath-source.install
vendored
Normal file
6
debian/openvswitch-datapath-source.install
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
debian/changelog usr/src/modules/openvswitch-datapath/debian
|
||||
debian/control usr/src/modules/openvswitch-datapath/debian
|
||||
debian/compat usr/src/modules/openvswitch-datapath/debian
|
||||
debian/*.modules.in usr/src/modules/openvswitch-datapath/debian
|
||||
debian/rules usr/src/modules/openvswitch-datapath/debian
|
||||
_debian/openvswitch.tar.gz usr/src/modules/openvswitch-datapath
|
27
debian/openvswitch-monitor.default
vendored
Normal file
27
debian/openvswitch-monitor.default
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
# This is a POSIX shell fragment -*- sh -*-
|
||||
|
||||
# To configure the Open vSwitch monitor package, modify the following.
|
||||
# Afterward, the monitor will be configured automatically at boot time.
|
||||
# It can be started immediately with
|
||||
# /etc/init.d/openvswitch-monitor start
|
||||
|
||||
# Defaults for initscript
|
||||
# sourced by /etc/init.d/openvswitch-monitor
|
||||
# installed at /etc/default/openvswitch-monitor by the maintainer scripts
|
||||
|
||||
# THRESHOLD: The number of failed attempts the monitor should make until
|
||||
# it reboots the system. A value of zero disables the monitor.
|
||||
THRESHOLD=3
|
||||
|
||||
# INTERVAL: The number of seconds to wait between probing secchan and
|
||||
# the datapath.
|
||||
INTERVAL=1
|
||||
|
||||
# LOG_FILE: File to log messages related to monitoring.
|
||||
LOG_FILE="/var/log/openvswitch/monitor"
|
||||
|
||||
# SWITCH_VCONN: The vconn used to connect to the switch (secchan).
|
||||
# The secchan must be configured to listen to this vconn. The default
|
||||
# here set is also listened to by default by the openvswitch-switch
|
||||
# package, so ordinarily there is no need to modify this.
|
||||
SWITCH_VCONN="/var/run/secchan.mgmt"
|
1
debian/openvswitch-monitor.dirs
vendored
Normal file
1
debian/openvswitch-monitor.dirs
vendored
Normal file
@ -0,0 +1 @@
|
||||
usr/sbin
|
174
debian/openvswitch-monitor.init
vendored
Executable file
174
debian/openvswitch-monitor.init
vendored
Executable file
@ -0,0 +1,174 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Example init.d script with LSB support.
|
||||
#
|
||||
# Please read this init.d carefully and modify the sections to
|
||||
# adjust it to the program you want to run.
|
||||
#
|
||||
# Copyright (c) 2007, 2009 Javier Fernandez-Sanguino <jfs@debian.org>
|
||||
#
|
||||
# This is free software; you may 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,
|
||||
# or (at your option) any later version.
|
||||
#
|
||||
# This 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 with
|
||||
# the Debian operating system, in /usr/share/common-licenses/GPL; if
|
||||
# not, write to the Free Software Foundation, Inc., 59 Temple Place,
|
||||
# Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
### BEGIN INIT INFO
|
||||
# Provides: openvswitch-monitor
|
||||
# Required-Start: $network $local_fs
|
||||
# Required-Stop:
|
||||
# Should-Start: $named $syslog openvswitch-switch
|
||||
# Should-Stop:
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: Open vSwitch switch monitor
|
||||
### END INIT INFO
|
||||
|
||||
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
|
||||
|
||||
DAEMON=/usr/sbin/ovs-monitor
|
||||
NAME=openvswitch-monitor
|
||||
DESC="Open vSwitch switch monitor"
|
||||
|
||||
PIDFILE=/var/run/$NAME.pid
|
||||
|
||||
test -x $DAEMON || exit 0
|
||||
|
||||
. /lib/lsb/init-functions
|
||||
|
||||
# Default options, these can be overriden by the information
|
||||
# at /etc/default/$NAME
|
||||
DAEMON_OPTS="" # Additional options given to the daemon
|
||||
|
||||
DODTIME=10 # Time to wait for the daemon to die, in seconds
|
||||
# If this value is set too low you might not
|
||||
# let some daemons to die gracefully and
|
||||
# 'restart' will not work
|
||||
|
||||
# Include defaults if available
|
||||
if [ -f /etc/default/$NAME ] ; then
|
||||
. /etc/default/$NAME
|
||||
fi
|
||||
|
||||
set -e
|
||||
|
||||
running_pid() {
|
||||
# Check if a given process pid's cmdline matches a given name
|
||||
pid=$1
|
||||
name=$2
|
||||
[ -z "$pid" ] && return 1
|
||||
[ ! -d /proc/$pid ] && return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
running() {
|
||||
# Check if the process is running looking at /proc
|
||||
# (works for all users)
|
||||
|
||||
# No pidfile, probably no daemon present
|
||||
[ ! -f "$PIDFILE" ] && return 1
|
||||
pid=`cat $PIDFILE`
|
||||
running_pid $pid $DAEMON || return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
start_daemon() {
|
||||
# Start the process using the wrapper
|
||||
if test $THRESHOLD != 0; then
|
||||
start-stop-daemon --start --quiet -m --background --pidfile $PIDFILE \
|
||||
--exec $DAEMON -- -c $THRESHOLD -i $INTERVAL -l $LOG_FILE \
|
||||
-s $SWITCH_VCONN $DAEMON_OPTS
|
||||
fi
|
||||
|
||||
# Wait up to 3 seconds for the daemon to start.
|
||||
for i in 1 2 3; do
|
||||
if running; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
}
|
||||
|
||||
stop_daemon() {
|
||||
start-stop-daemon -o --stop --pidfile $PIDFILE
|
||||
rm $PIDFILE
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
log_daemon_msg "Starting $DESC " "$NAME"
|
||||
# Check if it's running first
|
||||
if running ; then
|
||||
log_progress_msg "apparently already running"
|
||||
log_end_msg 0
|
||||
exit 0
|
||||
fi
|
||||
if start_daemon && running ; then
|
||||
# It's ok, the daemon started and is running
|
||||
log_end_msg 0
|
||||
else
|
||||
# Either we could not start it or it is not running
|
||||
# after we did
|
||||
# NOTE: Some daemons might die some time after they start,
|
||||
# this code does not try to detect this and might give
|
||||
# a false positive (use 'status' for that)
|
||||
log_end_msg 1
|
||||
fi
|
||||
;;
|
||||
stop)
|
||||
log_daemon_msg "Stopping $DESC" "$NAME"
|
||||
if running ; then
|
||||
# Only stop the daemon if we see it running
|
||||
stop_daemon
|
||||
log_end_msg $?
|
||||
else
|
||||
# If it's not running don't do anything
|
||||
log_progress_msg "apparently not running"
|
||||
log_end_msg 0
|
||||
exit 0
|
||||
fi
|
||||
;;
|
||||
restart|force-reload)
|
||||
log_daemon_msg "Restarting $DESC" "$NAME"
|
||||
if running ; then
|
||||
stop_daemon
|
||||
# Wait some sensible amount, some daemons need this
|
||||
[ -n "$DIETIME" ] && sleep $DIETIME
|
||||
fi
|
||||
start_daemon
|
||||
running
|
||||
log_end_msg $?
|
||||
;;
|
||||
status)
|
||||
log_daemon_msg "Checking status of $DESC" "$NAME"
|
||||
if running ; then
|
||||
log_progress_msg "running"
|
||||
log_end_msg 0
|
||||
else
|
||||
log_progress_msg "apparently not running"
|
||||
log_end_msg 1
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
# Use this if the daemon cannot reload
|
||||
reload)
|
||||
log_warning_msg "Reloading $NAME daemon: not implemented, as the daemon"
|
||||
log_warning_msg "cannot re-read the config file (use restart)."
|
||||
;;
|
||||
*)
|
||||
N=/etc/init.d/$NAME
|
||||
echo "Usage: $N {start|stop|restart|force-reload|status}" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user