Merge branch 'mainstream'
authorGiuseppe Lettieri <g.lettieri@iet.unipi.it>
Sat, 7 Sep 2013 13:48:06 +0000 (15:48 +0200)
committerGiuseppe Lettieri <g.lettieri@iet.unipi.it>
Sat, 7 Sep 2013 13:48:06 +0000 (15:48 +0200)
127 files changed:
AUTHORS
FAQ
INSTALL.RHEL
NEWS
OPENFLOW-1.1+
README
SubmittingPatches
acinclude.m4
configure.ac
datapath/Modules.mk
datapath/actions.c
datapath/checksum.c [deleted file]
datapath/checksum.h [deleted file]
datapath/compat.h
datapath/datapath.c
datapath/datapath.h
datapath/dp_notify.c
datapath/flow.c
datapath/flow.h
datapath/linux/Modules.mk
datapath/linux/compat/addrconf_core-openvswitch.c [deleted file]
datapath/linux/compat/genetlink-openvswitch.c
datapath/linux/compat/include/linux/dmi.h [deleted file]
datapath/linux/compat/include/linux/if.h
datapath/linux/compat/include/linux/if_ether.h
datapath/linux/compat/include/linux/inetdevice.h [deleted file]
datapath/linux/compat/include/linux/kernel.h
datapath/linux/compat/include/linux/kobject.h [deleted file]
datapath/linux/compat/include/linux/lockdep.h [deleted file]
datapath/linux/compat/include/linux/mutex.h [deleted file]
datapath/linux/compat/include/linux/netdevice.h
datapath/linux/compat/include/linux/netfilter_bridge.h [deleted file]
datapath/linux/compat/include/linux/netfilter_ipv4.h [deleted file]
datapath/linux/compat/include/linux/netlink.h
datapath/linux/compat/include/linux/rculist.h
datapath/linux/compat/include/linux/reciprocal_div.h [deleted file]
datapath/linux/compat/include/linux/rtnetlink.h
datapath/linux/compat/include/linux/skbuff.h
datapath/linux/compat/include/linux/slab.h [deleted file]
datapath/linux/compat/include/linux/timer.h [deleted file]
datapath/linux/compat/include/net/checksum.h
datapath/linux/compat/include/net/genetlink.h
datapath/linux/compat/include/net/ip.h
datapath/linux/compat/include/net/net_namespace.h
datapath/linux/compat/include/net/netlink.h
datapath/linux/compat/include/net/netns/generic.h [deleted file]
datapath/linux/compat/include/net/protocol.h [deleted file]
datapath/linux/compat/include/net/route.h [deleted file]
datapath/linux/compat/include/net/sctp/checksum.h
datapath/linux/compat/include/net/sock.h [deleted file]
datapath/linux/compat/include/net/vxlan.h
datapath/linux/compat/ip_output-openvswitch.c [deleted file]
datapath/linux/compat/ip_tunnels_core.c
datapath/linux/compat/kmemdup.c [deleted file]
datapath/linux/compat/net_namespace.c
datapath/linux/compat/netdevice.c
datapath/linux/compat/reciprocal_div.c
datapath/linux/compat/skbuff-openvswitch.c
datapath/linux/compat/time.c [deleted file]
datapath/linux/compat/utils.c [new file with mode: 0644]
datapath/linux/compat/vxlan.c
datapath/vlan.c [deleted file]
datapath/vlan.h
datapath/vport-gre.c
datapath/vport-internal_dev.c
datapath/vport-lisp.c
datapath/vport-netdev.c
datapath/vport-vxlan.c
datapath/vport.c
debian/changelog
debian/copyright.in
include/openflow/openflow-1.1.h
include/openflow/openflow-1.2.h
include/openflow/openflow-1.3.h
include/openflow/openflow-common.h
include/openvswitch/automake.mk
include/openvswitch/datapath-compat.h [deleted file]
lib/cfm.c
lib/daemon.c
lib/dpif-linux.c
lib/flow.c
lib/learning-switch.c
lib/list.c
lib/list.h
lib/netdev-dummy.c
lib/netlink-socket.c
lib/netlink-socket.h
lib/odp-execute.c
lib/odp-util.c
lib/ofp-actions.c
lib/ofp-actions.h
lib/ofp-msgs.h
lib/ofp-parse.c
lib/ofp-parse.h
lib/ofp-print.c
lib/ofp-util.c
lib/ofp-util.def
lib/ofp-util.h
lib/rconn.c
lib/timeval.c
lib/timeval.h
lib/util.c
m4/openvswitch.m4
ofproto/ofproto-dpif-mirror.c
ofproto/ofproto-dpif-upcall.c
ofproto/ofproto-dpif-upcall.h
ofproto/ofproto-dpif-xlate.c
ofproto/ofproto-dpif-xlate.h
ofproto/ofproto-dpif.c
ofproto/ofproto-dpif.h
ofproto/ofproto-provider.h
ofproto/ofproto.c
rhel/automake.mk
rhel/kmodtool-openvswitch-el5.sh [deleted file]
rhel/openvswitch-kmod-rhel5.spec.in [deleted file]
tests/automake.mk
tests/learn.at
tests/ofp-print.at
tests/ofproto-dpif.at
tests/test-lockfile.c
tests/test-timeval.c [deleted file]
tests/testsuite.at
tests/timeval.at [deleted file]
utilities/ovs-ofctl.8.in
utilities/ovs-ofctl.c
vswitchd/bridge.c
vswitchd/vswitch.xml

diff --git a/AUTHORS b/AUTHORS
index af34bfe..a708fb2 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -66,6 +66,7 @@ Mehak Mahajan           mmahajan@nicira.com
 Murphy McCauley         murphy.mccauley@gmail.com
 Natasha Gude            natasha@nicira.com
 Neil McKee              neil.mckee@inmon.com
+Neil Zhu                zhuj@centecnetworks.com
 Paraneetharan Chandrasekaran    paraneetharanc@gmail.com
 Paul Fazzone            pfazzone@nicira.com
 Paul Ingram             paul@nicira.com
diff --git a/FAQ b/FAQ
index 75d9007..7181484 100644 (file)
--- a/FAQ
+++ b/FAQ
@@ -27,7 +27,7 @@ A: Open vSwitch is a production quality open source software switch
 Q: What virtualization platforms can use Open vSwitch?
 
 A: Open vSwitch can currently run on any Linux-based virtualization
-   platform (kernel 2.6.18 and newer), including: KVM, VirtualBox, Xen,
+   platform (kernel 2.6.32 and newer), including: KVM, VirtualBox, Xen,
    Xen Cloud Platform, XenServer. As of Linux 3.3 it is part of the
    mainline kernel.  The bulk of the code is written in platform-
    independent C and is easily ported to other environments.  We welcome
@@ -148,13 +148,13 @@ A: The following table lists the Linux kernel versions against which the
        1.9.x      2.6.18 to 3.8
        1.10.x     2.6.18 to 3.8
        1.11.x     2.6.18 to 3.8
-       1.12.x     2.6.18 to 3.10
+       2.x        2.6.32 to 3.10
 
    Open vSwitch userspace should also work with the Linux kernel module
    built into Linux 3.3 and later.
 
    Open vSwitch userspace is not sensitive to the Linux kernel version.
-   It should build against almost any kernel, certainly against 2.6.18
+   It should build against almost any kernel, certainly against 2.6.32
    and later.
 
 Q: What Linux kernel versions does IPFIX flow monitoring work with?
@@ -250,6 +250,40 @@ A: The following commands configure br0 with eth0 and tap0 as trunk
 
        ovs-vsctl clear bridge br0 mirrors
 
+Q: Does Open vSwitch support configuring a port in promiscuous mode?
+
+A: Yes.  How you configure it depends on what you mean by "promiscuous
+   mode":
+
+      - Conventionally, "promiscuous mode" is a feature of a network
+        interface card.  Ordinarily, a NIC passes to the CPU only the
+        packets actually destined to its host machine.  It discards
+        the rest to avoid wasting memory and CPU cycles.  When
+        promiscuous mode is enabled, however, it passes every packet
+        to the CPU.  On an old-style shared-media or hub-based
+        network, this allows the host to spy on all packets on the
+        network.  But in the switched networks that are almost
+        everywhere these days, promiscuous mode doesn't have much
+        effect, because few packets not destined to a host are
+        delivered to the host's NIC.
+
+        This form of promiscuous mode is configured in the guest OS of
+        the VMs on your bridge, e.g. with "ifconfig".
+
+      - The VMware vSwitch uses a different definition of "promiscuous
+        mode".  When you configure promiscuous mode on a VMware vNIC,
+        the vSwitch sends a copy of every packet received by the
+        vSwitch to that vNIC.  That has a much bigger effect than just
+        enabling promiscuous mode in a guest OS.  Rather than getting
+        a few stray packets for which the switch does not yet know the
+        correct destination, the vNIC gets every packet.  The effect
+        is similar to replacing the vSwitch by a virtual hub.
+
+        This "promiscuous mode" is what switches normally call "port
+        mirroring" or "SPAN".  For information on how to configure
+        SPAN, see "How do I configure a port as a SPAN port, that is,
+        enable mirroring of all traffic to that port?"
+
 Q: How do I configure a VLAN as an RSPAN VLAN, that is, enable
    mirroring of all traffic to that VLAN?
 
index a698fae..cbb91de 100644 (file)
@@ -68,24 +68,7 @@ RHEL.  On RHEL 5, the default RPM source directory is
    then the kernel-devel package is missing or buggy.  Go back to step
    1 or 2 and fix the problem.
 
-7a. On RHEL 5, to build the Open vSwitch kernel module, copy
-    rhel/kmodtool-openvswitch-el5.sh into the RPM source directory and
-    run:
-
-       rpmbuild -bb --target=i686-unknown-linux \
-               rhel/openvswitch-kmod-rhel5.spec
-
-    You might have to specify a kernel version, e.g.:
-
-       rpmbuild -bb -D "kversion 2.6.18-238.12.1.el5" \
-               --target=i686-unknown-linux \
-               rhel/openvswitch-kmod-rhel5.spec
-
-    This produces a "kmod-openvswitch" RPM for each kernel variant,
-    which is usually: "kmod-openvswitch", "kmod-openvswitch-xen", and
-    "kmod-openvswitch-PAE".
-
-7b. On RHEL 6, to build the Open vSwitch kernel module, copy
+7. On RHEL 6, to build the Open vSwitch kernel module, copy
     rhel/openvswitch-kmod.files into the RPM source directory and run:
 
        rpmbuild -bb rhel/openvswitch-kmod-rhel6.spec
diff --git a/NEWS b/NEWS
index ef97b04..09c98eb 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,20 +1,25 @@
-post-v1.12.0
+Post-v2.0.0
 ---------------------
-    - OpenFlow:
-      * Support matching, rewriting SCTP ports
 
 
-v1.12.0 - xx xxx xxxx
+v2.0.0 - xx xxx xxxx
 ---------------------
     - OpenFlow:
       * Experimental support for OpenFlow 1.1 (in addition to 1.2 and
         1.3, which had experimental support in 1.10).
+      * Experimental protocol support for OpenFlow 1.1+ groups.  This
+        does not yet include an implementation in the Open vSwitch
+        software switch.
+      * Experimental protocol support for OpenFlow 1.2+ meters.  This
+        does not yet include an implementation in the Open vSwitch
+        software switch.
       * New support for matching outer source and destination IP address
         of tunneled packets, for tunnel ports configured with the newly
         added "remote_ip=flow" and "local_ip=flow" options.
       * Support for matching on metadata 'pkt_mark' for interacting with
         other system components. On Linux this corresponds to the skb
         mark.
+      * Support matching, rewriting SCTP ports
     - The Interface table in the database has a new "ifindex" column to
       report the interface's OS-assigned ifindex.
     - New "check-oftest" Makefile target for running OFTest against Open
@@ -27,10 +32,12 @@ v1.12.0 - xx xxx xxxx
     - Support for Linux kernels up to 3.10
     - ovs-ofctl:
       * New "ofp-parse" for printing OpenFlow messages read from a file.
+      * New commands for OpenFlow 1.1+ groups.
     - Added configurable flow caching support to IPFIX exporter.
+    - Dropped support for Linux pre-2.6.32.
 
 
-v1.11.0 - xx xxx xxxx
+v1.11.0 - 28 Aug 2013
 ---------------------
     - Support for megaflows, which allows wildcarding in the kernel (and
       any dpif implementation that supports wildcards).  Depending on
index 753dbba..7a75c44 100644 (file)
@@ -69,18 +69,6 @@ probably incomplete.
       behavior does not change.
       [required for OF1.1 and OF1.2]
 
-    * Flow table stats (OFPST_TABLE).
-
-        * Reference count (active entries)
-          [implemented]
-          [required for OF1.1 and OF1.2]
-
-        * Packet Lookups
-          [required for OF1.1; optional for OF1.2]
-
-        * Packet Matches
-          [required for OF1.1; optional for OF1.2]
-
     * MPLS.  Simon Horman maintains a patch series that adds this
       feature.  This is partially merged.
       [optional for OF1.1+]
@@ -113,17 +101,10 @@ probably incomplete.
 OpenFlow 1.2
 ------------
 
-OpenFlow 1.2 support requires OpenFlow 1.1 as a prerequisite, plus the
-following additional work.  (This is based on the change log at the
-end of the OF1.2 spec.  I didn't compare the specs carefully yet.)
-
-    * OFPT_FLOW_MOD:
-
-        * Add ability to delete flow in all tables.
-          [required for OF1.2+]
-
-        * Update DESIGN to describe OF1.2 behavior also.
-          [required for OF1.2+]
+OpenFlow 1.2 support requires OpenFlow 1.1 as a prerequisite. All the
+additional work specific to Openflow 1.2 are complete.  (This is based
+on the change log at the end of the OF1.2 spec.  I didn't compare the
+specs carefully yet.)
 
 OpenFlow 1.3
 ------------
@@ -187,9 +168,6 @@ didn't compare the specs carefully yet.)
       optimization in some cases for the software switch.
       [optional for OF1.3+]
 
-    * Duration Statistics
-      - New for Per Port, Per Queue, Per Group
-      [required for v1.3+]
 
 How to contribute
 -----------------
diff --git a/README b/README
index a57bb62..db1e3ef 100644 (file)
--- a/README
+++ b/README
@@ -30,7 +30,7 @@ vSwitch supports the following features:
     * Transactional configuration database with C and Python bindings
     * High-performance forwarding using a Linux kernel module
 
-The included Linux kernel module supports Linux 2.6.18 and up, with
+The included Linux kernel module supports Linux 2.6.32 and up, with
 testing focused on 2.6.32 with Centos and Xen patches.  Open vSwitch
 also has special support for Citrix XenServer and Red Hat Enterprise
 Linux hosts.
index cb585d0..9b3dd9e 100644 (file)
@@ -32,7 +32,7 @@ Testing is also important:
 
         - A patch that modifies Linux kernel code should be at least
           build-tested on various Linux kernel versions before
-          submission.  I suggest versions 2.6.18, 2.6.27, and whatever
+          submission.  I suggest versions 2.6.32 and whatever
           the current latest release version is at the time.
 
         - A patch that modifies the ofproto or vswitchd code should be
index 73ee5ce..071fe54 100644 (file)
@@ -134,14 +134,16 @@ AC_DEFUN([OVS_CHECK_LINUX], [
     AC_MSG_RESULT([$kversion])
 
     if test "$version" -ge 3; then
-       : # Linux 3.x
-    elif test "$version" = 2 && test "$patchlevel" -ge 6; then
-       : # Linux 2.6.x
+       if test "$version" = 3 && test "$patchlevel" -le 10; then
+          : # Linux 3.x
+       else
+         AC_ERROR([Linux kernel in $KBUILD is version $kversion, but version newer than 3.10.x is not supported])
+       fi
     else
-       if test "$KBUILD" = "$KSRC"; then
-         AC_ERROR([Linux kernel in $KBUILD is version $kversion, but version 2.6 or later is required])
+       if test "$version" -le 1 || test "$patchlevel" -le 5 || test "$sublevel" -le 31; then
+         AC_ERROR([Linux kernel in $KBUILD is version $kversion, but version 2.6.32 or later is required])
        else
-         AC_ERROR([Linux kernel in build tree $KBUILD (source tree $KSRC) is version $kversion, but version 2.6 or later is required])
+         : # Linux 2.6.x
        fi
     fi
     if (test ! -e "$KBUILD"/include/linux/version.h && \
@@ -258,9 +260,6 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [
   OVS_GREP_IFELSE([$KSRC/include/linux/skbuff.h], [skb_reset_mac_len])
   OVS_GREP_IFELSE([$KSRC/include/linux/skbuff.h], [skb_unclone])
 
-  OVS_GREP_IFELSE([$KSRC/include/linux/string.h], [kmemdup], [],
-                  [OVS_GREP_IFELSE([$KSRC/include/linux/slab.h], [kmemdup])])
-
   OVS_GREP_IFELSE([$KSRC/include/linux/types.h], [bool],
                   [OVS_DEFINE([HAVE_BOOL_TYPE])])
   OVS_GREP_IFELSE([$KSRC/include/linux/types.h], [__wsum],
@@ -272,7 +271,6 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [
   OVS_GREP_IFELSE([$KSRC/include/net/checksum.h], [csum_unfold])
 
   OVS_GREP_IFELSE([$KSRC/include/net/genetlink.h], [parallel_ops])
-  OVS_GREP_IFELSE([$KSRC/include/net/netlink.h], [NLA_NUL_STRING])
   OVS_GREP_IFELSE([$KSRC/include/net/netlink.h], [nla_get_be16])
   OVS_GREP_IFELSE([$KSRC/include/net/netlink.h], [nla_put_be16])
   OVS_GREP_IFELSE([$KSRC/include/net/netlink.h], [nla_put_be32])
index 7988633..d6596f9 100644 (file)
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 AC_PREREQ(2.64)
-AC_INIT(openvswitch, 1.12.90, ovs-bugs@openvswitch.org)
+AC_INIT(openvswitch, 2.0.90, ovs-bugs@openvswitch.org)
 AC_CONFIG_SRCDIR([datapath/datapath.c])
 AC_CONFIG_MACRO_DIR([m4])
 AC_CONFIG_AUX_DIR([build-aux])
@@ -80,7 +80,6 @@ OVS_CHECK_LINKER_SECTIONS
 OVS_CHECK_XENSERVER_VERSION
 OVS_CHECK_GROFF
 OVS_CHECK_GNU_MAKE
-OVS_CHECK_CACHE_TIME
 OVS_CHECK_TLS
 OVS_CHECK_GCC4_ATOMICS
 OVS_CHECK_ATOMIC_ALWAYS_LOCK_FREE(1)
index ccf4dfa..7ddf79c 100644 (file)
@@ -8,11 +8,9 @@ dist_modules = $(both_modules) # Modules to distribute
 
 openvswitch_sources = \
        actions.c \
-       checksum.c \
        datapath.c \
        dp_notify.c \
        flow.c \
-       vlan.c \
        vport.c \
        vport-gre.c \
        vport-internal_dev.c \
@@ -21,7 +19,6 @@ openvswitch_sources = \
        vport-vxlan.c
 
 openvswitch_headers = \
-       checksum.h \
        compat.h \
        datapath.h \
        flow.h \
index fa4b904..30ea1d2 100644 (file)
@@ -34,7 +34,6 @@
 #include <net/dsfield.h>
 #include <net/sctp/checksum.h>
 
-#include "checksum.h"
 #include "datapath.h"
 #include "vlan.h"
 #include "vport.h"
@@ -60,7 +59,7 @@ static int __pop_vlan_tci(struct sk_buff *skb, __be16 *current_tci)
        if (unlikely(err))
                return err;
 
-       if (get_ip_summed(skb) == OVS_CSUM_COMPLETE)
+       if (skb->ip_summed == CHECKSUM_COMPLETE)
                skb->csum = csum_sub(skb->csum, csum_partial(skb->data
                                        + (2 * ETH_ALEN), VLAN_HLEN, 0));
 
@@ -117,7 +116,7 @@ static int push_vlan(struct sk_buff *skb, const struct ovs_action_push_vlan *vla
                if (!__vlan_put_tag(skb, skb->vlan_proto, current_tag))
                        return -ENOMEM;
 
-               if (get_ip_summed(skb) == OVS_CSUM_COMPLETE)
+               if (skb->ip_summed == CHECKSUM_COMPLETE)
                        skb->csum = csum_add(skb->csum, csum_partial(skb->data
                                        + (2 * ETH_ALEN), VLAN_HLEN, 0));
 
@@ -134,16 +133,12 @@ static int set_eth_addr(struct sk_buff *skb,
        if (unlikely(err))
                return err;
 
-       if (get_ip_summed(skb) == OVS_CSUM_COMPLETE)
-               skb->csum = csum_sub(skb->csum, csum_partial(eth_hdr(skb),
-                                                            ETH_ALEN * 2, 0));
+       skb_postpull_rcsum(skb, eth_hdr(skb), ETH_ALEN * 2);
 
        memcpy(eth_hdr(skb)->h_source, eth_key->eth_src, ETH_ALEN);
        memcpy(eth_hdr(skb)->h_dest, eth_key->eth_dst, ETH_ALEN);
 
-       if (get_ip_summed(skb) == OVS_CSUM_COMPLETE)
-               skb->csum = csum_add(skb->csum, csum_partial(eth_hdr(skb),
-                                                            ETH_ALEN * 2, 0));
+       ovs_skb_postpush_rcsum(skb, eth_hdr(skb), ETH_ALEN * 2);
 
        return 0;
 }
@@ -161,8 +156,7 @@ static void set_ip_addr(struct sk_buff *skb, struct iphdr *nh,
                if (likely(transport_len >= sizeof(struct udphdr))) {
                        struct udphdr *uh = udp_hdr(skb);
 
-                       if (uh->check ||
-                           get_ip_summed(skb) == OVS_CSUM_PARTIAL) {
+                       if (uh->check || skb->ip_summed == CHECKSUM_PARTIAL) {
                                inet_proto_csum_replace4(&uh->check, skb,
                                                         *addr, new_addr, 1);
                                if (!uh->check)
@@ -189,8 +183,7 @@ static void update_ipv6_checksum(struct sk_buff *skb, u8 l4_proto,
                if (likely(transport_len >= sizeof(struct udphdr))) {
                        struct udphdr *uh = udp_hdr(skb);
 
-                       if (uh->check ||
-                           get_ip_summed(skb) == OVS_CSUM_PARTIAL) {
+                       if (uh->check || skb->ip_summed == CHECKSUM_PARTIAL) {
                                inet_proto_csum_replace16(&uh->check, skb,
                                                          addr, new_addr, 1);
                                if (!uh->check)
@@ -311,7 +304,7 @@ static void set_udp_port(struct sk_buff *skb, __be16 *port, __be16 new_port)
 {
        struct udphdr *uh = udp_hdr(skb);
 
-       if (uh->check && get_ip_summed(skb) != OVS_CSUM_PARTIAL) {
+       if (uh->check && skb->ip_summed != CHECKSUM_PARTIAL) {
                set_tp_port(skb, port, new_port, &uh->check);
 
                if (!uh->check)
@@ -478,7 +471,7 @@ static int execute_set_action(struct sk_buff *skb,
                break;
 
        case OVS_KEY_ATTR_SKB_MARK:
-               skb_set_mark(skb, nla_get_u32(nested_attr));
+               skb->mark = nla_get_u32(nested_attr);
                break;
 
        case OVS_KEY_ATTR_IPV4_TUNNEL:
diff --git a/datapath/checksum.c b/datapath/checksum.c
deleted file mode 100644 (file)
index 5146c65..0000000
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- * Copyright (c) 2007-2011 Nicira, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/tcp.h>
-#include <linux/udp.h>
-
-#include "checksum.h"
-#include "datapath.h"
-
-#ifdef NEED_CSUM_NORMALIZE
-
-#if defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID)
-/* This code is based on skb_checksum_setup() from Xen's net/dev/core.c.  We
- * can't call this function directly because it isn't exported in all
- * versions. */
-static int vswitch_skb_checksum_setup(struct sk_buff *skb)
-{
-       struct iphdr *iph;
-       unsigned char *th;
-       int err = -EPROTO;
-       __u16 csum_start, csum_offset;
-
-       if (!skb->proto_csum_blank)
-               return 0;
-
-       if (skb->protocol != htons(ETH_P_IP))
-               goto out;
-
-       if (!pskb_may_pull(skb, skb_network_header(skb) + sizeof(struct iphdr) - skb->data))
-               goto out;
-
-       iph = ip_hdr(skb);
-       th = skb_network_header(skb) + 4 * iph->ihl;
-
-       csum_start = th - skb->head;
-       switch (iph->protocol) {
-       case IPPROTO_TCP:
-               csum_offset = offsetof(struct tcphdr, check);
-               break;
-       case IPPROTO_UDP:
-               csum_offset = offsetof(struct udphdr, check);
-               break;
-       default:
-               if (net_ratelimit())
-                       pr_err("Attempting to checksum a non-TCP/UDP packet, "
-                              "dropping a protocol %d packet",
-                              iph->protocol);
-               goto out;
-       }
-
-       if (!pskb_may_pull(skb, th + csum_offset + 2 - skb->data))
-               goto out;
-
-       skb->proto_csum_blank = 0;
-       set_ip_summed(skb, OVS_CSUM_PARTIAL);
-       set_skb_csum_pointers(skb, csum_start, csum_offset);
-
-       err = 0;
-
-out:
-       return err;
-}
-#else
-static int vswitch_skb_checksum_setup(struct sk_buff *skb)
-{
-       return 0;
-}
-#endif /* not Xen old style checksums */
-
-/*
- *     compute_ip_summed - map external checksum state onto OVS representation
- *
- * @skb: Packet to manipulate.
- * @xmit: Whether we were on transmit path of network stack.  For example,
- *       this is true for the internal dev vport because it receives skbs
- *       that passed through dev_queue_xmit() but false for the netdev vport
- *       because its packets come from netif_receive_skb().
- *
- * Older kernels (and various versions of Xen) were not explicit enough about
- * checksum offload parameters and rely on a combination of context and
- * non standard fields.  This deals with all those variations so that we
- * can internally manipulate checksum offloads without worrying about kernel
- * version.
- *
- * Types of checksums that we can receive (these all refer to L4 checksums):
- * 1. CHECKSUM_NONE: Device that did not compute checksum, contains full
- *     (though not verified) checksum in packet but not in skb->csum.  Packets
- *     from the bridge local port will also have this type.
- * 2. CHECKSUM_COMPLETE (CHECKSUM_HW): Good device that computes checksums,
- *     also the GRE module.  This is the same as CHECKSUM_NONE, except it has
- *     a valid skb->csum.  Importantly, both contain a full checksum (not
- *     verified) in the packet itself.  The only difference is that if the
- *     packet gets to L4 processing on this machine (not in DomU) we won't
- *     have to recompute the checksum to verify.  Most hardware devices do not
- *     produce packets with this type, even if they support receive checksum
- *     offloading (they produce type #5).
- * 3. CHECKSUM_PARTIAL (CHECKSUM_HW): Packet without full checksum and needs to
- *     be computed if it is sent off box.  Unfortunately on earlier kernels,
- *     this case is impossible to distinguish from #2, despite having opposite
- *     meanings.  Xen adds an extra field on earlier kernels (see #4) in order
- *     to distinguish the different states.
- * 4. CHECKSUM_UNNECESSARY (with proto_csum_blank true): This packet was
- *     generated locally by a Xen DomU and has a partial checksum.  If it is
- *     handled on this machine (Dom0 or DomU), then the checksum will not be
- *     computed.  If it goes off box, the checksum in the packet needs to be
- *     completed.  Calling skb_checksum_setup converts this to CHECKSUM_HW
- *     (CHECKSUM_PARTIAL) so that the checksum can be completed.  In later
- *     kernels, this combination is replaced with CHECKSUM_PARTIAL.
- * 5. CHECKSUM_UNNECESSARY (with proto_csum_blank false): Packet with a correct
- *     full checksum or using a protocol without a checksum.  skb->csum is
- *     undefined.  This is common from devices with receive checksum
- *     offloading.  This is somewhat similar to CHECKSUM_NONE, except that
- *     nobody will try to verify the checksum with CHECKSUM_UNNECESSARY.
- *
- * Note that on earlier kernels, CHECKSUM_COMPLETE and CHECKSUM_PARTIAL are
- * both defined as CHECKSUM_HW.  Normally the meaning of CHECKSUM_HW is clear
- * based on whether it is on the transmit or receive path.  After the datapath
- * it will be intepreted as CHECKSUM_PARTIAL.  If the packet already has a
- * checksum, we will panic.  Since we can receive packets with checksums, we
- * assume that all CHECKSUM_HW packets have checksums and map them to
- * CHECKSUM_NONE, which has a similar meaning (the it is only different if the
- * packet is processed by the local IP stack, in which case it will need to
- * be reverified).  If we receive a packet with CHECKSUM_HW that really means
- * CHECKSUM_PARTIAL, it will be sent with the wrong checksum.  However, there
- * shouldn't be any devices that do this with bridging.
- */
-int compute_ip_summed(struct sk_buff *skb, bool xmit)
-{
-       /* For our convenience these defines change repeatedly between kernel
-        * versions, so we can't just copy them over...
-        */
-       switch (skb->ip_summed) {
-       case CHECKSUM_NONE:
-               set_ip_summed(skb, OVS_CSUM_NONE);
-               break;
-       case CHECKSUM_UNNECESSARY:
-               set_ip_summed(skb, OVS_CSUM_UNNECESSARY);
-               break;
-#ifdef CHECKSUM_HW
-       /* In theory this could be either CHECKSUM_PARTIAL or CHECKSUM_COMPLETE.
-        * However, on the receive side we should only get CHECKSUM_PARTIAL
-        * packets from Xen, which uses some special fields to represent this
-        * (see vswitch_skb_checksum_setup()).  Since we can only make one type
-        * work, pick the one that actually happens in practice.
-        *
-        * On the transmit side (basically after skb_checksum_setup()
-        * has been run or on internal dev transmit), packets with
-        * CHECKSUM_COMPLETE aren't generated, so assume CHECKSUM_PARTIAL.
-        */
-       case CHECKSUM_HW:
-               if (!xmit)
-                       set_ip_summed(skb, OVS_CSUM_COMPLETE);
-               else
-                       set_ip_summed(skb, OVS_CSUM_PARTIAL);
-               break;
-#else
-       case CHECKSUM_COMPLETE:
-               set_ip_summed(skb, OVS_CSUM_COMPLETE);
-               break;
-       case CHECKSUM_PARTIAL:
-               set_ip_summed(skb, OVS_CSUM_PARTIAL);
-               break;
-#endif
-       }
-
-       OVS_CB(skb)->csum_start = skb_headroom(skb) + skb_transport_offset(skb);
-
-       return vswitch_skb_checksum_setup(skb);
-}
-
-/*
- *     forward_ip_summed - map internal checksum state back onto native
- *                        kernel fields.
- *
- * @skb: Packet to manipulate.
- * @xmit: Whether we are about send on the transmit path the network stack.
- *       This follows the same logic as the @xmit field in compute_ip_summed().
- *       Generally, a given vport will have opposite values for @xmit passed to
- *       these two functions.
- *
- * When a packet is about to egress from OVS take our internal fields (including
- * any modifications we have made) and recreate the correct representation for
- * this kernel.  This may do things like change the transport header offset.
- */
-void forward_ip_summed(struct sk_buff *skb, bool xmit)
-{
-       switch (get_ip_summed(skb)) {
-       case OVS_CSUM_NONE:
-               skb->ip_summed = CHECKSUM_NONE;
-               break;
-       case OVS_CSUM_UNNECESSARY:
-               skb->ip_summed = CHECKSUM_UNNECESSARY;
-#if defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID)
-               skb->proto_data_valid = 1;
-#endif
-               break;
-#ifdef CHECKSUM_HW
-       case OVS_CSUM_COMPLETE:
-               if (!xmit)
-                       skb->ip_summed = CHECKSUM_HW;
-               else
-                       skb->ip_summed = CHECKSUM_NONE;
-               break;
-       case OVS_CSUM_PARTIAL:
-               if (!xmit) {
-                       skb->ip_summed = CHECKSUM_UNNECESSARY;
-#if defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID)
-                       skb->proto_csum_blank = 1;
-#endif
-               } else {
-                       skb->ip_summed = CHECKSUM_HW;
-               }
-               break;
-#else
-       case OVS_CSUM_COMPLETE:
-               skb->ip_summed = CHECKSUM_COMPLETE;
-               break;
-       case OVS_CSUM_PARTIAL:
-               skb->ip_summed = CHECKSUM_PARTIAL;
-               break;
-#endif
-       }
-
-       if (get_ip_summed(skb) == OVS_CSUM_PARTIAL)
-               skb_set_transport_header(skb, OVS_CB(skb)->csum_start -
-                                             skb_headroom(skb));
-}
-
-u8 get_ip_summed(struct sk_buff *skb)
-{
-       return OVS_CB(skb)->ip_summed;
-}
-
-void set_ip_summed(struct sk_buff *skb, u8 ip_summed)
-{
-       OVS_CB(skb)->ip_summed = ip_summed;
-}
-
-void get_skb_csum_pointers(const struct sk_buff *skb, u16 *csum_start,
-                          u16 *csum_offset)
-{
-       *csum_start = OVS_CB(skb)->csum_start;
-       *csum_offset = skb->csum;
-}
-
-void set_skb_csum_pointers(struct sk_buff *skb, u16 csum_start,
-                          u16 csum_offset)
-{
-       OVS_CB(skb)->csum_start = csum_start;
-       skb->csum = csum_offset;
-}
-#endif /* NEED_CSUM_NORMALIZE */
diff --git a/datapath/checksum.h b/datapath/checksum.h
deleted file mode 100644 (file)
index a440c59..0000000
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright (c) 2007-2011 Nicira, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- */
-
-#ifndef CHECKSUM_H
-#define CHECKSUM_H 1
-
-#include <linux/skbuff.h>
-#include <linux/version.h>
-
-#include <net/checksum.h>
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) || \
-       (defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID))
-#define NEED_CSUM_NORMALIZE
-#endif
-
-/* These are the same values as the checksum constants in 2.6.22+. */
-enum csum_type {
-       OVS_CSUM_NONE = 0,
-       OVS_CSUM_UNNECESSARY = 1,
-       OVS_CSUM_COMPLETE = 2,
-       OVS_CSUM_PARTIAL = 3,
-};
-
-#ifdef NEED_CSUM_NORMALIZE
-int compute_ip_summed(struct sk_buff *skb, bool xmit);
-void forward_ip_summed(struct sk_buff *skb, bool xmit);
-u8 get_ip_summed(struct sk_buff *skb);
-void set_ip_summed(struct sk_buff *skb, u8 ip_summed);
-void get_skb_csum_pointers(const struct sk_buff *skb, u16 *csum_start,
-                          u16 *csum_offset);
-void set_skb_csum_pointers(struct sk_buff *skb, u16 csum_start,
-                          u16 csum_offset);
-#else
-static inline int compute_ip_summed(struct sk_buff *skb, bool xmit)
-{
-       return 0;
-}
-
-static inline void forward_ip_summed(struct sk_buff *skb, bool xmit) { }
-
-static inline u8 get_ip_summed(struct sk_buff *skb)
-{
-       return skb->ip_summed;
-}
-
-static inline void set_ip_summed(struct sk_buff *skb, u8 ip_summed)
-{
-       skb->ip_summed = ip_summed;
-}
-
-static inline void get_skb_csum_pointers(const struct sk_buff *skb,
-                                        u16 *csum_start, u16 *csum_offset)
-{
-       *csum_start = skb->csum_start;
-       *csum_offset = skb->csum_offset;
-}
-
-static inline void set_skb_csum_pointers(struct sk_buff *skb, u16 csum_start,
-                                        u16 csum_offset)
-{
-       skb->csum_start = csum_start;
-       skb->csum_offset = csum_offset;
-}
-#endif
-
-/* This is really compatibility code that belongs in the compat directory.
- * However, it needs access to our normalized checksum values, so put it here.
- */
-#if defined(NEED_CSUM_NORMALIZE) || LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
-#define inet_proto_csum_replace4 rpl_inet_proto_csum_replace4
-static inline void inet_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
-                                           __be32 from, __be32 to,
-                                           int pseudohdr)
-{
-       __be32 diff[] = { ~from, to };
-
-       if (get_ip_summed(skb) != OVS_CSUM_PARTIAL) {
-               *sum = csum_fold(csum_partial((char *)diff, sizeof(diff),
-                               ~csum_unfold(*sum)));
-               if (get_ip_summed(skb) == OVS_CSUM_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)));
-}
-#endif
-
-#if defined(NEED_CSUM_NORMALIZE) || LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)
-#define inet_proto_csum_replace16 rpl_inet_proto_csum_replace16
-static inline void inet_proto_csum_replace16(__sum16 *sum,
-                                            struct sk_buff *skb,
-                                            const __be32 *from,
-                                            const __be32 *to,
-                                            int pseudohdr)
-{
-       __be32 diff[] = {
-               ~from[0], ~from[1], ~from[2], ~from[3],
-               to[0], to[1], to[2], to[3],
-       };
-       if (get_ip_summed(skb) != OVS_CSUM_PARTIAL) {
-               *sum = csum_fold(csum_partial(diff, sizeof(diff),
-                                ~csum_unfold(*sum)));
-               if (get_ip_summed(skb) == OVS_CSUM_COMPLETE && pseudohdr)
-                       skb->csum = ~csum_partial(diff, sizeof(diff),
-                                                 ~skb->csum);
-       } else if (pseudohdr)
-               *sum = ~csum_fold(csum_partial(diff, sizeof(diff),
-                                 csum_unfold(*sum)));
-}
-#endif
-
-#ifdef NEED_CSUM_NORMALIZE
-static inline void update_csum_start(struct sk_buff *skb, int delta)
-{
-       if (get_ip_summed(skb) == OVS_CSUM_PARTIAL) {
-               u16 csum_start, csum_offset;
-
-               get_skb_csum_pointers(skb, &csum_start, &csum_offset);
-               set_skb_csum_pointers(skb, csum_start + delta, csum_offset);
-       }
-}
-
-static inline int rpl_pskb_expand_head(struct sk_buff *skb, int nhead,
-                                      int ntail, gfp_t gfp_mask)
-{
-       int err;
-       int old_headroom = skb_headroom(skb);
-
-       err = pskb_expand_head(skb, nhead, ntail, gfp_mask);
-       if (unlikely(err))
-               return err;
-
-       update_csum_start(skb, skb_headroom(skb) - old_headroom);
-
-       return 0;
-}
-#define pskb_expand_head rpl_pskb_expand_head
-
-static inline unsigned char *rpl__pskb_pull_tail(struct sk_buff *skb,
-                                                 int delta)
-{
-       unsigned char *ret;
-       int old_headroom = skb_headroom(skb);
-
-       ret = __pskb_pull_tail(skb, delta);
-       if (unlikely(!ret))
-               return ret;
-
-       update_csum_start(skb, skb_headroom(skb) - old_headroom);
-
-       return ret;
-}
-#define __pskb_pull_tail rpl__pskb_pull_tail
-#endif
-
-#endif /* checksum.h */
index 8457dbf..bc7e880 100644 (file)
 #include <net/route.h>
 #include <net/xfrm.h>
 
-
-#ifndef HAVE_NLA_NUL_STRING
-static inline int CHECK_NUL_STRING(struct nlattr *attr, int maxlen)
-{
-       char *s;
-       int len;
-       if (!attr)
-               return 0;
-
-       len = nla_len(attr);
-       if (len >= maxlen)
-               return -EINVAL;
-
-       s = nla_data(attr);
-       if (s[len - 1] != '\0')
-               return -EINVAL;
-
-       return 0;
-}
-#else
-static inline int CHECK_NUL_STRING(struct nlattr *attr, int maxlen)
-{
-       return 0;
-}
-#endif  /* !HAVE_NLA_NUL_STRING */
-
 static inline void skb_clear_rxhash(struct sk_buff *skb)
 {
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)
@@ -58,54 +32,12 @@ static inline void skb_clear_rxhash(struct sk_buff *skb)
 #endif
 }
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
-#define GENL_SOCK(net) (genl_sock)
-#define SET_NETNSOK
-#else
-#define GENL_SOCK(net) ((net)->genl_sock)
-#define SET_NETNSOK    .netnsok = true,
-#endif
-
 #ifdef HAVE_PARALLEL_OPS
 #define SET_PARALLEL_OPS       .parallel_ops = true,
 #else
 #define SET_PARALLEL_OPS
 #endif
 
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
-#ifdef CONFIG_NETFILTER
-static inline u32 skb_get_mark(struct sk_buff *skb)
-{
-       return skb->nfmark;
-}
-
-static inline void skb_set_mark(struct sk_buff *skb, u32 mark)
-{
-       skb->nfmark = mark;
-}
-#else /* CONFIG_NETFILTER */
-static inline u32 skb_get_mark(struct sk_buff *skb)
-{
-       return 0;
-}
-
-static inline void skb_set_mark(struct sk_buff *skb, u32 mark)
-{
-}
-#endif
-#else /* before 2.6.20 */
-static inline u32 skb_get_mark(struct sk_buff *skb)
-{
-       return skb->mark;
-}
-
-static inline void skb_set_mark(struct sk_buff *skb, u32 mark)
-{
-       skb->mark = mark;
-}
-#endif /* after 2.6.20 */
-
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
 #define rt_dst(rt) (rt->dst)
 #else
@@ -130,13 +62,8 @@ static inline struct rtable *find_route(struct net *net,
        struct flowi fl = { .nl_u = { .ip4_u = {
                                        .daddr = daddr,
                                        .saddr = *saddr,
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
-                                       .fwmark = skb_mark,
-#endif
                                        .tos   = RT_TOS(tos) } },
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
                                        .mark = skb_mark,
-#endif
                                        .proto = ipproto };
 
        if (unlikely(ip_route_output_key(net, &rt, &fl)))
index 27deec8..bb1e282 100644 (file)
 #include <net/net_namespace.h>
 #include <net/netns/generic.h>
 
-#include "checksum.h"
 #include "datapath.h"
 #include "flow.h"
 #include "vlan.h"
 #include "vport-internal_dev.h"
 #include "vport-netdev.h"
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) || \
-    LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0)
-#error Kernels before 2.6.18 or after 3.9 are not supported by this version of Open vSwitch.
-#endif
-
 #define REHASH_FLOW_INTERVAL (10 * 60 * HZ)
 static void rehash_flow_table(struct work_struct *work);
 static DECLARE_DELAYED_WORK(rehash_flow_wq, rehash_flow_table);
@@ -278,7 +272,7 @@ static struct genl_family dp_packet_genl_family = {
        .name = OVS_PACKET_FAMILY,
        .version = OVS_PACKET_VERSION,
        .maxattr = OVS_PACKET_ATTR_MAX,
-        SET_NETNSOK
+       .netnsok = true,
         SET_PARALLEL_OPS
 };
 
@@ -300,8 +294,6 @@ int ovs_dp_upcall(struct datapath *dp, struct sk_buff *skb,
                goto err;
        }
 
-       forward_ip_summed(skb, true);
-
        if (!skb_is_gso(skb))
                err = queue_userspace_packet(ovs_dp_get_net(dp), dp_ifindex, skb, upcall_info);
        else
@@ -419,10 +411,12 @@ static int queue_userspace_packet(struct net *net, int dp_ifindex,
                nskb = skb_clone(skb, GFP_ATOMIC);
                if (!nskb)
                        return -ENOMEM;
-               
-               err = vlan_deaccel_tag(nskb);
-               if (err)
-                       return err;
+
+               nskb = __vlan_put_tag(nskb, nskb->vlan_proto, vlan_tx_tag_get(nskb));
+               if (!nskb)
+                       return -ENOMEM;
+
+               vlan_set_tci(nskb, 0);
 
                skb = nskb;
        }
@@ -662,14 +656,8 @@ static int validate_set(const struct nlattr *a,
        int err;
 
        case OVS_KEY_ATTR_PRIORITY:
-       case OVS_KEY_ATTR_ETHERNET:
-               break;
-
        case OVS_KEY_ATTR_SKB_MARK:
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) && !defined(CONFIG_NETFILTER)
-               if (nla_get_u32(ovs_key) != 0)
-                       return -EINVAL;
-#endif
+       case OVS_KEY_ATTR_ETHERNET:
                break;
 
        case OVS_KEY_ATTR_TUNNEL:
@@ -932,7 +920,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
        OVS_CB(packet)->flow = flow;
        OVS_CB(packet)->pkt_key = &flow->key;
        packet->priority = flow->key.phy.priority;
-       skb_set_mark(packet, flow->key.phy.skb_mark);
+       packet->mark = flow->key.phy.skb_mark;
 
        rcu_read_lock();
        dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
@@ -959,11 +947,7 @@ err:
 }
 
 static const struct nla_policy packet_policy[OVS_PACKET_ATTR_MAX + 1] = {
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
        [OVS_PACKET_ATTR_PACKET] = { .len = ETH_HLEN },
-#else
-       [OVS_PACKET_ATTR_PACKET] = { .minlen = ETH_HLEN },
-#endif
        [OVS_PACKET_ATTR_KEY] = { .type = NLA_NESTED },
        [OVS_PACKET_ATTR_ACTIONS] = { .type = NLA_NESTED },
 };
@@ -1015,7 +999,7 @@ static struct genl_family dp_flow_genl_family = {
        .name = OVS_FLOW_FAMILY,
        .version = OVS_FLOW_VERSION,
        .maxattr = OVS_FLOW_ATTR_MAX,
-        SET_NETNSOK
+       .netnsok = true,
         SET_PARALLEL_OPS
 };
 
@@ -1399,7 +1383,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
        if (!IS_ERR(reply))
                ovs_notify(reply, info, &ovs_dp_flow_multicast_group);
        else
-               netlink_set_err(GENL_SOCK(sock_net(skb->sk)), 0,
+               netlink_set_err(sock_net(skb->sk)->genl_sock, 0,
                                ovs_dp_flow_multicast_group.id, PTR_ERR(reply));
        return 0;
 
@@ -1583,9 +1567,7 @@ static struct genl_ops dp_flow_genl_ops[] = {
 };
 
 static const struct nla_policy datapath_policy[OVS_DP_ATTR_MAX + 1] = {
-#ifdef HAVE_NLA_NUL_STRING
        [OVS_DP_ATTR_NAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 },
-#endif
        [OVS_DP_ATTR_UPCALL_PID] = { .type = NLA_U32 },
 };
 
@@ -1595,7 +1577,7 @@ static struct genl_family dp_datapath_genl_family = {
        .name = OVS_DATAPATH_FAMILY,
        .version = OVS_DATAPATH_VERSION,
        .maxattr = OVS_DP_ATTR_MAX,
-        SET_NETNSOK
+       .netnsok = true,
         SET_PARALLEL_OPS
 };
 
@@ -1663,11 +1645,6 @@ static struct sk_buff *ovs_dp_cmd_build_info(struct datapath *dp, u32 portid,
        return skb;
 }
 
-static int ovs_dp_cmd_validate(struct nlattr *a[OVS_DP_ATTR_MAX + 1])
-{
-       return CHECK_NUL_STRING(a[OVS_DP_ATTR_NAME], IFNAMSIZ - 1);
-}
-
 /* Called with ovs_mutex. */
 static struct datapath *lookup_datapath(struct net *net,
                                        struct ovs_header *ovs_header,
@@ -1702,10 +1679,6 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
        if (!a[OVS_DP_ATTR_NAME] || !a[OVS_DP_ATTR_UPCALL_PID])
                goto err;
 
-       err = ovs_dp_cmd_validate(a);
-       if (err)
-               goto err;
-
        ovs_lock();
 
        err = -ENOMEM;
@@ -1815,10 +1788,6 @@ static int ovs_dp_cmd_del(struct sk_buff *skb, struct genl_info *info)
        struct datapath *dp;
        int err;
 
-       err = ovs_dp_cmd_validate(info->attrs);
-       if (err)
-               return err;
-
        ovs_lock();
        dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs);
        err = PTR_ERR(dp);
@@ -1848,10 +1817,6 @@ static int ovs_dp_cmd_set(struct sk_buff *skb, struct genl_info *info)
        struct datapath *dp;
        int err;
 
-       err = ovs_dp_cmd_validate(info->attrs);
-       if (err)
-               return err;
-
        ovs_lock();
        dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs);
        err = PTR_ERR(dp);
@@ -1862,7 +1827,7 @@ static int ovs_dp_cmd_set(struct sk_buff *skb, struct genl_info *info)
                                      info->snd_seq, OVS_DP_CMD_NEW);
        if (IS_ERR(reply)) {
                err = PTR_ERR(reply);
-               netlink_set_err(GENL_SOCK(sock_net(skb->sk)), 0,
+               netlink_set_err(sock_net(skb->sk)->genl_sock, 0,
                                ovs_dp_datapath_multicast_group.id, err);
                err = 0;
                goto unlock;
@@ -1883,10 +1848,6 @@ static int ovs_dp_cmd_get(struct sk_buff *skb, struct genl_info *info)
        struct datapath *dp;
        int err;
 
-       err = ovs_dp_cmd_validate(info->attrs);
-       if (err)
-               return err;
-
        ovs_lock();
        dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs);
        if (IS_ERR(dp)) {
@@ -1957,12 +1918,8 @@ static struct genl_ops dp_datapath_genl_ops[] = {
 };
 
 static const struct nla_policy vport_policy[OVS_VPORT_ATTR_MAX + 1] = {
-#ifdef HAVE_NLA_NUL_STRING
        [OVS_VPORT_ATTR_NAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 },
        [OVS_VPORT_ATTR_STATS] = { .len = sizeof(struct ovs_vport_stats) },
-#else
-       [OVS_VPORT_ATTR_STATS] = { .minlen = sizeof(struct ovs_vport_stats) },
-#endif
        [OVS_VPORT_ATTR_PORT_NO] = { .type = NLA_U32 },
        [OVS_VPORT_ATTR_TYPE] = { .type = NLA_U32 },
        [OVS_VPORT_ATTR_UPCALL_PID] = { .type = NLA_U32 },
@@ -1975,7 +1932,7 @@ static struct genl_family dp_vport_genl_family = {
        .name = OVS_VPORT_FAMILY,
        .version = OVS_VPORT_VERSION,
        .maxattr = OVS_VPORT_ATTR_MAX,
-        SET_NETNSOK
+       .netnsok = true,
         SET_PARALLEL_OPS
 };
 
@@ -2039,11 +1996,6 @@ struct sk_buff *ovs_vport_cmd_build_info(struct vport *vport, u32 portid,
        return skb;
 }
 
-static int ovs_vport_cmd_validate(struct nlattr *a[OVS_VPORT_ATTR_MAX + 1])
-{
-       return CHECK_NUL_STRING(a[OVS_VPORT_ATTR_NAME], IFNAMSIZ - 1);
-}
-
 /* Called with ovs_mutex or RCU read lock. */
 static struct vport *lookup_vport(struct net *net,
                                  struct ovs_header *ovs_header,
@@ -2094,10 +2046,6 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
            !a[OVS_VPORT_ATTR_UPCALL_PID])
                goto exit;
 
-       err = ovs_vport_cmd_validate(a);
-       if (err)
-               goto exit;
-
        ovs_lock();
        dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
        err = -ENODEV;
@@ -2166,10 +2114,6 @@ static int ovs_vport_cmd_set(struct sk_buff *skb, struct genl_info *info)
        struct vport *vport;
        int err;
 
-       err = ovs_vport_cmd_validate(a);
-       if (err)
-               goto exit;
-
        ovs_lock();
        vport = lookup_vport(sock_net(skb->sk), info->userhdr, a);
        err = PTR_ERR(vport);
@@ -2212,7 +2156,6 @@ exit_free:
        kfree_skb(reply);
 exit_unlock:
        ovs_unlock();
-exit:
        return err;
 }
 
@@ -2223,10 +2166,6 @@ static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
        struct vport *vport;
        int err;
 
-       err = ovs_vport_cmd_validate(a);
-       if (err)
-               goto exit;
-
        ovs_lock();
        vport = lookup_vport(sock_net(skb->sk), info->userhdr, a);
        err = PTR_ERR(vport);
@@ -2251,7 +2190,6 @@ static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
 
 exit_unlock:
        ovs_unlock();
-exit:
        return err;
 }
 
@@ -2263,10 +2201,6 @@ static int ovs_vport_cmd_get(struct sk_buff *skb, struct genl_info *info)
        struct vport *vport;
        int err;
 
-       err = ovs_vport_cmd_validate(a);
-       if (err)
-               goto exit;
-
        rcu_read_lock();
        vport = lookup_vport(sock_net(skb->sk), ovs_header, a);
        err = PTR_ERR(vport);
@@ -2285,7 +2219,6 @@ static int ovs_vport_cmd_get(struct sk_buff *skb, struct genl_info *info)
 
 exit_unlock:
        rcu_read_unlock();
-exit:
        return err;
 }
 
index 064211d..5d50dd4 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/skbuff.h>
 #include <linux/u64_stats_sync.h>
 
-#include "checksum.h"
 #include "compat.h"
 #include "flow.h"
 #include "vlan.h"
@@ -94,25 +93,11 @@ struct datapath {
  * @pkt_key: The flow information extracted from the packet.  Must be nonnull.
  * @tun_key: Key for the tunnel that encapsulated this packet. NULL if the
  * packet is not being tunneled.
- * @ip_summed: Consistently stores L4 checksumming status across different
- * kernel versions.
- * @csum_start: Stores the offset from which to start checksumming independent
- * of the transport header on all kernel versions.
- * packet was not received on a tunnel.
- * @vlan_tci: Provides a substitute for the skb->vlan_tci field on kernels
- * before 2.6.27.
  */
 struct ovs_skb_cb {
        struct sw_flow          *flow;
        struct sw_flow_key      *pkt_key;
        struct ovs_key_ipv4_tunnel  *tun_key;
-#ifdef NEED_CSUM_NORMALIZE
-       enum csum_type          ip_summed;
-       u16                     csum_start;
-#endif
-#ifdef NEED_VLAN_FIELD
-       u16                     vlan_tci;
-#endif
 };
 #define OVS_CB(skb) ((struct ovs_skb_cb *)(skb)->cb)
 
index d530893..847f611 100644 (file)
@@ -35,7 +35,7 @@ static void dp_detach_port_notify(struct vport *vport)
                                          OVS_VPORT_CMD_DEL);
        ovs_dp_detach_port(vport);
        if (IS_ERR(notify)) {
-               netlink_set_err(GENL_SOCK(ovs_dp_get_net(dp)), 0,
+               netlink_set_err(ovs_dp_get_net(dp)->genl_sock, 0,
                                ovs_dp_vport_multicast_group.id,
                                PTR_ERR(notify));
                return;
index 7a697a4..449e645 100644 (file)
@@ -853,7 +853,7 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key)
        if (OVS_CB(skb)->tun_key)
                memcpy(&key->tun_key, OVS_CB(skb)->tun_key, sizeof(key->tun_key));
        key->phy.in_port = in_port;
-       key->phy.skb_mark = skb_get_mark(skb);
+       key->phy.skb_mark = skb->mark;
 
        skb_reset_mac_header(skb);
 
@@ -1377,12 +1377,7 @@ static int metadata_from_nlattrs(struct sw_flow_match *match,  u64 *attrs,
 
        if (*attrs & (1ULL << OVS_KEY_ATTR_SKB_MARK)) {
                uint32_t mark = nla_get_u32(a[OVS_KEY_ATTR_SKB_MARK]);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) && !defined(CONFIG_NETFILTER)
-               if (!is_mask && mark != 0) {
-                       OVS_NLERR("skb->mark must be zero on this kernel (mark=%d).\n", mark);
-                       return -EINVAL;
-               }
-#endif
+
                SW_FLOW_KEY_PUT(match, phy.skb_mark, mark, is_mask);
                *attrs &= ~(1ULL << OVS_KEY_ATTR_SKB_MARK);
        }
@@ -1995,6 +1990,7 @@ nla_put_failure:
  * Returns zero if successful or a negative error code. */
 int ovs_flow_init(void)
 {
+       BUILD_BUG_ON(__alignof__(struct sw_flow_key) % __alignof__(long));
        BUILD_BUG_ON(sizeof(struct sw_flow_key) % sizeof(long));
 
        flow_cache = kmem_cache_create("sw_flow", sizeof(struct sw_flow), 0,
index eda74f3..03eae03 100644 (file)
@@ -127,7 +127,7 @@ struct sw_flow_key {
                        } nd;
                } ipv6;
        };
-} __aligned(__alignof__(long));
+} __aligned(BITS_PER_LONG/8); /* Ensure that we can do comparisons as longs. */
 
 struct sw_flow {
        struct rcu_head rcu;
index 178cd5e..e3c42cd 100644 (file)
@@ -1,5 +1,4 @@
 openvswitch_sources += \
-       linux/compat/addrconf_core-openvswitch.c \
        linux/compat/dev-openvswitch.c \
        linux/compat/exthdrs_core.c \
        linux/compat/flex_array.c \
@@ -7,23 +6,20 @@ openvswitch_sources += \
        linux/compat/gre.c \
        linux/compat/gso.c \
        linux/compat/genetlink-openvswitch.c \
-       linux/compat/ip_output-openvswitch.c \
        linux/compat/ip_tunnels_core.c \
-       linux/compat/kmemdup.c \
        linux/compat/netdevice.c \
        linux/compat/net_namespace.c \
        linux/compat/reciprocal_div.c \
        linux/compat/skbuff-openvswitch.c \
-       linux/compat/time.c     \
        linux/compat/vxlan.c    \
-       linux/compat/workqueue.c
+       linux/compat/workqueue.c \
+       linux/compat/utils.c
 openvswitch_headers += \
        linux/compat/gso.h \
        linux/compat/include/asm/percpu.h \
        linux/compat/include/linux/compiler.h \
        linux/compat/include/linux/compiler-gcc.h \
        linux/compat/include/linux/cpumask.h \
-       linux/compat/include/linux/dmi.h \
        linux/compat/include/linux/err.h \
        linux/compat/include/linux/etherdevice.h \
        linux/compat/include/linux/flex_array.h \
@@ -35,34 +31,25 @@ openvswitch_headers += \
        linux/compat/include/linux/if_tunnel.h \
        linux/compat/include/linux/if_vlan.h \
        linux/compat/include/linux/in.h \
-       linux/compat/include/linux/inetdevice.h \
        linux/compat/include/linux/ip.h \
        linux/compat/include/linux/ipv6.h \
        linux/compat/include/linux/jiffies.h \
        linux/compat/include/linux/kconfig.h \
        linux/compat/include/linux/kernel.h \
-       linux/compat/include/linux/kobject.h \
        linux/compat/include/linux/list.h \
-       linux/compat/include/linux/lockdep.h \
        linux/compat/include/linux/log2.h \
-       linux/compat/include/linux/mutex.h \
        linux/compat/include/linux/net.h \
        linux/compat/include/linux/netdevice.h \
        linux/compat/include/linux/netdev_features.h \
-       linux/compat/include/linux/netfilter_bridge.h \
-       linux/compat/include/linux/netfilter_ipv4.h \
        linux/compat/include/linux/netlink.h \
        linux/compat/include/linux/poison.h \
        linux/compat/include/linux/rculist.h \
        linux/compat/include/linux/rcupdate.h \
-       linux/compat/include/linux/reciprocal_div.h \
        linux/compat/include/linux/rtnetlink.h \
        linux/compat/include/linux/sctp.h \
        linux/compat/include/linux/skbuff.h \
-       linux/compat/include/linux/slab.h \
        linux/compat/include/linux/stddef.h \
        linux/compat/include/linux/tcp.h \
-       linux/compat/include/linux/timer.h \
        linux/compat/include/linux/types.h \
        linux/compat/include/linux/u64_stats_sync.h \
        linux/compat/include/linux/udp.h \
@@ -78,9 +65,5 @@ openvswitch_headers += \
        linux/compat/include/net/ipv6.h \
        linux/compat/include/net/net_namespace.h \
        linux/compat/include/net/netlink.h \
-       linux/compat/include/net/protocol.h \
-       linux/compat/include/net/route.h \
-       linux/compat/include/net/sock.h \
-       linux/compat/include/net/netns/generic.h \
        linux/compat/include/net/vxlan.h \
        linux/compat/include/net/sctp/checksum.h
diff --git a/datapath/linux/compat/addrconf_core-openvswitch.c b/datapath/linux/compat/addrconf_core-openvswitch.c
deleted file mode 100644 (file)
index 35e3612..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-#include <linux/version.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)
-
-/*
- * IPv6 library code, needed by static components when full IPv6 support is
- * not configured or static.
- */
-
-#include <net/ipv6.h>
-
-#define IPV6_ADDR_SCOPE_TYPE(scope)    ((scope) << 16)
-
-static inline unsigned ipv6_addr_scope2type(unsigned scope)
-{
-       switch (scope) {
-       case IPV6_ADDR_SCOPE_NODELOCAL:
-               return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_NODELOCAL) |
-                       IPV6_ADDR_LOOPBACK);
-       case IPV6_ADDR_SCOPE_LINKLOCAL:
-               return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL) |
-                       IPV6_ADDR_LINKLOCAL);
-       case IPV6_ADDR_SCOPE_SITELOCAL:
-               return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL) |
-                       IPV6_ADDR_SITELOCAL);
-       }
-       return IPV6_ADDR_SCOPE_TYPE(scope);
-}
-
-int __ipv6_addr_type(const struct in6_addr *addr)
-{
-       __be32 st;
-
-       st = addr->s6_addr32[0];
-
-       /* Consider all addresses with the first three bits different of
-          000 and 111 as unicasts.
-        */
-       if ((st & htonl(0xE0000000)) != htonl(0x00000000) &&
-           (st & htonl(0xE0000000)) != htonl(0xE0000000))
-               return (IPV6_ADDR_UNICAST |
-                       IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));
-
-       if ((st & htonl(0xFF000000)) == htonl(0xFF000000)) {
-               /* multicast */
-               /* addr-select 3.1 */
-               return (IPV6_ADDR_MULTICAST |
-                       ipv6_addr_scope2type(IPV6_ADDR_MC_SCOPE(addr)));
-       }
-
-       if ((st & htonl(0xFFC00000)) == htonl(0xFE800000))
-               return (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_UNICAST |
-                       IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL));               /* addr-select 3.1 */
-       if ((st & htonl(0xFFC00000)) == htonl(0xFEC00000))
-               return (IPV6_ADDR_SITELOCAL | IPV6_ADDR_UNICAST |
-                       IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL));               /* addr-select 3.1 */
-       if ((st & htonl(0xFE000000)) == htonl(0xFC000000))
-               return (IPV6_ADDR_UNICAST |
-                       IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));                  /* RFC 4193 */
-
-       if ((addr->s6_addr32[0] | addr->s6_addr32[1]) == 0) {
-               if (addr->s6_addr32[2] == 0) {
-                       if (addr->s6_addr32[3] == 0)
-                               return IPV6_ADDR_ANY;
-
-                       if (addr->s6_addr32[3] == htonl(0x00000001))
-                               return (IPV6_ADDR_LOOPBACK | IPV6_ADDR_UNICAST |
-                                       IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL));       /* addr-select 3.4 */
-
-                       return (IPV6_ADDR_COMPATv4 | IPV6_ADDR_UNICAST |
-                               IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));  /* addr-select 3.3 */
-               }
-
-               if (addr->s6_addr32[2] == htonl(0x0000ffff))
-                       return (IPV6_ADDR_MAPPED |
-                               IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));  /* addr-select 3.3 */
-       }
-
-       return (IPV6_ADDR_RESERVED |
-               IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));  /* addr-select 3.4 */
-}
-
-#endif /* kernel < 2.6.21 */
index 810223b..359f916 100644 (file)
 #include <net/genetlink.h>
 #include <linux/version.h>
 
-#define GENL_FIRST_MCGROUP 16
-#define GENL_LAST_MCGROUP  31
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
-#include <linux/mutex.h>
-#include <linux/openvswitch.h>
-
-#include "openvswitch/datapath-compat.h"
-
-static DEFINE_MUTEX(mc_group_mutex);
-
-int genl_register_mc_group(struct genl_family *family,
-                          struct genl_multicast_group *grp)
-{
-       static int next_group = GENL_FIRST_MCGROUP;
-
-       grp->family = family;
-
-       if (!strcmp(grp->name, OVS_VPORT_MCGROUP)) {
-               grp->id = OVS_VPORT_MCGROUP_FALLBACK_ID;
-               return 0;
-       }
-
-       mutex_lock(&mc_group_mutex);
-       grp->id = next_group;
-
-       if (++next_group > GENL_LAST_MCGROUP)
-               next_group = GENL_FIRST_MCGROUP;
-       mutex_unlock(&mc_group_mutex);
-
-       return 0;
-}
-#endif /* kernel < 2.6.23 */
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31)
-/**
- * genl_register_family_with_ops - register a generic netlink family
- * @family: generic netlink family
- * @ops: operations to be registered
- * @n_ops: number of elements to register
- *
- * Registers the specified family and operations from the specified table.
- * Only one family may be registered with the same family name or identifier.
- *
- * The family id may equal GENL_ID_GENERATE causing an unique id to
- * be automatically generated and assigned.
- *
- * Either a doit or dumpit callback must be specified for every registered
- * operation or the function will fail. Only one operation structure per
- * command identifier may be registered.
- *
- * See include/net/genetlink.h for more documenation on the operations
- * structure.
- *
- * This is equivalent to calling genl_register_family() followed by
- * genl_register_ops() for every operation entry in the table taking
- * care to unregister the family on error path.
- *
- * Return 0 on success or a negative error code.
- */
-int genl_register_family_with_ops(struct genl_family *family,
-       struct genl_ops *ops, size_t n_ops)
-{
-       int err, i;
-
-       err = genl_register_family(family);
-       if (err)
-               return err;
-
-       for (i = 0; i < n_ops; ++i, ++ops) {
-               err = genl_register_ops(family, ops);
-               if (err)
-                       goto err_out;
-       }
-       return 0;
-err_out:
-       genl_unregister_family(family);
-       return err;
-}
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
-/**
- * nlmsg_notify - send a notification netlink message
- * @sk: netlink socket to use
- * @skb: notification message
- * @portid: destination netlink portid for reports or 0
- * @group: destination multicast group or 0
- * @report: 1 to report back, 0 to disable
- * @flags: allocation flags
- */
-int nlmsg_notify(struct sock *sk, struct sk_buff *skb, u32 portid,
-                unsigned int group, int report, gfp_t flags)
-{
-       int err = 0;
-
-       if (group) {
-               int exclude_portid = 0;
-
-               if (report) {
-                       atomic_inc(&skb->users);
-                       exclude_portid = portid;
-               }
-
-               /* errors reported via destination sk->sk_err, but propagate
-                * delivery errors if NETLINK_BROADCAST_ERROR flag is set */
-               err = nlmsg_multicast(sk, skb, exclude_portid, group, flags);
-       }
-
-       if (report) {
-               int err2;
-
-               err2 = nlmsg_unicast(sk, skb, portid);
-               if (!err || err == -ESRCH)
-                       err = err2;
-       }
-
-       return err;
-}
-#endif
-
 /* This is analogous to rtnl_notify() but uses genl_sock instead of rtnl.
  *
  * This is not (yet) in any upstream kernel. */
 void genl_notify(struct sk_buff *skb, struct net *net, u32 portid, u32 group,
                 struct nlmsghdr *nlh, gfp_t flags)
 {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
        struct sock *sk = net->genl_sock;
-#else
-       struct sock *sk = genl_sock;
-#endif
        int report = 0;
 
        if (nlh)
@@ -140,10 +15,3 @@ void genl_notify(struct sk_buff *skb, struct net *net, u32 portid, u32 group,
 
        nlmsg_notify(sk, skb, portid, group, report, flags);
 }
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
-/* This function wasn't exported before 2.6.30.  Lose! */
-void netlink_set_err(struct sock *ssk, u32 portid, u32 group, int code)
-{
-}
-#endif
diff --git a/datapath/linux/compat/include/linux/dmi.h b/datapath/linux/compat/include/linux/dmi.h
deleted file mode 100644 (file)
index 20945d3..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-#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
index f53cf97..c4c656c 100644 (file)
@@ -3,13 +3,6 @@
 
 #include_next <linux/if.h>
 
-#include <linux/version.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31)
-
-#define IFF_XMIT_DST_RELEASE 0
-
-#endif /* linux kernel < 2.6.31 */
-
 #ifndef IFF_TX_SKB_SHARING
 #define IFF_TX_SKB_SHARING 0
 #endif
index e22ea96..25f63ca 100644 (file)
@@ -3,19 +3,6 @@
 
 #include_next <linux/if_ether.h>
 
-#include <linux/version.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
-
-#define ETH_P_TEB      0x6558          /* Trans Ether Bridging         */
-
-#endif /* linux kernel < 2.6.28 */
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
-
-#define ETH_P_FCOE     0x8906          /* Fibre Channel over Ethernet  */
-
-#endif /* linux kernel < 2.6.30 */
-
 #ifndef ETH_P_802_3_MIN
 #define ETH_P_802_3_MIN        0x0600
 #endif
diff --git a/datapath/linux/compat/include/linux/inetdevice.h b/datapath/linux/compat/include/linux/inetdevice.h
deleted file mode 100644 (file)
index 813a70a..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef __LINUX_INETDEVICE_WRAPPER_H
-#define __LINUX_INETDEVICE_WRAPPER_H 1
-
-#include_next <linux/inetdevice.h>
-
-#include <linux/version.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
-
-#define inetdev_by_index(net, ifindex) \
-               inetdev_by_index((ifindex))
-
-#endif /* linux kernel < 2.6.25 */
-
-#endif
index 6e248c5..5dfe08e 100644 (file)
@@ -8,33 +8,6 @@
 
 #include <linux/version.h>
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
-#undef pr_emerg
-#define pr_emerg(fmt, ...) \
-       printk(KERN_EMERG pr_fmt(fmt), ##__VA_ARGS__)
-#undef pr_alert
-#define pr_alert(fmt, ...) \
-       printk(KERN_ALERT pr_fmt(fmt), ##__VA_ARGS__)
-#undef pr_crit
-#define pr_crit(fmt, ...) \
-       printk(KERN_CRIT pr_fmt(fmt), ##__VA_ARGS__)
-#undef pr_err
-#define pr_err(fmt, ...) \
-       printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)
-#undef pr_warning
-#define pr_warning(fmt, ...) \
-       printk(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__)
-#undef pr_notice
-#define pr_notice(fmt, ...) \
-       printk(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__)
-#undef pr_info
-#define pr_info(fmt, ...) \
-       printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
-#undef pr_cont
-#define pr_cont(fmt, ...) \
-       printk(KERN_CONT fmt, ##__VA_ARGS__)
-#endif
-
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
 #define pr_warn pr_warning
 #endif
 
 #endif
 
-#if defined(CONFIG_PREEMPT) && LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)
-#error "CONFIG_PREEMPT is broken before 2.6.21--see commit 4498121ca3, \"[NET]: Handle disabled preemption in gfp_any()\""
-#endif
-
 #ifndef USHRT_MAX
 #define USHRT_MAX      ((u16)(~0U))
 #define SHRT_MAX       ((s16)(USHRT_MAX>>1))
diff --git a/datapath/linux/compat/include/linux/kobject.h b/datapath/linux/compat/include/linux/kobject.h
deleted file mode 100644 (file)
index 4cf797e..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef __LINUX_KOBJECT_WRAPPER_H
-#define __LINUX_KOBJECT_WRAPPER_H 1
-
-#include_next <linux/kobject.h>
-
-#include <linux/version.h>
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
-#define kobject_init(kobj, ktype) rpl_kobject_init(kobj, ktype)
-static inline void rpl_kobject_init(struct kobject *kobj, struct kobj_type *ktype)
-{
-       kobj->ktype = ktype;
-       (kobject_init)(kobj);
-}
-
-#define kobject_add(kobj, parent, name) rpl_kobject_add(kobj, parent, name)
-static inline int rpl_kobject_add(struct kobject *kobj,
-                                 struct kobject *parent,
-                                 const char *name)
-{
-       int err = kobject_set_name(kobj, "%s", name);
-       if (err)
-               return err;
-       kobj->parent = parent;
-       return (kobject_add)(kobj);
-}
-#endif
-
-
-#endif /* linux/kobject.h wrapper */
diff --git a/datapath/linux/compat/include/linux/lockdep.h b/datapath/linux/compat/include/linux/lockdep.h
deleted file mode 100644 (file)
index da3dfe8..0000000
+++ /dev/null
@@ -1,449 +0,0 @@
-/*
- * 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 */
diff --git a/datapath/linux/compat/include/linux/mutex.h b/datapath/linux/compat/include/linux/mutex.h
deleted file mode 100644 (file)
index 38a3d0d..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-#ifndef __LINUX_MUTEX_WRAPPER_H
-#define __LINUX_MUTEX_WRAPPER_H
-
-
-#include <linux/version.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)
-
-#include <linux/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
index 2ceff22..4e2b7f5 100644 (file)
@@ -6,15 +6,6 @@
 struct net;
 
 #include <linux/version.h>
-/* Before 2.6.21, struct net_device has a "struct class_device" member named
- * class_dev.  Beginning with 2.6.21, struct net_device instead has a "struct
- * device" member named dev.  Otherwise the usage of these members is pretty
- * much the same. */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)
-#define NETDEV_DEV_MEMBER class_dev
-#else
-#define NETDEV_DEV_MEMBER dev
-#endif
 
 #ifndef to_net_dev
 #define to_net_dev(class) container_of(class, struct net_device, NETDEV_DEV_MEMBER)
@@ -25,53 +16,6 @@ extern struct sk_buff *(*openvswitch_handle_frame_hook)(struct sk_buff *skb);
 extern int nr_bridges;
 #endif
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
-static inline
-struct net *dev_net(const struct net_device *dev)
-{
-#ifdef CONFIG_NET_NS
-       return dev->nd_net;
-#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)
-       return &init_net;
-#else
-       return NULL;
-#endif
-}
-
-static inline
-void dev_net_set(struct net_device *dev, const struct net *net)
-{
-#ifdef CONFIG_NET_NS
-       dev->nd_dev = net;
-#endif
-}
-#endif /* linux kernel < 2.6.26 */
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
-#define NETIF_F_NETNS_LOCAL 0
-#endif
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
-#define proc_net init_net.proc_net
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
-typedef int netdev_tx_t;
-#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
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
-#define net_xmit_eval(e)       ((e) == NET_XMIT_CN ? 0 : (e))
-#endif
-
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
 extern void unregister_netdevice_queue(struct net_device *dev,
                                        struct list_head *head);
@@ -82,13 +26,6 @@ extern void unregister_netdevice_many(struct list_head *head);
 extern void dev_disable_lro(struct net_device *dev);
 #endif
 
-#define skb_checksum_help rpl_skb_checksum_help
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
-extern int skb_checksum_help(struct sk_buff *skb, int);
-#else
-extern int skb_checksum_help(struct sk_buff *skb);
-#endif
-
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) || \
     defined HAVE_RHEL_OVS_HOOK
 static inline int netdev_rx_handler_register(struct net_device *dev,
@@ -119,20 +56,6 @@ static inline void netdev_rx_handler_unregister(struct net_device *dev)
 }
 #endif
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
-#undef SET_ETHTOOL_OPS
-#define SET_ETHTOOL_OPS(netdev, ops) \
-       ((netdev)->ethtool_ops = (struct ethtool_ops *)(ops))
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
-#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)
-#define dev_get_by_index_rcu(net, ifindex) dev_get_by_index_rcu(ifindex)
-#endif
-
 #ifndef HAVE_DEV_GET_BY_INDEX_RCU
 static inline struct net_device *dev_get_by_index_rcu(struct net *net, int ifindex)
 {
@@ -150,17 +73,6 @@ static inline struct net_device *dev_get_by_index_rcu(struct net *net, int ifind
 #define NETIF_F_FSO 0
 #endif
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
-#define NETIF_F_FCOE_CRC       (1 << 24) /* FCoE CRC32 */
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
-#define NETIF_F_IPV6_CSUM      16      /* Can checksum TCP/UDP over IPV6 */
-
-#define NETIF_F_V4_CSUM                (NETIF_F_GEN_CSUM | NETIF_F_IP_CSUM)
-#define NETIF_F_V6_CSUM                (NETIF_F_GEN_CSUM | NETIF_F_IPV6_CSUM)
-#endif
-
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38)
 #define skb_gso_segment rpl_skb_gso_segment
 struct sk_buff *rpl_skb_gso_segment(struct sk_buff *skb, u32 features);
diff --git a/datapath/linux/compat/include/linux/netfilter_bridge.h b/datapath/linux/compat/include/linux/netfilter_bridge.h
deleted file mode 100644 (file)
index c526537..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#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
diff --git a/datapath/linux/compat/include/linux/netfilter_ipv4.h b/datapath/linux/compat/include/linux/netfilter_ipv4.h
deleted file mode 100644 (file)
index ed8a5d9..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#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
index 44a2073..a64de4f 100644 (file)
 #endif
 
 #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 */
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
-static inline struct nlmsghdr *nlmsg_hdr(const struct sk_buff *skb)
-{
-       return (struct nlmsghdr *)skb->data;
-}
-#endif
-
 #endif
index 365d126..8df8ad8 100644 (file)
@@ -1,25 +1,7 @@
 #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>
-#include <linux/rcupdate.h>
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
-#define hlist_del_init_rcu rpl_hlist_del_init_rcu
-static inline void hlist_del_init_rcu(struct hlist_node *n)
-{
-       if (!hlist_unhashed(n)) {
-               __hlist_del(n);
-               n->pprev = NULL;
-       }
-}
-#endif
 
 #ifndef hlist_first_rcu
 #define hlist_first_rcu(head)   (*((struct hlist_node __rcu **)(&(head)->first)))
diff --git a/datapath/linux/compat/include/linux/reciprocal_div.h b/datapath/linux/compat/include/linux/reciprocal_div.h
deleted file mode 100644 (file)
index f618bdd..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef __LINUX_RECIPROCAL_DIV_WRAPPER_H
-#define __LINUX_RECIPROCAL_DIV_WRAPPER_H
-
-#include <linux/version.h>
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
-#include_next <linux/reciprocal_div.h>
-#else
-
-#include <linux/types.h>
-
-/*
- * This file describes reciprocical division.
- *
- * This optimizes the (A/B) problem, when A and B are two u32
- * and B is a known value (but not known at compile time)
- *
- * The math principle used is :
- *   Let RECIPROCAL_VALUE(B) be (((1LL << 32) + (B - 1))/ B)
- *   Then A / B = (u32)(((u64)(A) * (R)) >> 32)
- *
- * This replaces a divide by a multiply (and a shift), and
- * is generally less expensive in CPU cycles.
- */
-
-/*
- * Computes the reciprocal value (R) for the value B of the divisor.
- * Should not be called before each reciprocal_divide(),
- * or else the performance is slower than a normal divide.
- */
-extern u32 reciprocal_value(u32 B);
-
-
-static inline u32 reciprocal_divide(u32 A, u32 R)
-{
-       return (u32)(((u64)A * R) >> 32);
-}
-
-#endif /* Linux kernel < 2.6.20 */
-#endif /* __LINUX_RECIPROCAL_DIV_WRAPPER_H */
index 151f823..a1b689c 100644 (file)
@@ -3,49 +3,6 @@
 
 #include_next <linux/rtnetlink.h>
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
-static inline void rtnl_notify(struct sk_buff *skb, u32 portid, u32 group,
-                              struct nlmsghdr *nlh, gfp_t flags)
-{
-       BUG_ON(nlh != NULL);            /* not implemented */
-       if (group) {
-               /* errors reported via destination sk->sk_err */
-               nlmsg_multicast(rtnl, skb, 0, group, flags);
-       }
-}
-
-static inline void rtnl_set_sk_err(u32 group, int error)
-{
-       netlink_set_err(rtnl, 0, group, error);
-}
-#endif
-
-/* No 'net' parameter in these versions. */
-#define rtnl_notify(skb, net, portid, group, nlh, flags) \
-                   ((void) rtnl_notify(skb, portid, group, nlh, flags))
-#define rtnl_set_sk_err(net, group, error) \
-                       (rtnl_set_sk_err(group, error))
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
-/* Make the return type effectively 'void' to match Linux 2.6.30+. */
-#define rtnl_notify(skb, net, portid, group, nlh, flags) \
-       ((void) rtnl_notify(skb, net, portid, group, nlh, flags))
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
-static inline int rtnl_is_locked(void)
-{
-       if (unlikely(rtnl_trylock())) {
-               rtnl_unlock();
-               return 0;
-       }
-
-       return 1;
-}
-
-#endif
-
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34)
 #ifdef CONFIG_PROVE_LOCKING
 static inline int lockdep_rtnl_is_held(void)
index 461e07c..a486096 100644 (file)
@@ -5,17 +5,6 @@
 
 #include <linux/version.h>
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
-/* In version 2.6.24 the return type of skb_headroom() changed from 'int' to
- * 'unsigned int'.  We use skb_headroom() as one arm of a min(a,b) invocation
- * in make_writable() in actions.c, so we need the correct type. */
-#define skb_headroom rpl_skb_headroom
-static inline unsigned int rpl_skb_headroom(const struct sk_buff *skb)
-{
-       return skb->data - skb->head;
-}
-#endif
-
 #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,
@@ -82,13 +71,6 @@ static inline int skb_cow_head(struct sk_buff *skb, unsigned int headroom)
 }
 #endif /* !HAVE_SKB_COW_HEAD */
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
-static inline int skb_clone_writable(struct sk_buff *skb, int len)
-{
-       return false;
-}
-#endif
-
 #ifndef HAVE_SKB_DST_ACCESSOR_FUNCS
 static inline struct dst_entry *skb_dst(const struct sk_buff *skb)
 {
@@ -106,18 +88,6 @@ static inline struct rtable *skb_rtable(const struct sk_buff *skb)
 }
 #endif
 
-#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
 #define CHECKSUM_PARTIAL CHECKSUM_HW
 #endif
@@ -196,21 +166,6 @@ static inline void skb_copy_to_linear_data(struct sk_buff *skb,
 }
 #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 */
-
 #ifndef HAVE_SKB_WARN_LRO
 #ifndef NETIF_F_LRO
 static inline bool skb_warn_if_lro(const struct sk_buff *skb)
diff --git a/datapath/linux/compat/include/linux/slab.h b/datapath/linux/compat/include/linux/slab.h
deleted file mode 100644 (file)
index 9d6ad1f..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef __LINUX_SLAB_WRAPPER_H
-#define __LINUX_SLAB_WRAPPER_H 1
-
-#include_next <linux/slab.h>
-
-#ifndef HAVE_KMEMDUP
-extern void *kmemdup(const void *src, size_t len, gfp_t gfp);
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
-#define kmem_cache_create(n, s, a, f, c) kmem_cache_create(n, s, a, f, c, NULL)
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
-static inline void *rpl_kzalloc(size_t size, gfp_t flags)
-{
-       return kzalloc(size, flags & ~__GFP_ZERO);
-}
-#define kzalloc rpl_kzalloc
-
-static inline void *rpl_kmalloc(size_t size, gfp_t flags)
-{
-       if (flags & __GFP_ZERO)
-               return kzalloc(size, flags);
-
-       return kmalloc(size, flags);
-}
-#define kmalloc rpl_kmalloc
-#endif
-
-#endif
diff --git a/datapath/linux/compat/include/linux/timer.h b/datapath/linux/compat/include/linux/timer.h
deleted file mode 100644 (file)
index b9954a5..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-#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
index 502d02d..a40de40 100644 (file)
@@ -32,14 +32,13 @@ static inline void csum_replace2(__sum16 *sum, __be16 from, __be16 to)
 }
 #endif
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
-#define inet_proto_csum_replace2(sum, skb, from, to, pseudohdr) \
-       inet_proto_csum_replace4(sum, skb, (__force __be32)(from), \
-                                          (__force __be32)(to), pseudohdr)
-#endif
-
 #ifndef CSUM_MANGLED_0
 #define CSUM_MANGLED_0 ((__force __sum16)0xffff)
 #endif
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)
+void inet_proto_csum_replace16(__sum16 *sum, struct sk_buff *skb,
+                              const __be32 *from, const __be32 *to,
+                              int pseudohdr);
+#endif
 #endif /* checksum.h */
index ac199ec..91be168 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/version.h>
 #include <linux/netlink.h>
 #include <net/net_namespace.h>
+#include_next <net/genetlink.h>
 
 /*
  * 15e473046cb6e5d18a4d0057e61d76315230382b renames pid to portid
 #define portid pid
 #endif
 
-/* Very special super-nasty workaround here:
- *
- * Before 2.6.19, nlmsg_multicast() lacked a 'flags' parameter.  We work
- * around that in our <net/netlink.h> replacement, so that nlmsg_multicast
- * is a macro that expands to rpl_nlmsg_multicast, which in turn has the
- * 'flags' parameter.
- *
- * However, also before 2.6.19, <net/genetlink.h> contains an inline definition
- * of genlmsg_multicast() that, of course, calls it without the 'flags'
- * parameter.  This causes a build failure.
- *
- * This works around the problem by temporarily renaming both nlmsg_multicast
- * and genlmsg_multicast with a "busted_" prefix.  (Nothing actually defines
- * busted_nlmsg_multicast(), so if anything actually tries to call it, then
- * we'll get a link error.)
- */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
-#undef nlmsg_multicast
-#define nlmsg_multicast busted_nlmsg_multicast
-#define genlmsg_multicast busted_genlmsg_multicast
-extern int busted_nlmsg_multicast(struct sock *sk, struct sk_buff *skb,
-                                 u32 portid, unsigned int group);
-#endif /* linux kernel < v2.6.19 */
-
-#include_next <net/genetlink.h>
-
-/* Drop the "busted_" prefix described above. */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
-#undef nlmsg_multicast
-#undef genlmsg_multicast
-#define nlmsg_multicast rpl_nlmsg_multicast
-#endif /* linux kernel < v2.6.19 */
-
-#include <net/net_namespace.h>
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
-
-#include <linux/genetlink.h>
-
-/**
- * struct genl_multicast_group - generic netlink multicast group
- * @name: name of the multicast group, names are per-family
- * @id: multicast group ID, assigned by the core, to use with
- *       genlmsg_multicast().
- * @list: list entry for linking
- * @family: pointer to family, need not be set before registering
- */
-struct genl_multicast_group {
-       struct genl_family  *family;    /* private */
-       struct list_head        list;      /* private */
-       char name[GENL_NAMSIZ];
-       u32     id;
-};
-
-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 portid,
-               unsigned int group, gfp_t flags)
-{
-       int err;
-
-       NETLINK_CB(skb).dst_group = group;
-
-       err = netlink_broadcast(genl_sock, skb, portid, group, flags);
-       if (err > 0)
-               err = 0;
-
-       return err;
-}
-#endif /* linux kernel < 2.6.19 */
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
-#define genlmsg_multicast_netns(net, skb, portid, grp, flags) \
-               genlmsg_multicast(skb, portid, grp, flags)
-#endif
-
-#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_portid, 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_portid);
-}
-
-/**
- * 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 */
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31)
-int genl_register_family_with_ops(struct genl_family *family,
-       struct genl_ops *ops, size_t n_ops);
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
-#define genl_notify(skb, net, portid, group, nlh, flags) \
-       genl_notify(skb, portid, group, nlh, flags)
-#endif
 extern void genl_notify(struct sk_buff *skb, struct net *net, u32 portid,
                        u32 group, struct nlmsghdr *nlh, gfp_t flags);
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) && \
-    LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
-static inline struct net *genl_info_net(struct genl_info *info)
-{
-       return &init_net;
-}
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
-#define genlmsg_unicast(ignore_net, skb, portid)   genlmsg_unicast(skb, portid)
-#endif
 #endif /* genetlink.h */
index 1dccdea..4193d32 100644 (file)
@@ -4,12 +4,6 @@
 #include_next <net/ip.h>
 
 #include <linux/version.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
-
-extern int             __ip_local_out(struct sk_buff *skb);
-extern int             ip_local_out(struct sk_buff *skb);
-
-#endif /* linux kernel < 2.6.25 */
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,1,0)
 static inline bool ip_is_fragment(const struct iphdr *iph)
index 440c601..be64093 100644 (file)
@@ -1,69 +1,10 @@
 #ifndef __NET_NET_NAMESPACE_WRAPPER_H
 #define __NET_NET_NAMESPACE_WRAPPER_H 1
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
-/* <net/net_namespace.h> exists, go ahead and include it. */
 #include_next <net/net_namespace.h>
-#else
-/* No network namespace support. */
-struct net;
-
-static inline struct net *hold_net(struct net *net)
-{
-       return net;
-}
-
-static inline void release_net(struct net *net)
-{
-}
-
-#define __net_init      __init
-#define __net_exit      __exit
-#endif /* 2.6.24 */
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
-#ifdef CONFIG_NET_NS
-static inline
-int net_eq(const struct net *net1, const struct net *net2)
-{
-       return net1 == net2;
-}
-#else
-static inline
-int net_eq(const struct net *net1, const struct net *net2)
-{
-       return 1;
-}
-#endif /* CONFIG_NET_NS */
-#endif /* 2.6.26 */
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
-#ifdef CONFIG_NET_NS
-
-static inline void write_pnet(struct net **pnet, struct net *net)
-{
-       *pnet = net;
-}
-
-static inline struct net *read_pnet(struct net * const *pnet)
-{
-       return *pnet;
-}
-
-#else
-
-#define write_pnet(pnet, net)   do { (void)(net); } while (0)
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
-#define read_pnet(pnet)         (&init_net)
-#else
-#define read_pnet(pnet)         (NULL)
-#endif /* 2.6.24 */
-
-#endif /* CONFIG_NET_NS */
-#endif /* 2.6.29 */
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
+/* for 2.6.32* */
 struct rpl_pernet_operations {
        int (*init)(struct net *net);
        void (*exit)(struct net *net);
@@ -76,12 +17,6 @@ struct rpl_pernet_operations {
 #define register_pernet_device rpl_register_pernet_gen_device
 #define unregister_pernet_device rpl_unregister_pernet_gen_device
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
-extern int rpl_register_pernet_gen_device(struct rpl_pernet_operations *ops);
-extern void rpl_unregister_pernet_gen_device(struct rpl_pernet_operations *ops);
-
-#else /* for 2.6.32* */
-
 int compat_init_net(struct net *net, struct rpl_pernet_operations *pnet);
 void compat_exit_net(struct net *net, struct rpl_pernet_operations *pnet);
 
@@ -110,18 +45,8 @@ static void rpl_unregister_pernet_gen_##TYPE(struct rpl_pernet_operations *rpl_p
 {                                                                                      \
        unregister_pernet_gen_##TYPE(*pnet_gen_##TYPE->id, &rpl_pnet->ops);             \
 }
-#endif
-#endif /* 2.6.33 */
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) || \
-    LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)
+#else
 #define DEFINE_COMPAT_PNET_REG_FUNC(TYPE)
 #endif /* 2.6.33 */
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
-#undef for_each_net
-#define for_each_net(net)   { net = NULL; }
-
-#endif /* 2.6.32 */
-
 #endif /* net/net_namespace.h wrapper */
index 308cd69..a6dc584 100644 (file)
@@ -4,31 +4,6 @@
 #include <linux/version.h>
 #include_next <net/netlink.h>
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
-/* Before v2.6.29, a NLA_NESTED attribute, if it was present, was not allowed
- * to be empty.  However, OVS depends on the ability to accept empty
- * attributes.  For example, a present but empty OVS_FLOW_ATTR_ACTIONS on
- * OVS_FLOW_CMD_SET replaces the existing set of actions by an empty "drop"
- * action, whereas a missing OVS_FLOW_ATTR_ACTIONS leaves the existing
- * actions, if any, unchanged.
- *
- * NLA_NESTED is different from NLA_UNSPEC in only two ways:
- *
- * - If the size of the nested attributes is zero, no further size checks
- *   are performed.
- *
- * - If the size of the nested attributes is not zero and no length
- *   parameter is specified the minimum size of nested attributes is
- *   NLA_HDRLEN.
- *
- * nla_parse_nested() validates that there is at least enough space for
- * NLA_HDRLEN, so neither of these conditions are important, and we might
- * as well use NLA_UNSPEC with old kernels.
- */
-#undef NLA_NESTED
-#define NLA_NESTED NLA_UNSPEC
-#endif
-
 #ifndef HAVE_NLA_GET_BE16
 /**
  * nla_get_be16 - return payload of __be16 attribute
@@ -40,36 +15,6 @@ static inline __be16 nla_get_be16(const struct nlattr *nla)
 }
 #endif  /* !HAVE_NLA_GET_BE16 */
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
-/**
- * nla_get_be32 - return payload of __be32 attribute
- * @nla: __be32 netlink attribute
- */
-static inline __be32 nla_get_be32(const struct nlattr *nla)
-{
-       return *(__be32 *) nla_data(nla);
-}
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
-/* These functions' nlattr source arguments weren't "const" before 2.6.29, so
- * cast their arguments to the non-"const" versions.  Using macros for this
- * isn't exactly a brilliant idea, but it seems less error-prone than copying
- * the definitions of all umpteen functions. */
-#define nla_get_u64(nla)   (nla_get_u64)  ((struct nlattr *) (nla))
-#define nla_get_u32(nla)   (nla_get_u32)  ((struct nlattr *) (nla))
-#define nla_get_u16(nla)   (nla_get_u16)  ((struct nlattr *) (nla))
-#define nla_get_u8(nla)    (nla_get_u8)   ((struct nlattr *) (nla))
-/* nla_get_be64 is handled separately below. */
-#define nla_get_be32(nla)  (nla_get_be32) ((struct nlattr *) (nla))
-#define nla_get_be16(nla)  (nla_get_be16) ((struct nlattr *) (nla))
-#define nla_get_be8(nla)   (nla_get_be8)  ((struct nlattr *) (nla))
-#define nla_get_flag(nla)  (nla_get_flag) ((struct nlattr *) (nla))
-#define nla_get_msecs(nla) (nla_get_msecs)((struct nlattr *) (nla))
-#define nla_memcpy(dst, src, count) \
-       (nla_memcpy)(dst, (struct nlattr *)(src), count)
-#endif
-
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34)
 /* This function was introduced in 2.6.31, but initially it performed an
  * unaligned access, so we replace it up to 2.6.34 where it was fixed.  */
@@ -106,26 +51,6 @@ static inline int nla_put_be64(struct sk_buff *skb, int attrtype, __be64 value)
 }
 #endif
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
-/**
- * nla_type - attribute type
- * @nla: netlink attribute
- */
-static inline int nla_type(const struct nlattr *nla)
-{
-       return nla->nla_type & NLA_TYPE_MASK;
-}
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
-#define nla_parse_nested(tb, maxtype, nla, policy) \
-       nla_parse_nested(tb, maxtype, (struct nlattr *)(nla), \
-                       (struct nla_policy *)(policy))
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
-#define nla_parse_nested(tb, maxtype, nla, policy) \
-       nla_parse_nested(tb, maxtype, (struct nlattr *)(nla), policy)
-#endif
-
 #ifndef nla_for_each_nested
 #define nla_for_each_nested(pos, nla, rem) \
        nla_for_each_attr(pos, nla_data(nla), nla_len(nla), rem)
@@ -138,42 +63,4 @@ static inline struct nlattr *nla_find_nested(struct nlattr *nla, int attrtype)
 }
 #endif
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
-/**
- * nlmsg_report - need to report back to application?
- * @nlh: netlink message header
- *
- * Returns 1 if a report back to the application is requested.
- */
-static inline int nlmsg_report(const struct nlmsghdr *nlh)
-{
-       return !!(nlh->nlmsg_flags & NLM_F_ECHO);
-}
-
-extern int             nlmsg_notify(struct sock *sk, struct sk_buff *skb,
-                                    u32 portid, unsigned int group, int report,
-                                    gfp_t flags);
-#endif /* linux kernel < 2.6.19 */
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
-/* Before 2.6.19 the 'flags' parameter was missing, so replace it.  We have to
- * #include <net/genetlink.h> first because the 2.6.18 version of that header
- * has an inline call to nlmsg_multicast() without, of course, any 'flags'
- * argument. */
-#define nlmsg_multicast rpl_nlmsg_multicast
-static inline int nlmsg_multicast(struct sock *sk, struct sk_buff *skb,
-                                 u32 portid, unsigned int group, gfp_t flags)
-{
-       int err;
-
-       NETLINK_CB(skb).dst_group = group;
-
-       err = netlink_broadcast(sk, skb, portid, group, flags);
-       if (err > 0)
-               err = 0;
-
-       return err;
-}
-#endif /* linux kernel < 2.6.19 */
-
 #endif /* net/netlink.h */
diff --git a/datapath/linux/compat/include/net/netns/generic.h b/datapath/linux/compat/include/net/netns/generic.h
deleted file mode 100644 (file)
index 1a0303f..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef __NET_NET_NETNS_GENERIC_WRAPPER_H
-#define __NET_NET_NETNS_GENERIC_WRAPPER_H 1
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
-/* <net/netns/generic.h> exists, go ahead and include it. */
-#include_next <net/netns/generic.h>
-#else
-#define net_generic rpl_net_generic
-void *net_generic(const struct net *net, int id);
-#endif
-
-#endif /* net/netns/generic.h wrapper */
diff --git a/datapath/linux/compat/include/net/protocol.h b/datapath/linux/compat/include/net/protocol.h
deleted file mode 100644 (file)
index 6ffe0cb..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef __NET_PROTOCOL_WRAPPER_H
-#define __NET_PROTOCOL_WRAPPER_H 1
-
-#include_next <net/protocol.h>
-
-#include <linux/version.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
-#define inet_add_protocol(prot, num) inet_add_protocol((struct net_protocol *)(prot), num)
-#define inet_del_protocol(prot, num) inet_del_protocol((struct net_protocol *)(prot), num)
-#endif
-
-#endif
diff --git a/datapath/linux/compat/include/net/route.h b/datapath/linux/compat/include/net/route.h
deleted file mode 100644 (file)
index 86e8e5b..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef __NET_ROUTE_WRAPPER_H
-#define __NET_ROUTE_WRAPPER_H 1
-
-#include_next <net/route.h>
-
-#include <linux/version.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
-
-#define ip_route_output_key(net, rp, flp) \
-               ip_route_output_key((rp), (flp))
-
-#endif /* linux kernel < 2.6.25 */
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38)
-static inline int ip4_dst_hoplimit(const struct dst_entry *dst)
-{
-       return dst_metric(dst, RTAX_HOPLIMIT);
-}
-#endif
-
-#endif
index 11fb0b6..59d209b 100644 (file)
@@ -2,12 +2,7 @@
 #define __SCTP_CHECKSUM_WRAPPER_H 1
 
 #include <linux/version.h>
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
-#include <net/sctp/sctp.h>
-#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25) */
 #include_next <net/sctp/checksum.h>
-#endif
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,12,0)
 static inline __le32 sctp_compute_cksum(const struct sk_buff *skb,
diff --git a/datapath/linux/compat/include/net/sock.h b/datapath/linux/compat/include/net/sock.h
deleted file mode 100644 (file)
index 513489a..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef __NET_SOCK_WRAPPER_H
-#define __NET_SOCK_WRAPPER_H 1
-
-#include_next <net/sock.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
-struct net;
-
-static inline struct net *sock_net(const struct sock *sk)
-{
-       return NULL;
-}
-
-#endif
-
-#endif /* net/sock.h wrapper */
index 102bc0c..46cbfb6 100644 (file)
@@ -5,35 +5,26 @@
 #include <linux/netdevice.h>
 #include <linux/udp.h>
 
+struct vxlan_sock;
+typedef void (vxlan_rcv_t)(struct vxlan_sock *vs, struct sk_buff *skb, __be32 key);
+
 /* per UDP socket information */
 struct vxlan_sock {
        struct hlist_node hlist;
-       struct rcu_head   rcu;
-       struct socket     *sock;
-       struct list_head  handler_list;
-};
-
-struct vxlan_handler;
-typedef int (vxlan_rcv_t)(struct vxlan_handler *vh, struct sk_buff *skb, __be32 key);
-
-struct vxlan_handler {
-       vxlan_rcv_t       *rcv;
-       struct list_head   node;
-       void              *data;
-       struct vxlan_sock *vs;
-       atomic_t           refcnt;
-       struct rcu_head    rcu;
+       vxlan_rcv_t      *rcv;
+       void             *data;
        struct work_struct del_work;
-       int                priority;
+       struct socket    *sock;
+       struct rcu_head   rcu;
 };
 
-void vxlan_handler_put(struct vxlan_handler *vh);
+struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port,
+                                 vxlan_rcv_t *rcv, void *data,
+                                 bool no_share);
 
-struct vxlan_handler *vxlan_handler_add(struct net *net,
-                                       __be16 portno, vxlan_rcv_t *rcv,
-                                       void *data, int priority, bool create);
+void vxlan_sock_release(struct vxlan_sock *vs);
 
-int vxlan_xmit_skb(struct net *net, struct vxlan_handler *vh,
+int vxlan_xmit_skb(struct net *net, struct vxlan_sock *vs,
                   struct rtable *rt, struct sk_buff *skb,
                   __be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df,
                   __be16 src_port, __be16 dst_port, __be32 vni);
diff --git a/datapath/linux/compat/ip_output-openvswitch.c b/datapath/linux/compat/ip_output-openvswitch.c
deleted file mode 100644 (file)
index a09fcbc..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-#include <linux/version.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
-
-#include <linux/netfilter_ipv4.h>
-#include <net/ip.h>
-
-int __ip_local_out(struct sk_buff *skb)
-{
-       struct iphdr *iph = ip_hdr(skb);
-
-       iph->tot_len = htons(skb->len);
-       ip_send_check(iph);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
-       return nf_hook(PF_INET, NF_IP_LOCAL_OUT, &skb, NULL, skb->dst->dev,
-                      dst_output);
-#else
-       return nf_hook(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, skb->dst->dev,
-                      dst_output);
-#endif /* kernel < 2.6.24 */
-}
-
-int ip_local_out(struct sk_buff *skb)
-{
-       int err;
-
-       err = __ip_local_out(skb);
-       if (likely(err == 1))
-               err = dst_output(skb);
-
-       return err;
-}
-
-#endif /* kernel < 2.6.25 */
index 01cc2fb..f9f6cae 100644 (file)
@@ -31,7 +31,6 @@
 #include <net/route.h>
 #include <net/xfrm.h>
 
-#include "checksum.h"
 #include "compat.h"
 #include "gso.h"
 
@@ -100,9 +99,6 @@ int iptunnel_pull_header(struct sk_buff *skb, int hdr_len, __be16 inner_proto)
                skb->protocol = inner_proto;
        }
 
-       if (unlikely(compute_ip_summed(skb, false)))
-               return -EPROTO;
-
        nf_reset(skb);
        secpath_reset(skb);
        skb_clear_rxhash(skb);
diff --git a/datapath/linux/compat/kmemdup.c b/datapath/linux/compat/kmemdup.c
deleted file mode 100644 (file)
index b5188fd..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef HAVE_KMEMDUP
-
-#include <linux/slab.h>
-#include <linux/string.h>
-
-/**
- * kmemdup - duplicate region of memory
- *
- * @src: memory region to duplicate
- * @len: memory region length
- * @gfp: GFP mask to use
- */
-void *kmemdup(const void *src, size_t len, gfp_t gfp)
-{
-       void *p;
-
-       p = kmalloc(len, gfp);
-       if (p)
-               memcpy(p, src, len);
-       return p;
-}
-#endif
index 843e6c1..1fba3b1 100644 (file)
@@ -4,9 +4,6 @@
 #include <net/netns/generic.h>
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
-static int net_assign_generic(struct net *net, int id, void *data);
-#endif
 
 int compat_init_net(struct net *net, struct rpl_pernet_operations *pnet)
 {
@@ -41,35 +38,3 @@ void compat_exit_net(struct net *net, struct rpl_pernet_operations *pnet)
        kfree(ovs_net);
 }
 #endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
-#define MAX_DATA_COUNT 2
-static struct net *net;
-
-static void *__ovs_net_data[MAX_DATA_COUNT];
-static int count;
-
-static int net_assign_generic(struct net *net, int id, void *data)
-{
-       BUG_ON(id >= MAX_DATA_COUNT);
-       __ovs_net_data[id] = data;
-       return 0;
-}
-
-void *net_generic(const struct net *net, int id)
-{
-       return __ovs_net_data[id];
-}
-
-int rpl_register_pernet_gen_device(struct rpl_pernet_operations *rpl_pnet)
-{
-       *rpl_pnet->id = count++;
-       return compat_init_net(net, rpl_pnet);
-}
-
-void rpl_unregister_pernet_gen_device(struct rpl_pernet_operations *rpl_pnet)
-{
-       compat_exit_net(net, rpl_pnet);
-}
-
-#endif
index f03efde..248066d 100644 (file)
@@ -49,11 +49,7 @@ static u32 harmonize_features(struct sk_buff *skb, __be16 protocol, u32 features
 
 u32 rpl_netif_skb_features(struct sk_buff *skb)
 {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
-       unsigned long vlan_features = 0;
-#else
        unsigned long vlan_features = skb->dev->vlan_features;
-#endif /* kernel version < 2.6.26 */
 
        __be16 protocol = skb->protocol;
        u32 features = skb->dev->features;
index 6a3bd48..7ec7528 100644 (file)
@@ -1,9 +1,13 @@
 #include <asm/div64.h>
 #include <linux/reciprocal_div.h>
 
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0)
+/* definition is required since reciprocal_value() is not exported */
 u32 reciprocal_value(u32 k)
 {
        u64 val = (1LL << 32) + (k - 1);
        do_div(val, k);
        return (u32)val;
 }
+#endif
index 2707ef0..3baa09e 100644 (file)
@@ -14,25 +14,3 @@ void __skb_warn_lro_forwarding(const struct sk_buff *skb)
 }
 
 #endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
-int skb_checksum_help(struct sk_buff *skb, int inward)
-#else
-int skb_checksum_help(struct sk_buff *skb)
-#endif
-{
-       if (unlikely(skb_is_nonlinear(skb))) {
-               int err;
-
-               err = __skb_linearize(skb);
-               if (unlikely(err))
-                       return err;
-       }
-
-#undef skb_checksum_help
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
-       return skb_checksum_help(skb, 0);
-#else
-       return skb_checksum_help(skb);
-#endif
-}
diff --git a/datapath/linux/compat/time.c b/datapath/linux/compat/time.c
deleted file mode 100644 (file)
index 490e1a4..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-#include <linux/time.h>
-
-#include <linux/version.h>
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
-
-/* "set_normalized_timespec" is defined but not exported in kernels
- * before 2.6.26. */
-
-/**
- * set_normalized_timespec - set timespec sec and nsec parts and normalize
- *
- * @ts:         pointer to timespec variable to be set
- * @sec:        seconds to set
- * @nsec:       nanoseconds to set
- *
- * Set seconds and nanoseconds field of a timespec variable and
- * normalize to the timespec storage format
- *
- * Note: The tv_nsec part is always in the range of
- *      0 <= tv_nsec < NSEC_PER_SEC
- * For negative values only the tv_sec field is negative !
- */
-void set_normalized_timespec(struct timespec *ts,
-                            time_t sec, long nsec)
-{
-       while (nsec >= NSEC_PER_SEC) {
-               nsec -= NSEC_PER_SEC;
-               ++sec;
-       }
-       while (nsec < 0) {
-               nsec += NSEC_PER_SEC;
-               --sec;
-       }
-       ts->tv_sec = sec;
-       ts->tv_nsec = nsec;
-}
-
-#endif /* linux kernel < 2.6.26 */
diff --git a/datapath/linux/compat/utils.c b/datapath/linux/compat/utils.c
new file mode 100644 (file)
index 0000000..844d372
--- /dev/null
@@ -0,0 +1,39 @@
+#include <linux/module.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/ctype.h>
+#include <linux/inet.h>
+#include <linux/mm.h>
+#include <linux/net.h>
+#include <net/checksum.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/percpu.h>
+#include <linux/init.h>
+#include <linux/ratelimit.h>
+
+#include <net/sock.h>
+
+#include <asm/byteorder.h>
+#include <asm/uaccess.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)
+void inet_proto_csum_replace16(__sum16 *sum, struct sk_buff *skb,
+                              const __be32 *from, const __be32 *to,
+                              int pseudohdr)
+{
+       __be32 diff[] = {
+               ~from[0], ~from[1], ~from[2], ~from[3],
+               to[0], to[1], to[2], to[3],
+       };
+       if (skb->ip_summed != CHECKSUM_PARTIAL) {
+               *sum = csum_fold(csum_partial(diff, sizeof(diff),
+                                       ~csum_unfold(*sum)));
+               if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr)
+                       skb->csum = ~csum_partial(diff, sizeof(diff),
+                                       ~skb->csum);
+       } else if (pseudohdr)
+               *sum = ~csum_fold(csum_partial(diff, sizeof(diff),
+                                       csum_unfold(*sum)));
+}
+#endif
index f3df4e3..d774b6c 100644 (file)
@@ -51,7 +51,6 @@
 #include <net/netns/generic.h>
 #include <net/vxlan.h>
 
-#include "checksum.h"
 #include "compat.h"
 #include "gso.h"
 #include "vlan.h"
@@ -59,8 +58,6 @@
 #define PORT_HASH_BITS 8
 #define PORT_HASH_SIZE  (1<<PORT_HASH_BITS)
 
-#define VXLAN_N_VID    (1u << 24)
-#define VXLAN_VID_MASK (VXLAN_N_VID - 1)
 /* IP header + UDP + VXLAN + Ethernet header */
 #define VXLAN_HEADROOM (20 + 8 + 8 + 14)
 #define VXLAN_HLEN (sizeof(struct udphdr) + sizeof(struct vxlanhdr))
@@ -75,10 +72,13 @@ struct vxlanhdr {
 
 static int vxlan_net_id;
 
+static int vxlan_init_module(void);
+static void vxlan_cleanup_module(void);
+
 /* per-network namespace private data for this module */
 struct vxlan_net {
        struct hlist_head sock_list[PORT_HASH_SIZE];
-       struct mutex      sock_lock;    /* RTNL lock nests inside this lock. */
+       spinlock_t  sock_lock;
 };
 
 /* Socket hash table head */
@@ -90,7 +90,8 @@ static inline struct hlist_head *vs_head(struct net *net, __be16 port)
 }
 
 /* Find VXLAN socket based on network namespace and UDP port */
-static struct vxlan_sock *vxlan_find_port(struct net *net, __be16 port)
+
+static struct vxlan_sock *vxlan_find_sock(struct net *net, __be16 port)
 {
        struct vxlan_sock *vs;
 
@@ -104,7 +105,6 @@ static struct vxlan_sock *vxlan_find_port(struct net *net, __be16 port)
 /* Callback from net/ipv4/udp.c to receive packets */
 static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
 {
-       struct vxlan_handler *vh;
        struct vxlan_sock *vs;
        struct vxlanhdr *vxh;
 
@@ -124,14 +124,12 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
        if (iptunnel_pull_header(skb, VXLAN_HLEN, htons(ETH_P_TEB)))
                goto drop;
 
-       vs = vxlan_find_port(sock_net(sk), inet_sport(sk));
+       vs = vxlan_find_sock(sock_net(sk), inet_sport(sk));
        if (!vs)
                goto drop;
 
-       list_for_each_entry_rcu(vh, &vs->handler_list, node) {
-               if (vh->rcv(vh, skb, vxh->vx_vni) == PACKET_RCVD)
-                       return 0;
-       }
+       vs->rcv(vs, skb, vxh->vx_vni);
+       return 0;
 
 drop:
        /* Consume bad packet */
@@ -211,7 +209,7 @@ static int handle_offloads(struct sk_buff *skb)
        return 0;
 }
 
-int vxlan_xmit_skb(struct net *net, struct vxlan_handler *vh,
+int vxlan_xmit_skb(struct net *net, struct vxlan_sock *vs,
                   struct rtable *rt, struct sk_buff *skb,
                   __be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df,
                   __be16 src_port, __be16 dst_port, __be32 vni)
@@ -232,8 +230,14 @@ int vxlan_xmit_skb(struct net *net, struct vxlan_handler *vh,
        if (unlikely(err))
                return err;
 
-       if (unlikely(vlan_deaccel_tag(skb)))
-               return -ENOMEM;
+       if (vlan_tx_tag_present(skb)) {
+               if (unlikely(!__vlan_put_tag(skb,
+                                               skb->vlan_proto,
+                                               vlan_tx_tag_get(skb))))
+                       return -ENOMEM;
+
+               vlan_set_tci(skb, 0);
+       }
 
        vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh));
        vxh->vx_flags = htonl(VXLAN_FLAGS);
@@ -249,7 +253,7 @@ int vxlan_xmit_skb(struct net *net, struct vxlan_handler *vh,
        uh->len = htons(skb->len);
        uh->check = 0;
 
-       vxlan_set_owner(vh->vs->sock->sk, skb);
+       vxlan_set_owner(vs->sock->sk, skb);
 
        err = handle_offloads(skb);
        if (err)
@@ -259,8 +263,26 @@ int vxlan_xmit_skb(struct net *net, struct vxlan_handler *vh,
                        IPPROTO_UDP, tos, ttl, df);
 }
 
-static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port)
+static void rcu_free_vs(struct rcu_head *rcu)
 {
+       struct vxlan_sock *vs = container_of(rcu, struct vxlan_sock, rcu);
+
+       kfree(vs);
+}
+
+static void vxlan_del_work(struct work_struct *work)
+{
+       struct vxlan_sock *vs = container_of(work, struct vxlan_sock, del_work);
+
+       sk_release_kernel(vs->sock->sk);
+       call_rcu(&vs->rcu, rcu_free_vs);
+       vxlan_cleanup_module();
+}
+
+static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port,
+                                             vxlan_rcv_t *rcv, void *data)
+{
+       struct vxlan_net *vn = net_generic(net, vxlan_net_id);
        struct vxlan_sock *vs;
        struct sock *sk;
        struct sockaddr_in vxlan_addr = {
@@ -271,8 +293,12 @@ static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port)
        int rc;
 
        vs = kmalloc(sizeof(*vs), GFP_KERNEL);
-       if (!vs)
+       if (!vs) {
+               pr_debug("memory alocation failure\n");
                return ERR_PTR(-ENOMEM);
+       }
+
+       INIT_WORK(&vs->del_work, vxlan_del_work);
 
        /* Create UDP socket for encapsulation receive. */
        rc = sock_create_kern(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &vs->sock);
@@ -287,81 +313,36 @@ static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port)
        sk_change_net(sk, net);
 
        rc = kernel_bind(vs->sock, (struct sockaddr *) &vxlan_addr,
-                        sizeof(vxlan_addr));
+                       sizeof(vxlan_addr));
        if (rc < 0) {
                pr_debug("bind for UDP socket %pI4:%u (%d)\n",
-                        &vxlan_addr.sin_addr, ntohs(vxlan_addr.sin_port), rc);
+                               &vxlan_addr.sin_addr, ntohs(vxlan_addr.sin_port), rc);
                sk_release_kernel(sk);
                kfree(vs);
                return ERR_PTR(rc);
        }
+       vs->rcv = rcv;
+       vs->data = data;
 
        /* Disable multicast loopback */
        inet_sk(sk)->mc_loop = 0;
-       INIT_LIST_HEAD(&vs->handler_list);
+       spin_lock(&vn->sock_lock);
        hlist_add_head_rcu(&vs->hlist, vs_head(net, port));
+       spin_unlock(&vn->sock_lock);
 
        /* Mark socket as an encapsulation socket. */
        udp_sk(sk)->encap_type = 1;
        udp_sk(sk)->encap_rcv = vxlan_udp_encap_recv;
        udp_encap_enable();
-
        return vs;
 }
 
-static void rcu_free_vs_callback(struct rcu_head *rcu)
-{
-       struct vxlan_sock *vs = container_of(rcu, struct vxlan_sock, rcu);
-
-       kfree(vs);
-}
-
-static void vxlan_socket_del(struct vxlan_sock *vs)
-{
-       if (list_empty(&vs->handler_list)) {
-               hlist_del_rcu(&vs->hlist);
-
-               sk_release_kernel(vs->sock->sk);
-               call_rcu(&vs->rcu, rcu_free_vs_callback);
-       }
-}
-
-static int vxlan_init_module(void);
-static void vxlan_cleanup_module(void);
-
-static void rcu_free_vh_callback(struct rcu_head *rcu)
-{
-       struct vxlan_handler *vh = container_of(rcu, struct vxlan_handler, rcu);
-
-       kfree(vh);
-}
-
-static void vh_del_work(struct work_struct *work)
-{
-       struct vxlan_handler *vh = container_of(work, struct vxlan_handler, del_work);
-       struct vxlan_sock *vs = vh->vs;
-       struct net *net = sock_net(vs->sock->sk);
-       struct vxlan_net *vn = net_generic(net, vxlan_net_id);
-
-       mutex_lock(&vn->sock_lock);
-
-       list_del_rcu(&vh->node);
-       call_rcu(&vh->rcu, rcu_free_vh_callback);
-       vxlan_socket_del(vs);
-
-       mutex_unlock(&vn->sock_lock);
-
-       vxlan_cleanup_module();
-}
-
-struct vxlan_handler *vxlan_handler_add(struct net *net,
-                                       __be16 portno, vxlan_rcv_t *rcv,
-                                       void *data, int priority, bool create)
+struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port,
+                                 vxlan_rcv_t *rcv, void *data,
+                                 bool no_share)
 {
        struct vxlan_net *vn;
        struct vxlan_sock *vs;
-       struct vxlan_handler *vh;
-       struct vxlan_handler *new;
        int err;
 
        err = vxlan_init_module();
@@ -369,64 +350,19 @@ struct vxlan_handler *vxlan_handler_add(struct net *net,
                return ERR_PTR(err);
 
        vn = net_generic(net, vxlan_net_id);
-       mutex_lock(&vn->sock_lock);
-       /* Look to see if can reuse socket */
-       vs = vxlan_find_port(net, portno);
-       if (!vs) {
-               vs = vxlan_socket_create(net, portno);
-               if (IS_ERR(vs)) {
-                       new = (void *) vs;
-                       goto out;
-               }
-       }
-
-       /* Try existing vxlan hanlders for this socket. */
-       list_for_each_entry(vh, &vs->handler_list, node) {
-               if (vh->rcv == rcv) {
-                       if (create) {
-                               vxlan_socket_del(vs);
-                               new = ERR_PTR(-EEXIST);
-                               goto out;
-                       }
-                       atomic_inc(&vh->refcnt);
-                       new = vh;
-                       goto out;
-               }
-       }
-
-       new = kzalloc(sizeof(*new), GFP_KERNEL);
-       if (!new) {
-               vxlan_socket_del(vs);
-               new = ERR_PTR(-ENOMEM);
-               goto out;
-       }
-
-       new->rcv = rcv;
-       new->vs = vs;
-       atomic_set(&new->refcnt, 1);
-       INIT_WORK(&new->del_work, vh_del_work);
-       new->data = data;
-       new->priority = priority;
-
-       list_for_each_entry(vh, &vs->handler_list, node) {
-               if (vh->priority > priority) {
-                       list_add_tail_rcu(&new->node, &vh->node);
-                       goto out;
-               }
-       }
-
-       list_add_tail_rcu(&new->node, &vs->handler_list);
-out:
-       mutex_unlock(&vn->sock_lock);
-       return new;
+       vs = vxlan_socket_create(net, port, rcv, data);
+       return vs;
 }
 
-void vxlan_handler_put(struct vxlan_handler *vh)
+void vxlan_sock_release(struct vxlan_sock *vs)
 {
-       BUG_ON(!vh->vs);
+       struct vxlan_net *vn = net_generic(sock_net(vs->sock->sk), vxlan_net_id);
+
+       spin_lock(&vn->sock_lock);
+       hlist_del_rcu(&vs->hlist);
+       spin_unlock(&vn->sock_lock);
 
-       if (atomic_dec_and_test(&vh->refcnt))
-               queue_work(&vh->del_work);
+       queue_work(&vs->del_work);
 }
 
 static int vxlan_init_net(struct net *net)
@@ -434,7 +370,7 @@ static int vxlan_init_net(struct net *net)
        struct vxlan_net *vn = net_generic(net, vxlan_net_id);
        unsigned int h;
 
-       mutex_init(&vn->sock_lock);
+       spin_lock_init(&vn->sock_lock);
 
        for (h = 0; h < PORT_HASH_SIZE; ++h)
                INIT_HLIST_HEAD(&vn->sock_list[h]);
diff --git a/datapath/vlan.c b/datapath/vlan.c
deleted file mode 100644 (file)
index 104ed55..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (c) 2007-2011 Nicira, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/if_vlan.h>
-#include <linux/skbuff.h>
-
-#include "datapath.h"
-#include "vlan.h"
-
-#ifdef NEED_VLAN_FIELD
-void vlan_copy_skb_tci(struct sk_buff *skb)
-{
-       OVS_CB(skb)->vlan_tci = 0;
-}
-
-u16 vlan_get_tci(struct sk_buff *skb)
-{
-       return OVS_CB(skb)->vlan_tci;
-}
-
-void vlan_set_tci(struct sk_buff *skb, u16 vlan_tci)
-{
-       OVS_CB(skb)->vlan_tci = vlan_tci;
-}
-
-bool vlan_tx_tag_present(struct sk_buff *skb)
-{
-       return OVS_CB(skb)->vlan_tci & VLAN_TAG_PRESENT;
-}
-
-u16 vlan_tx_tag_get(struct sk_buff *skb)
-{
-       return OVS_CB(skb)->vlan_tci & ~VLAN_TAG_PRESENT;
-}
-
-struct sk_buff *__vlan_hwaccel_put_tag(struct sk_buff *skb, u16 vlan_tci)
-{
-       OVS_CB(skb)->vlan_tci = vlan_tci | VLAN_TAG_PRESENT;
-       return skb;
-}
-#endif /* NEED_VLAN_FIELD */
index aee5551..13ae6a7 100644 (file)
  * equivalent to those on 2.6.33+.
  */
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
-#define NEED_VLAN_FIELD
-#endif
-
-#ifndef NEED_VLAN_FIELD
-static inline void vlan_copy_skb_tci(struct sk_buff *skb) { }
-
 static inline u16 vlan_get_tci(struct sk_buff *skb)
 {
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
@@ -69,37 +62,4 @@ static inline void vlan_set_tci(struct sk_buff *skb, u16 vlan_tci)
 #endif
        skb->vlan_tci = vlan_tci;
 }
-#else
-void vlan_copy_skb_tci(struct sk_buff *skb);
-u16 vlan_get_tci(struct sk_buff *skb);
-void vlan_set_tci(struct sk_buff *skb, u16 vlan_tci);
-
-#undef vlan_tx_tag_present
-bool vlan_tx_tag_present(struct sk_buff *skb);
-
-#undef vlan_tx_tag_get
-u16 vlan_tx_tag_get(struct sk_buff *skb);
-
-#define __vlan_hwaccel_put_tag rpl__vlan_hwaccel_put_tag
-struct sk_buff *__vlan_hwaccel_put_tag(struct sk_buff *skb, u16 vlan_tci);
-#endif /* NEED_VLAN_FIELD */
-
-static inline int vlan_deaccel_tag(struct sk_buff *skb)
-{
-       if (!vlan_tx_tag_present(skb))
-               return 0;
-
-       skb = __vlan_put_tag(skb, skb->vlan_proto, vlan_tx_tag_get(skb));
-       if (unlikely(!skb))
-               return -ENOMEM;
-
-       if (get_ip_summed(skb) == OVS_CSUM_COMPLETE)
-               skb->csum = csum_add(skb->csum,
-                                    csum_partial(skb->data + (2 * ETH_ALEN),
-                                                 VLAN_HLEN, 0));
-
-       vlan_set_tci(skb, 0);
-       return 0;
-}
-
 #endif /* vlan.h */
index 5af6dbe..a49002f 100644 (file)
@@ -129,8 +129,6 @@ static int __send(struct vport *vport, struct sk_buff *skb,
        __be32 saddr;
        int err;
 
-       forward_ip_summed(skb, true);
-
        /* Route lookup */
        saddr = OVS_CB(skb)->tun_key->ipv4_src;
        rt = find_route(ovs_dp_get_net(vport->dp),
@@ -138,7 +136,7 @@ static int __send(struct vport *vport, struct sk_buff *skb,
                        OVS_CB(skb)->tun_key->ipv4_dst,
                        IPPROTO_GRE,
                        OVS_CB(skb)->tun_key->ipv4_tos,
-                       skb_get_mark(skb));
+                       skb->mark);
        if (IS_ERR(rt)) {
                err = PTR_ERR(rt);
                goto error;
@@ -158,9 +156,14 @@ static int __send(struct vport *vport, struct sk_buff *skb,
                        goto err_free_rt;
        }
 
-       if (unlikely(vlan_deaccel_tag(skb))) {
-               err = -ENOMEM;
-               goto err_free_rt;
+       if (vlan_tx_tag_present(skb)) {
+               if (unlikely(!__vlan_put_tag(skb,
+                                            skb->vlan_proto,
+                                            vlan_tx_tag_get(skb)))) {
+                       err = -ENOMEM;
+                       goto err_free_rt;
+               }
+               vlan_set_tci(skb, 0);
        }
 
        /* Push Tunnel header. */
index db55ee0..8e65f71 100644 (file)
@@ -29,7 +29,6 @@
 #include <net/dst.h>
 #include <net/xfrm.h>
 
-#include "checksum.h"
 #include "datapath.h"
 #include "vlan.h"
 #include "vport-internal_dev.h"
@@ -41,9 +40,6 @@
 
 struct internal_dev {
        struct vport *vport;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
-       struct net_device_stats stats;
-#endif
 };
 
 static struct internal_dev *internal_dev_priv(struct net_device *netdev)
@@ -59,11 +55,7 @@ static struct rtnl_link_stats64 *internal_dev_get_stats(struct net_device *netde
 #else
 static struct net_device_stats *internal_dev_sys_stats(struct net_device *netdev)
 {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
-       struct net_device_stats *stats = &internal_dev_priv(netdev)->stats;
-#else
        struct net_device_stats *stats = &netdev->stats;
-#endif
 #endif
        struct vport *vport = ovs_internal_dev_get_vport(netdev);
        struct ovs_vport_stats vport_stats;
@@ -87,13 +79,6 @@ static struct net_device_stats *internal_dev_sys_stats(struct net_device *netdev
 /* Called with rcu_read_lock_bh. */
 static int internal_dev_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
-       if (unlikely(compute_ip_summed(skb, true))) {
-               kfree_skb(skb);
-               return 0;
-       }
-
-       vlan_copy_skb_tci(skb);
-
        rcu_read_lock();
        ovs_vport_receive(internal_dev_priv(netdev)->vport, skb, NULL);
        rcu_read_unlock();
@@ -187,10 +172,8 @@ static void do_setup(struct net_device *netdev)
        netdev->features = NETIF_F_LLTX | NETIF_F_SG | NETIF_F_FRAGLIST |
                           NETIF_F_HIGHDMA | NETIF_F_HW_CSUM | NETIF_F_TSO;
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
        netdev->vlan_features = netdev->features;
        netdev->features |= NETIF_F_HW_VLAN_CTAG_TX;
-#endif
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39)
        netdev->hw_features = netdev->features & ~NETIF_F_LLTX;
@@ -269,8 +252,19 @@ static int internal_dev_recv(struct vport *vport, struct sk_buff *skb)
        int len;
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
-       if (unlikely(vlan_deaccel_tag(skb)))
-               return 0;
+       if (vlan_tx_tag_present(skb)) {
+               if (unlikely(!__vlan_put_tag(skb,
+                                            skb->vlan_proto,
+                                            vlan_tx_tag_get(skb))))
+                       return 0;
+
+               if (skb->ip_summed == CHECKSUM_COMPLETE)
+                       skb->csum = csum_add(skb->csum,
+                                            csum_partial(skb->data + (2 * ETH_ALEN),
+                                                         VLAN_HLEN, 0));
+
+               vlan_set_tci(skb, 0);
+       }
 #endif
 
        len = skb->len;
@@ -283,14 +277,9 @@ static int internal_dev_recv(struct vport *vport, struct sk_buff *skb)
        skb->pkt_type = PACKET_HOST;
        skb->protocol = eth_type_trans(skb, netdev);
        skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
-       forward_ip_summed(skb, false);
 
        netif_rx(skb);
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
-       netdev->last_rx = jiffies;
-#endif
-
        return len;
 }
 
index 80e980a..259cc2b 100644 (file)
@@ -20,7 +20,6 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/version.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
 
 #include <linux/in.h>
 #include <linux/ip.h>
@@ -239,11 +238,6 @@ static void ovs_tnl_rcv(struct vport *vport, struct sk_buff *skb,
        secpath_reset(skb);
        vlan_set_tci(skb, 0);
 
-       if (unlikely(compute_ip_summed(skb, false))) {
-               kfree_skb(skb);
-               return;
-       }
-
        ovs_vport_receive(vport, skb, tun_key);
 }
 
@@ -442,9 +436,6 @@ static struct sk_buff *handle_offloads(struct sk_buff *skb)
 {
        int err;
 
-       forward_ip_summed(skb, true);
-
-
        if (skb_is_gso(skb)) {
                struct sk_buff *nskb;
                char cb[sizeof(skb->cb)];
@@ -463,7 +454,7 @@ static struct sk_buff *handle_offloads(struct sk_buff *skb)
                        memcpy(nskb->cb, cb, sizeof(cb));
                        nskb = nskb->next;
                }
-       } else if (get_ip_summed(skb) == OVS_CSUM_PARTIAL) {
+       } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
                /* Pages aren't locked and could change at any time.
                 * If this happens after we compute the checksum, the
                 * checksum will be wrong.  We linearize now to avoid
@@ -480,8 +471,7 @@ static struct sk_buff *handle_offloads(struct sk_buff *skb)
                        goto error;
        }
 
-       set_ip_summed(skb, OVS_CSUM_NONE);
-
+       skb->ip_summed = CHECKSUM_NONE;
        return skb;
 
 error:
@@ -508,7 +498,7 @@ static int ovs_tnl_send(struct vport *vport, struct sk_buff *skb,
                        OVS_CB(skb)->tun_key->ipv4_dst,
                        ipproto,
                        OVS_CB(skb)->tun_key->ipv4_tos,
-                       skb_get_mark(skb));
+                       skb->mark);
        if (IS_ERR(rt)) {
                err = PTR_ERR(rt);
                goto error;
@@ -552,8 +542,14 @@ static int ovs_tnl_send(struct vport *vport, struct sk_buff *skb,
 
                skb->next = NULL;
 
-               if (unlikely(vlan_deaccel_tag(skb)))
-                       goto next;
+               if (vlan_tx_tag_present(skb)) {
+                       if (unlikely(!__vlan_put_tag(skb,
+                                                       skb->vlan_proto,
+                                                       vlan_tx_tag_get(skb))))
+                               goto next;
+
+                       vlan_set_tci(skb, 0);
+               }
 
                frag_len = skb->len;
                skb_push(skb, tunnel_hlen);
@@ -646,6 +642,3 @@ const struct vport_ops ovs_lisp_vport_ops = {
        .get_options    = lisp_get_options,
        .send           = lisp_tnl_send,
 };
-#else
-#warning LISP tunneling will not be available on kernels before 2.6.26
-#endif /* Linux kernel < 2.6.26 */
index 50373b1..215a47e 100644 (file)
@@ -29,7 +29,6 @@
 
 #include <net/llc.h>
 
-#include "checksum.h"
 #include "datapath.h"
 #include "vlan.h"
 #include "vport-internal_dev.h"
@@ -80,7 +79,7 @@ static struct sk_buff *netdev_frame_hook(struct sk_buff *skb)
 
        return NULL;
 }
-#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
 /*
  * Used as br_handle_frame_hook.  (Cannot run bridge at the same time, even on
  * different set of devices!)
@@ -92,17 +91,6 @@ static struct sk_buff *netdev_frame_hook(struct net_bridge_port *p,
        netdev_port_receive((struct vport *)p, skb);
        return NULL;
 }
-#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
-/*
- * Used as br_handle_frame_hook.  (Cannot run bridge at the same time, even on
- * different set of devices!)
- */
-/* Called with rcu_read_lock and bottom-halves disabled. */
-static int netdev_frame_hook(struct net_bridge_port *p, struct sk_buff **pskb)
-{
-       netdev_port_receive((struct vport *)p, *pskb);
-       return 1;
-}
 #else
 #error
 #endif
@@ -186,9 +174,6 @@ static struct vport *netdev_create(const struct vport_parms *parms)
                goto error_master_upper_dev_unlink;
 
        dev_set_promiscuity(netdev_vport->dev, 1);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
-       dev_disable_lro(netdev_vport->dev);
-#endif
        netdev_vport->dev->priv_flags |= IFF_OVS_DATAPATH;
        rtnl_unlock();
 
@@ -254,14 +239,9 @@ static void netdev_port_receive(struct vport *vport, struct sk_buff *skb)
        if (unlikely(!skb))
                return;
 
-       if (unlikely(compute_ip_summed(skb, false)))
-               goto error;
-
        skb_push(skb, ETH_HLEN);
        ovs_skb_postpush_rcsum(skb, skb->data, ETH_HLEN);
 
-       vlan_copy_skb_tci(skb);
-
        ovs_vport_receive(vport, skb, NULL);
        return;
 
@@ -306,7 +286,6 @@ static int netdev_send(struct vport *vport, struct sk_buff *skb)
        }
 
        skb->dev = netdev_vport->dev;
-       forward_ip_summed(skb, true);
 
        if (vlan_tx_tag_present(skb) && !dev_supports_vlan_tx(skb->dev)) {
                int features;
index f3ef947..de49ab1 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * Copyright (c) 2011 Nicira, Inc.
- * Copyright (c) 2012 Cisco Systems, Inc.
+ * Copyright (c) 2013 Nicira, Inc.
+ * Copyright (c) 2013 Cisco Systems, Inc.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of version 2 of the GNU General Public
@@ -20,7 +20,6 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/version.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
 
 #include <linux/in.h>
 #include <linux/ip.h>
 #include "datapath.h"
 #include "vport.h"
 
-#define OVS_VXLAN_RCV_PRIORITY         8
-
 /**
  * struct vxlan_port - Keeps track of open UDP ports
- * @vh: vxlan_handler created for the port.
+ * @vs: vxlan_sock created for the port.
  * @name: vport name.
  */
 struct vxlan_port {
-       struct vxlan_handler *vh;
+       struct vxlan_sock *vs;
        char name[IFNAMSIZ];
 };
 
@@ -62,11 +59,11 @@ static inline struct vxlan_port *vxlan_vport(const struct vport *vport)
 }
 
 /* Called with rcu_read_lock and BH disabled. */
-static int vxlan_rcv(struct vxlan_handler *vh, struct sk_buff *skb, __be32 vx_vni)
+static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb, __be32 vx_vni)
 {
-       struct vport *vport = vh->data;
-       struct iphdr *iph;
        struct ovs_key_ipv4_tunnel tun_key;
+       struct vport *vport = vs->data;
+       struct iphdr *iph;
        __be64 key;
 
        /* Save outer tunnel values */
@@ -75,13 +72,12 @@ static int vxlan_rcv(struct vxlan_handler *vh, struct sk_buff *skb, __be32 vx_vn
        ovs_flow_tun_key_init(&tun_key, iph, key, TUNNEL_KEY);
 
        ovs_vport_receive(vport, skb, &tun_key);
-       return PACKET_RCVD;
 }
 
 static int vxlan_get_options(const struct vport *vport, struct sk_buff *skb)
 {
        struct vxlan_port *vxlan_port = vxlan_vport(vport);
-       __be16 dst_port = inet_sport(vxlan_port->vh->vs->sock->sk);
+       __be16 dst_port = inet_sport(vxlan_port->vs->sock->sk);
 
        if (nla_put_u16(skb, OVS_TUNNEL_ATTR_DST_PORT, ntohs(dst_port)))
                return -EMSGSIZE;
@@ -92,7 +88,7 @@ static void vxlan_tnl_destroy(struct vport *vport)
 {
        struct vxlan_port *vxlan_port = vxlan_vport(vport);
 
-       vxlan_handler_put(vxlan_port->vh);
+       vxlan_sock_release(vxlan_port->vs);
 
        ovs_vport_deferred_free(vport);
 }
@@ -102,7 +98,7 @@ static struct vport *vxlan_tnl_create(const struct vport_parms *parms)
        struct net *net = ovs_dp_get_net(parms->dp);
        struct nlattr *options = parms->options;
        struct vxlan_port *vxlan_port;
-       struct vxlan_handler *vh;
+       struct vxlan_sock *vs;
        struct vport *vport;
        struct nlattr *a;
        u16 dst_port;
@@ -129,13 +125,12 @@ static struct vport *vxlan_tnl_create(const struct vport_parms *parms)
        vxlan_port = vxlan_vport(vport);
        strncpy(vxlan_port->name, parms->name, IFNAMSIZ);
 
-       vh = vxlan_handler_add(net, htons(dst_port), vxlan_rcv,
-                              vport, OVS_VXLAN_RCV_PRIORITY, true);
-       if (IS_ERR(vh)) {
+       vs = vxlan_sock_add(net, htons(dst_port), vxlan_rcv, vport, true);
+       if (IS_ERR(vs)) {
                ovs_vport_free(vport);
-               return (void *)vh;
+               return (void *)vs;
        }
-       vxlan_port->vh = vh;
+       vxlan_port->vs = vs;
 
        return vport;
 
@@ -146,7 +141,7 @@ error:
 static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb)
 {
        struct vxlan_port *vxlan_port = vxlan_vport(vport);
-       __be16 dst_port = inet_sport(vxlan_port->vh->vs->sock->sk);
+       __be16 dst_port = inet_sport(vxlan_port->vs->sock->sk);
        struct net *net = ovs_dp_get_net(vport->dp);
        struct rtable *rt;
        __be16 src_port;
@@ -161,8 +156,6 @@ static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb)
                goto error;
        }
 
-       forward_ip_summed(skb, true);
-
        /* Route lookup */
        saddr = OVS_CB(skb)->tun_key->ipv4_src;
        rt = find_route(ovs_dp_get_net(vport->dp),
@@ -170,7 +163,7 @@ static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb)
                        OVS_CB(skb)->tun_key->ipv4_dst,
                        IPPROTO_UDP,
                        OVS_CB(skb)->tun_key->ipv4_tos,
-                       skb_get_mark(skb));
+                       skb->mark);
        if (IS_ERR(rt)) {
                err = PTR_ERR(rt);
                goto error;
@@ -184,7 +177,7 @@ static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb)
        inet_get_local_port_range(&port_min, &port_max);
        src_port = vxlan_src_port(port_min, port_max, skb);
 
-       err = vxlan_xmit_skb(net, vxlan_port->vh, rt, skb,
+       err = vxlan_xmit_skb(net, vxlan_port->vs, rt, skb,
                             saddr, OVS_CB(skb)->tun_key->ipv4_dst,
                             OVS_CB(skb)->tun_key->ipv4_tos,
                             OVS_CB(skb)->tun_key->ipv4_ttl, df,
@@ -210,6 +203,3 @@ const struct vport_ops ovs_vxlan_vport_ops = {
        .get_options    = vxlan_get_options,
        .send           = vxlan_tnl_send,
 };
-#else
-#warning VXLAN tunneling will not be available on kernels before 2.6.26
-#endif /* Linux kernel < 2.6.26 */
index f26beaf..f62201d 100644 (file)
@@ -44,10 +44,8 @@ static const struct vport_ops *vport_ops_list[] = {
        &ovs_gre_vport_ops,
        &ovs_gre64_vport_ops,
 #endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
        &ovs_vxlan_vport_ops,
        &ovs_lisp_vport_ops,
-#endif
 };
 
 /* Protected by RCU read lock for reading, ovs_mutex for writing. */
index 10068fa..cb55e8e 100644 (file)
@@ -1,11 +1,12 @@
-openvswitch (1.12.90-1) unstable; urgency=low
+openvswitch (2.0.90-1) unstable; urgency=low
    [ Open vSwitch team ]
    * New upstream version
     - Nothing yet!  Try NEWS...
 
- -- Open vSwitch team <dev@openvswitch.org>  Tue, 03 Jul 2013 15:05:34 -0700
+ -- Open vSwitch team <dev@openvswitch.org>  Wed, 28 Aug 2013 16:17:38 -0700
 
-openvswitch (1.12.0-1) unstable; urgency=low
+
+openvswitch (2.0.0-1) unstable; urgency=low
    [ Open vSwitch team ]
    * New upstream version
     - OpenFlow:
@@ -14,6 +15,10 @@ openvswitch (1.12.0-1) unstable; urgency=low
       * New support for matching outer source and destination IP address
         of tunneled packets, for tunnel ports configured with the newly
         added "remote_ip=flow" and "local_ip=flow" options.
+      * Support for matching on metadata 'pkt_mark' for interacting with
+        other system components. On Linux this corresponds to the skb
+        mark.
+      * Support matching, rewriting SCTP ports
     - The Interface table in the database has a new "ifindex" column to
       report the interface's OS-assigned ifindex.
     - New "check-oftest" Makefile target for running OFTest against Open
@@ -23,9 +28,13 @@ openvswitch (1.12.0-1) unstable; urgency=low
       through database paths (e.g. Private key option with the database name
       should look like "--private-key=db:Open_vSwitch,SSL,private_key").
     - Added ovs-dev.py, a utility script helpful for Open vSwitch developers.
-    - Support for Linux kernels up to 3.9
+    - Support for Linux kernels up to 3.10
+    - ovs-ofctl:
+      * New "ofp-parse" for printing OpenFlow messages read from a file.
+    - Added configurable flow caching support to IPFIX exporter.
+    - Dropped support for Linux pre-2.6.32.
 
- -- Open vSwitch team <dev@openvswitch.org>  Tue, 03 Jul 2013 15:02:34 -0700
+ -- Open vSwitch team <dev@openvswitch.org>  Wed, 28 Aug 2013 16:11:32 -0700
 
 openvswitch (1.11.0-1) unstable; urgency=low
    [ Open vSwitch team ]
@@ -61,7 +70,7 @@ openvswitch (1.11.0-1) unstable; urgency=low
     - New CFM demand mode which uses data traffic to indicate interface
       liveness.
 
- -- Open vSwitch team <dev@openvswitch.org>  Mon, 29 Apr 2013 14:30:34 -0700
+ -- Open vSwitch team <dev@openvswitch.org>  Wed, 28 Aug 2013 14:31:44 -0700
 
 openvswitch (1.10.0-1) unstable; urgency=low
    [ Open vSwitch team ]
index 3bcf332..c6631d5 100644 (file)
@@ -76,7 +76,6 @@ License:
   GNU General Public License version 2 and the Apache License Version 2.0.
 
        include/linux/openvswitch.h
-       include/openvswitch/datapath-compat.h
 
   On Debian systems, the complete text of the GNU General Public License
   version 2 can be found in `/usr/share/common-licenses/GPL-2'.
index f7c2e78..a2309b1 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2011, 2012 The Board of Trustees of The Leland Stanford
+/* Copyright (c) 2008, 2011, 2012, 2013 The Board of Trustees of The Leland Stanford
  * Junior University
  *
  * We are making the OpenFlow specification and associated documentation
@@ -150,8 +150,8 @@ OFP_ASSERT(sizeof(struct ofp11_port_mod) == 32);
 
 /* Group setup and teardown (controller -> datapath). */
 struct ofp11_group_mod {
-    ovs_be16 command;             /* One of OFPGC_*. */
-    uint8_t type;                 /* One of OFPGT_*. */
+    ovs_be16 command;             /* One of OFPGC11_*. */
+    uint8_t type;                 /* One of OFPGT11_*. */
     uint8_t pad;                  /* Pad to 64 bits. */
     ovs_be32 group_id;            /* Group identifier. */
     /* struct ofp11_bucket buckets[0]; The bucket length is inferred from the
@@ -725,7 +725,7 @@ OFP_ASSERT(sizeof(struct ofp11_bucket_counter) == 16);
 /* Body of reply to OFPST11_GROUP_DESC request. */
 struct ofp11_group_desc_stats {
     ovs_be16 length;            /* Length of this entry. */
-    uint8_t type;               /* One of OFPGT_*. */
+    uint8_t type;               /* One of OFPGT11_*. */
     uint8_t pad;                /* Pad to 64 bits. */
     ovs_be32 group_id;          /* Group identifier. */
     /* struct ofp11_bucket buckets[0]; */
index 2977047..d1e42a4 100644 (file)
@@ -301,7 +301,7 @@ OFP_ASSERT(sizeof(struct ofp12_table_stats) == 128);
 
 /* Body of reply to OFPST12_GROUP_FEATURES request. Group features. */
 struct ofp12_group_features_stats {
-    ovs_be32  types;           /* Bitmap of OFPGT_* values supported. */
+    ovs_be32  types;           /* Bitmap of OFPGT11_* values supported. */
     ovs_be32  capabilities;    /* Bitmap of OFPGFC12_* capability supported. */
     ovs_be32  max_groups[4];   /* Maximum number of groups for each type. */
     ovs_be32  actions[4];      /* Bitmaps of OFPAT_* that are supported. */
index 1071d3d..767e048 100644 (file)
@@ -116,8 +116,7 @@ enum ofp13_table_config {
     OFPTC13_DEPRECATED_MASK = 3  /* Deprecated bits */
 };
 
-/* OpenFlow 1.3 specific flags
- * (struct ofp12_flow_mod, member flags). */
+/* OpenFlow 1.3 specific flags for flow_mod messages. */
 enum ofp13_flow_mod_flags {
     OFPFF13_NO_PKT_COUNTS = 1 << 3, /* Don't keep track of packet count. */
     OFPFF13_NO_BYT_COUNTS = 1 << 4  /* Don't keep track of byte count. */
index a9e5a76..5018f85 100644 (file)
@@ -306,7 +306,7 @@ OFP_ASSERT(sizeof(struct ofp_action_vendor_header) == 8);
  * header and any padding used to make the action 64-bit aligned.
  * NB: The length of an action *must* always be a multiple of eight. */
 struct ofp_action_header {
-    ovs_be16 type;                  /* One of OFPAT10_*. */
+    ovs_be16 type;                  /* One of OFPAT*. */
     ovs_be16 len;                   /* Length of action, including this
                                        header.  This is the length of action,
                                        including any padding to make it
index 88d9529..d651c16 100644 (file)
@@ -1,4 +1,3 @@
 noinst_HEADERS += \
-       include/openvswitch/datapath-compat.h \
        include/openvswitch/types.h
 
diff --git a/include/openvswitch/datapath-compat.h b/include/openvswitch/datapath-compat.h
deleted file mode 100644 (file)
index 338b422..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (c) 2011 Nicira, Inc.
- *
- * This file is offered under your choice of two licenses: Apache 2.0 or GNU
- * GPL 2.0 or later.  The permission statements for each of these licenses is
- * given below.  You may license your modifications to this file under either
- * of these licenses or both.  If you wish to license your modifications under
- * only one of these licenses, delete the permission text for the other
- * license.
- *
- * ----------------------------------------------------------------------
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ----------------------------------------------------------------------
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- * ----------------------------------------------------------------------
- */
-
-#ifndef OPENVSWITCH_DATAPATH_COMPAT_H
-#define OPENVSWITCH_DATAPATH_COMPAT_H 1
-
-#define OVS_VPORT_MCGROUP_FALLBACK_ID 33
-
-#endif /* openvswitch/datapath-compat.h */
index 297894e..4a46c05 100644 (file)
--- a/lib/cfm.c
+++ b/lib/cfm.c
@@ -862,7 +862,7 @@ cfm_get_remote_mpids(const struct cfm *cfm, uint64_t **rmps, size_t *n_rmps)
     OVS_EXCLUDED(mutex)
 {
     ovs_mutex_lock(&mutex);
-    *rmps = xmemdup(cfm->rmps_array, cfm->rmps_array_len);
+    *rmps = xmemdup(cfm->rmps_array, cfm->rmps_array_len * sizeof **rmps);
     *n_rmps = cfm->rmps_array_len;
     ovs_mutex_unlock(&mutex);
 }
index 98f30d7..1c9ebe2 100644 (file)
@@ -289,7 +289,6 @@ fork_and_clean_up(void)
         fatal_signal_fork();
     } else if (!pid) {
         /* Running in child process. */
-        time_postfork();
         lockfile_postfork();
     }
     return pid;
index ca5f496..e2300d6 100644 (file)
@@ -46,7 +46,6 @@
 #include "netlink.h"
 #include "odp-util.h"
 #include "ofpbuf.h"
-#include "openvswitch/datapath-compat.h"
 #include "packets.h"
 #include "poll-loop.h"
 #include "random.h"
@@ -1566,8 +1565,7 @@ dpif_linux_init(void)
         }
         if (!error) {
             error = nl_lookup_genl_mcgroup(OVS_VPORT_FAMILY, OVS_VPORT_MCGROUP,
-                                           &ovs_vport_mcgroup,
-                                           OVS_VPORT_MCGROUP_FALLBACK_ID);
+                                           &ovs_vport_mcgroup);
         }
 
         ovsthread_once_done(&once);
index 8263672..9ab1961 100644 (file)
@@ -1141,10 +1141,10 @@ miniflow_clone(struct miniflow *dst, const struct miniflow *src)
 void
 miniflow_move(struct miniflow *dst, struct miniflow *src)
 {
-    int n = miniflow_n_values(src);
-    if (n <= MINI_N_INLINE) {
+    if (src->values == src->inline_values) {
         dst->values = dst->inline_values;
-        memcpy(dst->values, src->values, n * sizeof *dst->values);
+        memcpy(dst->values, src->values,
+               miniflow_n_values(src) * sizeof *dst->values);
     } else {
         dst->values = src->values;
     }
@@ -1373,7 +1373,7 @@ minimask_clone(struct minimask *dst, const struct minimask *src)
 void
 minimask_move(struct minimask *dst, struct minimask *src)
 {
-    miniflow_clone(&dst->masks, &src->masks);
+    miniflow_move(&dst->masks, &src->masks);
 }
 
 /* Initializes 'dst_' as the bit-wise "and" of 'a_' and 'b_'.
index 336257c..c587930 100644 (file)
@@ -346,6 +346,7 @@ lswitch_process_packet(struct lswitch *sw, const struct ofpbuf *msg)
     case OFPTYPE_PORT_STATUS:
     case OFPTYPE_PACKET_OUT:
     case OFPTYPE_FLOW_MOD:
+    case OFPTYPE_GROUP_MOD:
     case OFPTYPE_PORT_MOD:
     case OFPTYPE_BARRIER_REQUEST:
     case OFPTYPE_BARRIER_REPLY:
index 227546e..e341d45 100644 (file)
@@ -101,6 +101,20 @@ list_moved(struct list *list)
     list->prev->next = list->next->prev = list;
 }
 
+/* Initializes 'dst' with the contents of 'src', compensating for moving it
+ * around in memory.  The effect is that, if 'src' was the head of a list, now
+ * 'dst' is the head of a list containing the same elements. */
+void
+list_move(struct list *dst, struct list *src)
+{
+    if (!list_is_empty(src)) {
+        *dst = *src;
+        list_moved(dst);
+    } else {
+        list_init(dst);
+    }
+}
+
 /* Removes 'elem' from its list and returns the element that followed it.
    Undefined behavior if 'elem' is not in a list. */
 struct list *
index 786b176..0da082e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -40,6 +40,7 @@ void list_push_front(struct list *, struct list *);
 void list_push_back(struct list *, struct list *);
 void list_replace(struct list *, const struct list *);
 void list_moved(struct list *);
+void list_move(struct list *dst, struct list *src);
 
 /* List removal. */
 struct list *list_remove(struct list *);
index 16a6b0b..8f3deb2 100644 (file)
@@ -912,6 +912,9 @@ netdev_dummy_register(bool override)
         sset_init(&types);
         netdev_enumerate_types(&types);
         SSET_FOR_EACH (type, &types) {
+            if (!strcmp(type, "patch")) {
+                continue;
+            }
             if (!netdev_unregister_provider(type)) {
                 struct netdev_class *class;
                 int error;
index 9562d38..23c05c5 100644 (file)
@@ -925,12 +925,10 @@ do_lookup_genl_family(const char *name, struct nlattr **attrs,
 /* Finds the multicast group called 'group_name' in genl family 'family_name'.
  * When successful, writes its result to 'multicast_group' and returns 0.
  * Otherwise, clears 'multicast_group' and returns a positive error code.
- *
- * Some kernels do not support looking up a multicast group with this function.
- * In this case, 'multicast_group' will be populated with 'fallback'. */
+ */
 int
 nl_lookup_genl_mcgroup(const char *family_name, const char *group_name,
-                       unsigned int *multicast_group, unsigned int fallback)
+                       unsigned int *multicast_group)
 {
     struct nlattr *family_attrs[ARRAY_SIZE(family_policy)];
     const struct nlattr *mc;
@@ -945,10 +943,7 @@ nl_lookup_genl_mcgroup(const char *family_name, const char *group_name,
     }
 
     if (!family_attrs[CTRL_ATTR_MCAST_GROUPS]) {
-        *multicast_group = fallback;
-        VLOG_WARN("%s-%s: has no multicast group, using fallback %d",
-                  family_name, group_name, *multicast_group);
-        error = 0;
+        error = EPROTO;
         goto exit;
     }
 
index 986b574..18db417 100644 (file)
@@ -111,7 +111,6 @@ int nl_dump_done(struct nl_dump *);
 /* Miscellaneous */
 int nl_lookup_genl_family(const char *name, int *number);
 int nl_lookup_genl_mcgroup(const char *family_name, const char *group_name,
-                           unsigned int *multicast_group,
-                           unsigned int fallback);
+                           unsigned int *multicast_group);
 
 #endif /* netlink-socket.h */
index 0f03855..c91cc4a 100644 (file)
@@ -182,10 +182,11 @@ odp_execute_actions(void *dp, struct ofpbuf *packet, struct flow *key,
             break;
 
         case OVS_ACTION_ATTR_USERSPACE: {
-            const struct nlattr *userdata;
-
-            userdata = nl_attr_find_nested(a, OVS_USERSPACE_ATTR_USERDATA);
-            userspace(dp, packet, key, userdata);
+            if (userspace) {
+                const struct nlattr *userdata;
+                userdata = nl_attr_find_nested(a, OVS_USERSPACE_ATTR_USERDATA);
+                userspace(dp, packet, key, userdata);
+            }
             break;
         }
 
index 15ad2be..f20bd8a 100644 (file)
@@ -2553,8 +2553,12 @@ odp_flow_key_from_flow__(struct ofpbuf *buf, const struct flow *data,
             icmpv6_key->icmpv6_type = ntohs(data->tp_src);
             icmpv6_key->icmpv6_code = ntohs(data->tp_dst);
 
-            if (icmpv6_key->icmpv6_type == ND_NEIGHBOR_SOLICIT
-                    || icmpv6_key->icmpv6_type == ND_NEIGHBOR_ADVERT) {
+            if (flow->tp_dst == htons(0) &&
+                (flow->tp_src == htons(ND_NEIGHBOR_SOLICIT) ||
+                 flow->tp_src == htons(ND_NEIGHBOR_ADVERT)) &&
+                (!is_mask || (data->tp_src == htons(0xffff) &&
+                              data->tp_dst == htons(0xffff)))) {
+
                 struct ovs_key_nd *nd_key;
 
                 nd_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_ND,
@@ -2965,8 +2969,9 @@ parse_l2_5_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1],
             flow->tp_src = htons(icmpv6_key->icmpv6_type);
             flow->tp_dst = htons(icmpv6_key->icmpv6_code);
             expected_bit = OVS_KEY_ATTR_ICMPV6;
-            if (src_flow->tp_src == htons(ND_NEIGHBOR_SOLICIT) ||
-                src_flow->tp_src == htons(ND_NEIGHBOR_ADVERT)) {
+            if (src_flow->tp_dst == htons(0) &&
+                (src_flow->tp_src == htons(ND_NEIGHBOR_SOLICIT) ||
+                 src_flow->tp_src == htons(ND_NEIGHBOR_ADVERT))) {
                 if (!is_mask) {
                     expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_ND;
                 }
@@ -2981,7 +2986,8 @@ parse_l2_5_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1],
                     if (is_mask) {
                         if (!is_all_zeros((const uint8_t *) nd_key,
                                           sizeof *nd_key) &&
-                            flow->tp_src != htons(0xffff)) {
+                            (flow->tp_src != htons(0xffff) ||
+                             flow->tp_dst != htons(0xffff))) {
                             return ODP_FIT_ERROR;
                         } else {
                             expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_ND;
index 61e2854..77aa69c 100644 (file)
@@ -860,6 +860,12 @@ ofpact_from_openflow11(const union ofp_action *a, struct ofpbuf *out)
         break;
     }
 
+    case OFPUTIL_OFPAT11_GROUP: {
+        struct ofp11_action_group *oag = (struct ofp11_action_group *)a;
+        ofpact_put_GROUP(out)->group_id = ntohl(oag->group_id);
+        break;
+    }
+
 #define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) case OFPUTIL_##ENUM:
 #include "ofp-util.def"
         return ofpact_from_nxast(a, code, out);
@@ -945,6 +951,7 @@ ovs_instruction_type_from_ofpact_type(enum ofpact_type type)
     case OFPACT_GOTO_TABLE:
         return OVSINST_OFPIT11_GOTO_TABLE;
     case OFPACT_OUTPUT:
+    case OFPACT_GROUP:
     case OFPACT_CONTROLLER:
     case OFPACT_ENQUEUE:
     case OFPACT_OUTPUT_REG:
@@ -1302,6 +1309,9 @@ ofpact_check__(const struct ofpact *a, struct flow *flow, ofp_port_t max_ports,
         }
         return 0;
 
+    case OFPACT_GROUP:
+        return 0;
+
     default:
         NOT_REACHED();
     }
@@ -1598,6 +1608,7 @@ ofpact_to_nxast(const struct ofpact *a, struct ofpbuf *out)
         ofpact_sample_to_nxast(ofpact_get_SAMPLE(a), out);
         break;
 
+    case OFPACT_GROUP:
     case OFPACT_OUTPUT:
     case OFPACT_ENQUEUE:
     case OFPACT_SET_VLAN_VID:
@@ -1710,6 +1721,9 @@ ofpact_to_openflow10(const struct ofpact *a, struct ofpbuf *out)
         /* XXX */
         break;
 
+    case OFPACT_GROUP:
+        break;
+
     case OFPACT_CONTROLLER:
     case OFPACT_OUTPUT_REG:
     case OFPACT_BUNDLE:
@@ -1882,6 +1896,11 @@ ofpact_to_openflow11(const struct ofpact *a, struct ofpbuf *out)
     case OFPACT_METER:
         NOT_REACHED();
 
+    case OFPACT_GROUP:
+        ofputil_put_OFPAT11_GROUP(out)->group_id =
+            htonl(ofpact_get_GROUP(a)->group_id);
+        break;
+
     case OFPACT_CONTROLLER:
     case OFPACT_OUTPUT_REG:
     case OFPACT_BUNDLE:
@@ -2051,6 +2070,7 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, ofp_port_t port)
     case OFPACT_CLEAR_ACTIONS:
     case OFPACT_GOTO_TABLE:
     case OFPACT_METER:
+    case OFPACT_GROUP:
     default:
         return false;
     }
@@ -2073,6 +2093,24 @@ ofpacts_output_to_port(const struct ofpact *ofpacts, size_t ofpacts_len,
     return false;
 }
 
+/* Returns true if any action in the 'ofpacts_len' bytes of 'ofpacts' outputs
+ * to 'group', false otherwise. */
+bool
+ofpacts_output_to_group(const struct ofpact *ofpacts, size_t ofpacts_len,
+                        uint32_t group_id)
+{
+    const struct ofpact *a;
+
+    OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
+        if (a->type == OFPACT_GROUP
+            && ofpact_get_GROUP(a)->group_id == group_id) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
 bool
 ofpacts_equal(const struct ofpact *a, size_t a_len,
               const struct ofpact *b, size_t b_len)
@@ -2383,6 +2421,11 @@ ofpact_format(const struct ofpact *a, struct ds *s)
                       ovs_instruction_name_from_type(OVSINST_OFPIT13_METER),
                       ofpact_get_METER(a)->meter_id);
         break;
+
+    case OFPACT_GROUP:
+        ds_put_format(s, "group:%"PRIu32,
+                      ofpact_get_GROUP(a)->group_id);
+        break;
     }
 }
 
index 101c33d..a3fb60f 100644 (file)
@@ -51,6 +51,7 @@
 #define OFPACTS                                                     \
     /* Output. */                                                   \
     DEFINE_OFPACT(OUTPUT,          ofpact_output,        ofpact)    \
+    DEFINE_OFPACT(GROUP,           ofpact_group,         ofpact)    \
     DEFINE_OFPACT(CONTROLLER,      ofpact_controller,    ofpact)    \
     DEFINE_OFPACT(ENQUEUE,         ofpact_enqueue,       ofpact)    \
     DEFINE_OFPACT(OUTPUT_REG,      ofpact_output_reg,    ofpact)    \
@@ -490,6 +491,14 @@ struct ofpact_goto_table {
     uint8_t table_id;
 };
 
+/* OFPACT_GROUP.
+ *
+ * Used for OFPAT11_GROUP. */
+struct ofpact_group {
+    struct ofpact ofpact;
+    uint32_t group_id;
+};
+
 /* Converting OpenFlow to ofpacts. */
 enum ofperr ofpacts_pull_openflow10(struct ofpbuf *openflow,
                                     unsigned int actions_len,
@@ -517,6 +526,8 @@ void ofpacts_put_openflow11_instructions(const struct ofpact[],
 /* Working with ofpacts. */
 bool ofpacts_output_to_port(const struct ofpact[], size_t ofpacts_len,
                             ofp_port_t port);
+bool ofpacts_output_to_group(const struct ofpact[], size_t ofpacts_len,
+                             uint32_t group_id);
 bool ofpacts_equal(const struct ofpact a[], size_t a_len,
                    const struct ofpact b[], size_t b_len);
 
index 3ead49e..47256de 100644 (file)
@@ -177,6 +177,9 @@ enum ofpraw {
     /* NXT 1.0+ (13): struct nx_flow_mod, uint8_t[8][]. */
     OFPRAW_NXT_FLOW_MOD,
 
+    /* OFPT 1.1+ (15): struct ofp11_group_mod, uint8_t[8][]. */
+    OFPRAW_OFPT11_GROUP_MOD,
+
     /* OFPT 1.0 (15): struct ofp10_port_mod. */
     OFPRAW_OFPT10_PORT_MOD,
     /* OFPT 1.1+ (16): struct ofp11_port_mod. */
@@ -295,15 +298,15 @@ enum ofpraw {
     /* OFPST 1.1+ (6): struct ofp11_group_stats_request. */
     OFPRAW_OFPST11_GROUP_REQUEST,
 
-    /* OFPST 1.1-1.2 (6): struct ofp11_group_stats[]. */
+    /* OFPST 1.1-1.2 (6): uint8_t[8][]. */
     OFPRAW_OFPST11_GROUP_REPLY,
-    /* OFPST 1.3 (6): struct ofp13_group_stats[]. */
+    /* OFPST 1.3 (6): uint8_t[8][]. */
     OFPRAW_OFPST13_GROUP_REPLY,
 
     /* OFPST 1.1+ (7): void. */
     OFPRAW_OFPST11_GROUP_DESC_REQUEST,
 
-    /* OFPST 1.1+ (7): struct ofp11_group_desc_stats[]. */
+    /* OFPST 1.1+ (7): uint8_t[8][]. */
     OFPRAW_OFPST11_GROUP_DESC_REPLY,
 
     /* OFPST 1.2+ (8): void. */
@@ -460,6 +463,7 @@ enum ofptype {
     OFPTYPE_FLOW_MOD,            /* OFPRAW_OFPT10_FLOW_MOD.
                                   * OFPRAW_OFPT11_FLOW_MOD.
                                   * OFPRAW_NXT_FLOW_MOD. */
+    OFPTYPE_GROUP_MOD,           /* OFPRAW_OFPT11_GROUP_MOD. */
     OFPTYPE_PORT_MOD,            /* OFPRAW_OFPT10_PORT_MOD.
                                   * OFPRAW_OFPT11_PORT_MOD. */
 
index 176f61f..ad3981c 100644 (file)
@@ -819,6 +819,10 @@ parse_named_action(enum ofputil_action_code code,
         }
         break;
 
+    case OFPUTIL_OFPAT11_GROUP:
+        error = str_to_u32(arg, &ofpact_put_GROUP(ofpacts)->group_id);
+        break;
+
     case OFPUTIL_NXAST_STACK_PUSH:
         error = nxm_parse_stack_action(ofpact_put_STACK_PUSH(ofpacts), arg);
         break;
@@ -1157,6 +1161,7 @@ parse_ofp_str__(struct ofputil_flow_mod *fm, int command, char *string,
     fm->buffer_id = UINT32_MAX;
     fm->out_port = OFPP_ANY;
     fm->flags = 0;
+    fm->out_group = OFPG11_ANY;
     if (fields & F_ACTIONS) {
         act_str = strstr(string, "action");
         if (!act_str) {
@@ -1794,6 +1799,7 @@ parse_ofp_flow_stats_request_str(struct ofputil_flow_stats_request *fsr,
     fsr->cookie_mask = fm.cookie_mask;
     fsr->match = fm.match;
     fsr->out_port = fm.out_port;
+    fsr->out_group = fm.out_group;
     fsr->table_id = fm.table_id;
     return NULL;
 }
@@ -1878,3 +1884,287 @@ exit:
     }
     return error;
 }
+
+static char * WARN_UNUSED_RESULT
+parse_bucket_str(struct ofputil_bucket *bucket, char *str_,
+                  enum ofputil_protocol *usable_protocols)
+{
+    struct ofpbuf ofpacts;
+    char *pos, *act, *arg;
+    int n_actions;
+
+    bucket->weight = 1;
+    bucket->watch_port = OFPP_ANY;
+    bucket->watch_group = OFPG11_ANY;
+
+    pos = str_;
+    n_actions = 0;
+    ofpbuf_init(&ofpacts, 64);
+    while (ofputil_parse_key_value(&pos, &act, &arg)) {
+        char *error = NULL;
+
+        if (!strcasecmp(act, "weight")) {
+            error = str_to_u16(arg, "weight", &bucket->weight);
+        } else if (!strcasecmp(act, "watch_port")) {
+            if (!ofputil_port_from_string(arg, &bucket->watch_port)
+                || (ofp_to_u16(bucket->watch_port) >= ofp_to_u16(OFPP_MAX)
+                    && bucket->watch_port != OFPP_ANY)) {
+                error = xasprintf("%s: invalid watch_port", arg);
+            }
+        } else if (!strcasecmp(act, "watch_group")) {
+            error = str_to_u32(arg, &bucket->watch_group);
+            if (!error && bucket->watch_group > OFPG_MAX) {
+                error = xasprintf("invalid watch_group id %"PRIu32,
+                                  bucket->watch_group);
+            }
+        } else {
+            error = str_to_ofpact__(pos, act, arg, &ofpacts, n_actions,
+                                    usable_protocols);
+            n_actions++;
+        }
+
+        if (error) {
+            ofpbuf_uninit(&ofpacts);
+            return error;
+        }
+    }
+
+    ofpact_pad(&ofpacts);
+    bucket->ofpacts = ofpacts.data;
+    bucket->ofpacts_len = ofpacts.size;
+
+    return NULL;
+}
+
+static char * WARN_UNUSED_RESULT
+parse_ofp_group_mod_str__(struct ofputil_group_mod *gm, uint16_t command,
+                          char *string,
+                          enum ofputil_protocol *usable_protocols)
+{
+    enum {
+        F_GROUP_TYPE  = 1 << 0,
+        F_BUCKETS     = 1 << 1,
+    } fields;
+    char *save_ptr = NULL;
+    bool had_type = false;
+    char *name;
+    struct ofputil_bucket *bucket;
+    char *error = NULL;
+
+    *usable_protocols = OFPUTIL_P_OF11_UP;
+
+    switch (command) {
+    case OFPGC11_ADD:
+        fields = F_GROUP_TYPE | F_BUCKETS;
+        break;
+
+    case OFPGC11_DELETE:
+        fields = 0;
+        break;
+
+    case OFPGC11_MODIFY:
+        fields = F_GROUP_TYPE | F_BUCKETS;
+        break;
+
+    default:
+        NOT_REACHED();
+    }
+
+    memset(gm, 0, sizeof *gm);
+    gm->command = command;
+    gm->group_id = OFPG_ANY;
+    list_init(&gm->buckets);
+    if (command == OFPGC11_DELETE && string[0] == '\0') {
+        gm->group_id = OFPG_ALL;
+        return NULL;
+    }
+
+    *usable_protocols = OFPUTIL_P_OF11_UP;
+
+    if (fields & F_BUCKETS) {
+        char *bkt_str = strstr(string, "bucket");
+
+        if (bkt_str) {
+            *bkt_str = '\0';
+        }
+
+        while (bkt_str) {
+            char *next_bkt_str;
+
+            bkt_str = strchr(bkt_str + 1, '=');
+            if (!bkt_str) {
+                error = xstrdup("must specify bucket content");
+                goto out;
+            }
+            bkt_str++;
+
+            next_bkt_str = strstr(bkt_str, "bucket");
+            if (next_bkt_str) {
+                *next_bkt_str = '\0';
+            }
+
+            bucket = xzalloc(sizeof(struct ofputil_bucket));
+            error = parse_bucket_str(bucket, bkt_str, usable_protocols);
+            if (error) {
+                free(bucket);
+                goto out;
+            }
+            list_push_back(&gm->buckets, &bucket->list_node);
+
+            bkt_str = next_bkt_str;
+        }
+    }
+
+    for (name = strtok_r(string, "=, \t\r\n", &save_ptr); name;
+         name = strtok_r(NULL, "=, \t\r\n", &save_ptr)) {
+        char *value;
+
+        value = strtok_r(NULL, ", \t\r\n", &save_ptr);
+        if (!value) {
+            error = xasprintf("field %s missing value", name);
+            goto out;
+        }
+
+        if (!strcmp(name, "group_id")) {
+            if(!strcmp(value, "all")) {
+                gm->group_id = OFPG_ALL;
+            } else {
+                char *error = str_to_u32(value, &gm->group_id);
+                if (error) {
+                    goto out;
+                }
+                if (gm->group_id != OFPG_ALL && gm->group_id > OFPG_MAX) {
+                    error = xasprintf("invalid group id %"PRIu32,
+                                      gm->group_id);
+                    goto out;
+                }
+            }
+        } else if (!strcmp(name, "type")){
+            if (!(fields & F_GROUP_TYPE)) {
+                error = xstrdup("type is not needed");
+                goto out;
+            }
+            if (!strcmp(value, "all")) {
+                gm->type = OFPGT11_ALL;
+            } else if (!strcmp(value, "select")) {
+                gm->type = OFPGT11_SELECT;
+            } else if (!strcmp(value, "indirect")) {
+                gm->type = OFPGT11_INDIRECT;
+            } else if (!strcmp(value, "ff") ||
+                       !strcmp(value, "fast_failover")) {
+                gm->type = OFPGT11_FF;
+            } else {
+                error = xasprintf("invalid group type %s", value);
+                goto out;
+            }
+            had_type = true;
+        } else if (!strcmp(name, "bucket")) {
+            error = xstrdup("bucket is not needed");
+            goto out;
+        } else {
+            error = xasprintf("unknown keyword %s", name);
+            goto out;
+        }
+    }
+    if (gm->group_id == OFPG_ANY) {
+        error = xstrdup("must specify a group_id");
+        goto out;
+    }
+    if (fields & F_GROUP_TYPE && !had_type) {
+        error = xstrdup("must specify a type");
+        goto out;
+    }
+
+    /* Validate buckets. */
+    LIST_FOR_EACH (bucket, list_node, &gm->buckets) {
+        if (bucket->weight != 1 && gm->type != OFPGT11_SELECT) {
+            error = xstrdup("Only select groups can have bucket weights.");
+            goto out;
+        }
+    }
+    if (gm->type == OFPGT11_INDIRECT && !list_is_short(&gm->buckets)) {
+        error = xstrdup("Indirect groups can have at most one bucket.");
+        goto out;
+    }
+
+    return NULL;
+ out:
+    ofputil_bucket_list_destroy(&gm->buckets);
+    return error;
+}
+
+char * WARN_UNUSED_RESULT
+parse_ofp_group_mod_str(struct ofputil_group_mod *gm, uint16_t command,
+                        const char *str_,
+                        enum ofputil_protocol *usable_protocols)
+{
+    char *string = xstrdup(str_);
+    char *error = parse_ofp_group_mod_str__(gm, command, string,
+                                            usable_protocols);
+    free(string);
+
+    if (error) {
+        ofputil_bucket_list_destroy(&gm->buckets);
+    }
+    return error;
+}
+
+char * WARN_UNUSED_RESULT
+parse_ofp_group_mod_file(const char *file_name, uint16_t command,
+                         struct ofputil_group_mod **gms, size_t *n_gms,
+                         enum ofputil_protocol *usable_protocols)
+{
+    size_t allocated_gms;
+    int line_number;
+    FILE *stream;
+    struct ds s;
+
+    *gms = NULL;
+    *n_gms = 0;
+
+    stream = !strcmp(file_name, "-") ? stdin : fopen(file_name, "r");
+    if (stream == NULL) {
+        return xasprintf("%s: open failed (%s)",
+                         file_name, ovs_strerror(errno));
+    }
+
+    allocated_gms = *n_gms;
+    ds_init(&s);
+    line_number = 0;
+    *usable_protocols = OFPUTIL_P_OF11_UP;
+    while (!ds_get_preprocessed_line(&s, stream, &line_number)) {
+        enum ofputil_protocol usable;
+        char *error;
+
+        if (*n_gms >= allocated_gms) {
+            *gms = x2nrealloc(*gms, &allocated_gms, sizeof **gms);
+        }
+        error = parse_ofp_group_mod_str(&(*gms)[*n_gms], command, ds_cstr(&s),
+                                        &usable);
+        if (error) {
+            size_t i;
+
+            for (i = 0; i < *n_gms; i++) {
+                ofputil_bucket_list_destroy(&(*gms)[i].buckets);
+            }
+            free(*gms);
+            *gms = NULL;
+            *n_gms = 0;
+
+            ds_destroy(&s);
+            if (stream != stdin) {
+                fclose(stream);
+            }
+
+            return xasprintf("%s:%d: %s", file_name, line_number, error);
+        }
+        *usable_protocols &= usable;
+        *n_gms += 1;
+    }
+
+    ds_destroy(&s);
+    if (stream != stdin) {
+        fclose(stream);
+    }
+    return NULL;
+}
index cdb6831..1c3228a 100644 (file)
@@ -29,6 +29,7 @@ struct ofpbuf;
 struct ofputil_flow_mod;
 struct ofputil_flow_monitor_request;
 struct ofputil_flow_stats_request;
+struct ofputil_group_mod;
 struct ofputil_meter_mod;
 enum ofputil_protocol;
 
@@ -66,4 +67,14 @@ char *parse_flow_monitor_request(struct ofputil_flow_monitor_request *,
                                  enum ofputil_protocol *usable_protocols)
     WARN_UNUSED_RESULT;
 
+char *parse_ofp_group_mod_file(const char *file_name, uint16_t command,
+                               struct ofputil_group_mod **gms, size_t *n_gms,
+                               enum ofputil_protocol *usable_protocols)
+    WARN_UNUSED_RESULT;
+
+char *parse_ofp_group_mod_str(struct ofputil_group_mod *, uint16_t command,
+                              const char *string,
+                              enum ofputil_protocol *usable_protocols)
+    WARN_UNUSED_RESULT;
+
 #endif /* ofp-parse.h */
index 560762b..518f9af 100644 (file)
@@ -2140,6 +2140,200 @@ ofp_print_not_implemented(struct ds *string)
     ds_put_cstr(string, "NOT IMPLEMENTED YET!\n");
 }
 
+static void
+ofp_print_group(struct ds *s, uint32_t group_id, uint8_t type,
+                struct list *p_buckets)
+{
+    static const char *type_str[] = { "all", "select", "indirect",
+                                      "ff", "unknown" };
+    struct ofputil_bucket *bucket;
+
+    ds_put_format(s, "group_id=%"PRIu32",type=%s",
+                  group_id, type_str[type > 4 ? 4 : type]);
+    if (!p_buckets) {
+        return;
+    }
+
+    LIST_FOR_EACH (bucket, list_node, p_buckets) {
+        ds_put_cstr(s, ",bucket=");
+
+        if (bucket->weight != 1) {
+            ds_put_format(s, "weight:%"PRIu16",", bucket->weight);
+        }
+        if (bucket->watch_port != OFPP_NONE) {
+            ds_put_format(s, "watch_port:%"PRIu32",", bucket->watch_port);
+        }
+        if (bucket->watch_group != OFPG11_ANY) {
+            ds_put_format(s, "watch_group:%"PRIu32",", bucket->watch_group);
+        }
+
+        ofpacts_format(bucket->ofpacts, bucket->ofpacts_len, s);
+    }
+}
+
+static void
+ofp_print_group_desc(struct ds *s, const struct ofp_header *oh)
+{
+    struct ofpbuf b;
+
+    ofpbuf_use_const(&b, oh, ntohs(oh->length));
+    for (;;) {
+        struct ofputil_group_desc gd;
+        int retval;
+
+        retval = ofputil_decode_group_desc_reply(&gd, &b);
+        if (retval) {
+            if (retval != EOF) {
+                ds_put_cstr(s, " ***parse error***");
+            }
+            break;
+        }
+
+        ds_put_char(s, '\n');
+        ds_put_char(s, ' ');
+        ofp_print_group(s, gd.group_id, gd.type, &gd.buckets);
+     }
+}
+
+static void
+ofp_print_ofpst_group_request(struct ds *string, const struct ofp_header *oh)
+{
+    enum ofperr error;
+    uint32_t group_id;
+
+    error = ofputil_decode_group_stats_request(oh, &group_id);
+    if (error) {
+        ofp_print_error(string, error);
+        return;
+    }
+
+    ds_put_cstr(string, " group_id=");
+    ofputil_format_group(group_id, string);
+}
+
+static void
+ofp_print_group_stats(struct ds *s, const struct ofp_header *oh)
+{
+    struct ofpbuf b;
+    uint32_t bucket_i;
+
+    ofpbuf_use_const(&b, oh, ntohs(oh->length));
+
+    for (;;) {
+        struct ofputil_group_stats gs;
+        int retval;
+
+        retval = ofputil_decode_group_stats_reply(&b, &gs);
+        if (retval) {
+            if (retval != EOF) {
+                ds_put_cstr(s, " ***parse error***");
+            }
+            break;
+        }
+
+        ds_put_char(s, '\n');
+
+        ds_put_char(s, ' ');
+        ds_put_format(s, "group_id=%"PRIu32",", gs.group_id);
+
+        if (gs.duration_sec != UINT32_MAX) {
+            ds_put_cstr(s, "duration=");
+            ofp_print_duration(s, gs.duration_sec, gs.duration_nsec);
+            ds_put_char(s, ',');
+        }
+        ds_put_format(s, "ref_count=%"PRIu32",", gs.ref_count);
+        ds_put_format(s, "packet_count=%"PRIu64",", gs.packet_count);
+        ds_put_format(s, "byte_count=%"PRIu64"", gs.byte_count);
+
+        for (bucket_i = 0; bucket_i < gs.n_buckets; bucket_i++) {
+            if (gs.bucket_stats[bucket_i].packet_count != UINT64_MAX) {
+                ds_put_format(s, ",bucket%"PRIu32":", bucket_i);
+                ds_put_format(s, "packet_count=%"PRIu64",", gs.bucket_stats[bucket_i].packet_count);
+                ds_put_format(s, "byte_count=%"PRIu64"", gs.bucket_stats[bucket_i].byte_count);
+            }
+        }
+
+        free(gs.bucket_stats);
+     }
+}
+
+static void
+ofp_print_group_features(struct ds *string, const struct ofp_header *oh)
+{
+    struct ofputil_group_features features;
+
+    ofputil_decode_group_features_reply(oh, &features);
+
+    ds_put_format(string, "\n Group table:\n");
+    ds_put_format(string, "    Types:  0x%"PRIx32"\n", features.types);
+    ds_put_format(string, "    Capabilities:  0x%"PRIx32"\n",
+                  features.capabilities);
+
+    if (features.types & (1u << OFPGT11_ALL)) {
+        ds_put_format(string, "    All group :\n");
+        ds_put_format(string,
+                      "        max_groups = %#"PRIx32" actions=0x%08"PRIx32"\n",
+                      features.max_groups[0], features.actions[0]);
+    }
+
+    if (features.types & (1u << OFPGT11_SELECT)) {
+        ds_put_format(string, "    Select group :\n");
+        ds_put_format(string, "        max_groups = %#"PRIx32" "
+                      "actions=0x%08"PRIx32"\n",
+                      features.max_groups[1], features.actions[1]);
+    }
+
+    if (features.types & (1u << OFPGT11_INDIRECT)) {
+        ds_put_format(string, "    Indirect group :\n");
+        ds_put_format(string, "        max_groups = %#"PRIx32" "
+                      "actions=0x%08"PRIx32"\n",
+                      features.max_groups[2], features.actions[2]);
+    }
+
+    if (features.types & (1u << OFPGT11_FF)) {
+        ds_put_format(string, "    Fast Failover group :\n");
+        ds_put_format(string, "        max_groups = %#"PRIx32" "
+                      "actions=0x%08"PRIx32"\n",
+                      features.max_groups[3], features.actions[3]);
+    }
+}
+
+static void
+ofp_print_group_mod(struct ds *s, const struct ofp_header *oh)
+{
+    struct ofputil_group_mod gm;
+    int error;
+
+    error = ofputil_decode_group_mod(oh, &gm);
+    if (error) {
+        ofp_print_error(s, error);
+        return;
+    }
+
+    ds_put_char(s, '\n');
+
+    ds_put_char(s, ' ');
+    switch (gm.command) {
+    case OFPGC11_ADD:
+        ds_put_cstr(s, "ADD");
+        break;
+
+    case OFPGC11_MODIFY:
+        ds_put_cstr(s, "MOD");
+        break;
+
+    case OFPGC11_DELETE:
+        ds_put_cstr(s, "DEL");
+        break;
+
+    default:
+        ds_put_format(s, "cmd:%"PRIu16"", gm.command);
+    }
+    ds_put_char(s, ' ');
+
+    ofp_print_group(s, gm.group_id, gm.type, &gm.buckets);
+}
+
 static void
 ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
                 struct ds *string, int verbosity)
@@ -2149,17 +2343,39 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
     ofp_header_to_string__(oh, raw, string);
     switch (ofptype_from_ofpraw(raw)) {
 
-        /* FIXME: Change the following once they are implemented: */
-    case OFPTYPE_QUEUE_GET_CONFIG_REQUEST:
-    case OFPTYPE_QUEUE_GET_CONFIG_REPLY:
-    case OFPTYPE_GET_ASYNC_REQUEST:
-    case OFPTYPE_GET_ASYNC_REPLY:
     case OFPTYPE_GROUP_STATS_REQUEST:
+        ofp_print_stats_request(string, oh);
+        ofp_print_ofpst_group_request(string, oh);
+        break;
+
     case OFPTYPE_GROUP_STATS_REPLY:
+        ofp_print_group_stats(string, oh);
+        break;
+
     case OFPTYPE_GROUP_DESC_STATS_REQUEST:
+        ofp_print_stats_request(string, oh);
+        break;
+
     case OFPTYPE_GROUP_DESC_STATS_REPLY:
+        ofp_print_group_desc(string, oh);
+        break;
+
     case OFPTYPE_GROUP_FEATURES_STATS_REQUEST:
+        ofp_print_stats_request(string, oh);
+        break;
+
     case OFPTYPE_GROUP_FEATURES_STATS_REPLY:
+        ofp_print_group_features(string, oh);
+        break;
+
+    case OFPTYPE_GROUP_MOD:
+        ofp_print_group_mod(string, oh);
+        break;
+
+    case OFPTYPE_QUEUE_GET_CONFIG_REQUEST:
+    case OFPTYPE_QUEUE_GET_CONFIG_REPLY:
+    case OFPTYPE_GET_ASYNC_REQUEST:
+    case OFPTYPE_GET_ASYNC_REPLY:
     case OFPTYPE_TABLE_FEATURES_STATS_REQUEST:
     case OFPTYPE_TABLE_FEATURES_STATS_REPLY:
         ofp_print_not_implemented(string);
index 61fb74f..8ac9186 100644 (file)
@@ -1537,6 +1537,8 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
         if (error) {
             return error;
         }
+        fm->out_group = ntohl(ofm->out_group);
+
         if ((ofm->command == OFPFC_DELETE
              || ofm->command == OFPFC_DELETE_STRICT)
             && ofm->out_group != htonl(OFPG_ANY)) {
@@ -1578,6 +1580,7 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
             fm->hard_timeout = ntohs(ofm->hard_timeout);
             fm->buffer_id = ntohl(ofm->buffer_id);
             fm->out_port = u16_to_ofp(ntohs(ofm->out_port));
+            fm->out_group = OFPG11_ANY;
             raw_flags = ofm->flags;
         } else if (raw == OFPRAW_NXT_FLOW_MOD) {
             /* Nicira extended flow_mod. */
@@ -1608,6 +1611,7 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
             fm->hard_timeout = ntohs(nfm->hard_timeout);
             fm->buffer_id = ntohl(nfm->buffer_id);
             fm->out_port = u16_to_ofp(ntohs(nfm->out_port));
+            fm->out_group = OFPG11_ANY;
             raw_flags = nfm->flags;
         } else {
             NOT_REACHED();
@@ -2058,7 +2062,7 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,
         ofm->priority = htons(fm->priority);
         ofm->buffer_id = htonl(fm->buffer_id);
         ofm->out_port = ofputil_port_to_ofp11(fm->out_port);
-        ofm->out_group = htonl(OFPG11_ANY);
+        ofm->out_group = htonl(fm->out_group);
         ofm->flags = raw_flags;
         ofputil_put_ofp11_match(msg, &fm->match, protocol);
         ofpacts_put_openflow11_instructions(fm->ofpacts, fm->ofpacts_len, msg);
@@ -2124,6 +2128,7 @@ ofputil_decode_ofpst10_flow_request(struct ofputil_flow_stats_request *fsr,
     fsr->aggregate = aggregate;
     ofputil_match_from_ofp10_match(&ofsr->match, &fsr->match);
     fsr->out_port = u16_to_ofp(ntohs(ofsr->out_port));
+    fsr->out_group = OFPG11_ANY;
     fsr->table_id = ofsr->table_id;
     fsr->cookie = fsr->cookie_mask = htonll(0);
 
@@ -2144,9 +2149,7 @@ ofputil_decode_ofpst11_flow_request(struct ofputil_flow_stats_request *fsr,
     if (error) {
         return error;
     }
-    if (ofsr->out_group != htonl(OFPG11_ANY)) {
-        return OFPERR_OFPFMFC_UNKNOWN;
-    }
+    fsr->out_group = ntohl(ofsr->out_group);
     fsr->cookie = ofsr->cookie;
     fsr->cookie_mask = ofsr->cookie_mask;
     error = ofputil_pull_ofp11_match(b, &fsr->match, NULL);
@@ -2176,6 +2179,7 @@ ofputil_decode_nxst_flow_request(struct ofputil_flow_stats_request *fsr,
 
     fsr->aggregate = aggregate;
     fsr->out_port = u16_to_ofp(ntohs(nfsr->out_port));
+    fsr->out_group = OFPG11_ANY;
     fsr->table_id = nfsr->table_id;
 
     return 0;
@@ -2242,7 +2246,7 @@ ofputil_encode_flow_stats_request(const struct ofputil_flow_stats_request *fsr,
         ofsr = ofpbuf_put_zeros(msg, sizeof *ofsr);
         ofsr->table_id = fsr->table_id;
         ofsr->out_port = ofputil_port_to_ofp11(fsr->out_port);
-        ofsr->out_group = htonl(OFPG11_ANY);
+        ofsr->out_group = htonl(fsr->out_group);
         ofsr->cookie = fsr->cookie;
         ofsr->cookie_mask = fsr->cookie_mask;
         ofputil_put_ofp11_match(msg, &fsr->match, protocol);
@@ -2486,7 +2490,7 @@ unknown_to_zero(uint64_t count)
 
 /* Appends an OFPST_FLOW or NXST_FLOW reply that contains the data in 'fs' to
  * those already present in the list of ofpbufs in 'replies'.  'replies' should
- * have been initialized with ofputil_start_stats_reply(). */
+ * have been initialized with ofpmp_init(). */
 void
 ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs,
                                 struct list *replies)
@@ -4576,6 +4580,65 @@ ofputil_port_to_string(ofp_port_t port,
     }
 }
 
+/* Stores the group id represented by 's' into '*group_idp'.  's' may be an
+ * integer or, for reserved group IDs, the standard OpenFlow name for the group
+ * (either "ANY" or "ALL").
+ *
+ * Returns true if successful, false if 's' is not a valid OpenFlow group ID or
+ * name. */
+bool
+ofputil_group_from_string(const char *s, uint32_t *group_idp)
+{
+    if (!strcasecmp(s, "any")) {
+        *group_idp = OFPG11_ANY;
+    } else if (!strcasecmp(s, "all")) {
+        *group_idp = OFPG11_ALL;
+    } else if (!str_to_uint(s, 10, group_idp)) {
+        VLOG_WARN("%s is not a valid group ID.  (Valid group IDs are "
+                  "32-bit nonnegative integers or the keywords ANY or "
+                  "ALL.)", s);
+        return false;
+    }
+
+    return true;
+}
+
+/* Appends to 's' a string representation of the OpenFlow group ID 'group_id'.
+ * Most groups' string representation is just the number, but for special
+ * groups, e.g. OFPG11_ALL, it is the name, e.g. "ALL". */
+void
+ofputil_format_group(uint32_t group_id, struct ds *s)
+{
+    char name[MAX_GROUP_NAME_LEN];
+
+    ofputil_group_to_string(group_id, name, sizeof name);
+    ds_put_cstr(s, name);
+}
+
+
+/* Puts in the 'bufsize' byte in 'namebuf' a null-terminated string
+ * representation of OpenFlow group ID 'group_id'.  Most group are represented
+ * as just their number, but special groups, e.g. OFPG11_ALL, are represented
+ * by name, e.g. "ALL". */
+void
+ofputil_group_to_string(uint32_t group_id,
+                        char namebuf[MAX_GROUP_NAME_LEN + 1], size_t bufsize)
+{
+    switch (group_id) {
+    case OFPG11_ALL:
+        ovs_strlcpy(namebuf, "ALL", bufsize);
+        break;
+
+    case OFPG11_ANY:
+        ovs_strlcpy(namebuf, "ANY", bufsize);
+        break;
+
+    default:
+        snprintf(namebuf, bufsize, "%"PRIu32, group_id);
+        break;
+    }
+}
+
 /* Given a buffer 'b' that contains an array of OpenFlow ports of type
  * 'ofp_version', tries to pull the first element from the array.  If
  * successful, initializes '*pp' with an abstract representation of the
@@ -5193,6 +5256,543 @@ ofputil_decode_port_stats_request(const struct ofp_header *request,
     }
 }
 
+/* Frees all of the "struct ofputil_bucket"s in the 'buckets' list. */
+void
+ofputil_bucket_list_destroy(struct list *buckets)
+{
+    struct ofputil_bucket *bucket, *next_bucket;
+
+    LIST_FOR_EACH_SAFE (bucket, next_bucket, list_node, buckets) {
+        list_remove(&bucket->list_node);
+        free(bucket->ofpacts);
+        free(bucket);
+    }
+}
+
+/* Returns an OpenFlow group stats request for OpenFlow version 'ofp_version',
+ * that requests stats for group 'group_id'.  (Use OFPG_ALL to request stats
+ * for all groups.)
+ *
+ * Group statistics include packet and byte counts for each group. */
+struct ofpbuf *
+ofputil_encode_group_stats_request(enum ofp_version ofp_version,
+                                   uint32_t group_id)
+{
+    struct ofpbuf *request;
+
+    switch (ofp_version) {
+    case OFP10_VERSION:
+        ovs_fatal(0, "dump-group-stats needs OpenFlow 1.1 or later "
+                     "(\'-O OpenFlow11\')");
+    case OFP11_VERSION:
+    case OFP12_VERSION:
+    case OFP13_VERSION: {
+        struct ofp11_group_stats_request *req;
+        request = ofpraw_alloc(OFPRAW_OFPST11_GROUP_REQUEST, ofp_version, 0);
+        req = ofpbuf_put_zeros(request, sizeof *req);
+        req->group_id = htonl(group_id);
+        break;
+    }
+    default:
+        NOT_REACHED();
+    }
+
+    return request;
+}
+
+/* Returns an OpenFlow group description request for OpenFlow version
+ * 'ofp_version', that requests stats for group 'group_id'.  (Use OFPG_ALL to
+ * request stats for all groups.)
+ *
+ * Group descriptions include the bucket and action configuration for each
+ * group. */
+struct ofpbuf *
+ofputil_encode_group_desc_request(enum ofp_version ofp_version)
+{
+    struct ofpbuf *request;
+
+    switch (ofp_version) {
+    case OFP10_VERSION:
+        ovs_fatal(0, "dump-groups needs OpenFlow 1.1 or later "
+                     "(\'-O OpenFlow11\')");
+    case OFP11_VERSION:
+    case OFP12_VERSION:
+    case OFP13_VERSION: {
+        request = ofpraw_alloc(OFPRAW_OFPST11_GROUP_DESC_REQUEST, ofp_version, 0);
+        break;
+    }
+    default:
+        NOT_REACHED();
+    }
+
+    return request;
+}
+
+static void *
+ofputil_group_stats_to_ofp11(const struct ofputil_group_stats *ogs,
+                             size_t base_len, struct list *replies)
+{
+    struct ofp11_bucket_counter *bc11;
+    struct ofp11_group_stats *gs11;
+    size_t length;
+    int i;
+
+    length = base_len + sizeof(struct ofp11_bucket_counter) * ogs->n_buckets;
+
+    gs11 = ofpmp_append(replies, length);
+    memset(gs11, 0, base_len);
+    gs11->length = htons(length);
+    gs11->group_id = htonl(ogs->group_id);
+    gs11->ref_count = htonl(ogs->ref_count);
+    gs11->packet_count = htonll(ogs->packet_count);
+    gs11->byte_count = htonll(ogs->byte_count);
+
+    bc11 = (void *) (((uint8_t *) gs11) + base_len);
+    for (i = 0; i < ogs->n_buckets; i++) {
+        const struct bucket_counter *obc = &ogs->bucket_stats[i];
+
+        bc11[i].packet_count = htonll(obc->packet_count);
+        bc11[i].byte_count = htonll(obc->byte_count);
+    }
+
+    return gs11;
+}
+
+static void
+ofputil_append_of13_group_stats(const struct ofputil_group_stats *ogs,
+                                struct list *replies)
+{
+    struct ofp13_group_stats *gs13;
+
+    gs13 = ofputil_group_stats_to_ofp11(ogs, sizeof *gs13, replies);
+    gs13->duration_sec = htonl(ogs->duration_sec);
+    gs13->duration_nsec = htonl(ogs->duration_nsec);
+}
+
+/* Encodes 'ogs' properly for the format of the list of group statistics
+ * replies already begun in 'replies' and appends it to the list.  'replies'
+ * must have originally been initialized with ofpmp_init(). */
+void
+ofputil_append_group_stats(struct list *replies,
+                           const struct ofputil_group_stats *ogs)
+{
+    struct ofpbuf *msg = ofpbuf_from_list(list_back(replies));
+    struct ofp_header *oh = msg->data;
+
+    switch ((enum ofp_version)oh->version) {
+    case OFP11_VERSION:
+    case OFP12_VERSION:
+        ofputil_group_stats_to_ofp11(ogs, sizeof(struct ofp11_group_stats),
+                                     replies);
+        break;
+
+    case OFP13_VERSION:
+        ofputil_append_of13_group_stats(ogs, replies);
+        break;
+
+    case OFP10_VERSION:
+    default:
+        NOT_REACHED();
+    }
+}
+
+/* Returns an OpenFlow group features request for OpenFlow version
+ * 'ofp_version'. */
+struct ofpbuf *
+ofputil_encode_group_features_request(enum ofp_version ofp_version)
+{
+    struct ofpbuf *request = NULL;
+
+    switch (ofp_version) {
+    case OFP10_VERSION:
+    case OFP11_VERSION:
+        ovs_fatal(0, "dump-group-features needs OpenFlow 1.2 or later "
+                     "(\'-O OpenFlow12\')");
+    case OFP12_VERSION:
+    case OFP13_VERSION: {
+        request = ofpraw_alloc(OFPRAW_OFPST12_GROUP_FEATURES_REQUEST,
+                                        ofp_version, 0);
+        break;
+    }
+    default:
+        NOT_REACHED();
+    }
+
+    return request;
+}
+
+/* Returns a OpenFlow message that encodes 'features' properly as a reply to
+ * group features request 'request'. */
+struct ofpbuf *
+ofputil_encode_group_features_reply(
+    const struct ofputil_group_features *features,
+    const struct ofp_header *request)
+{
+    struct ofp12_group_features_stats *ogf;
+    struct ofpbuf *reply;
+
+    reply = ofpraw_alloc_xid(OFPRAW_OFPST12_GROUP_FEATURES_REPLY,
+                             request->version, request->xid, 0);
+    ogf = ofpbuf_put_zeros(reply, sizeof *ogf);
+    ogf->types = htonl(features->types);
+    ogf->capabilities = htonl(features->capabilities);
+    ogf->max_groups[0] = htonl(features->max_groups[0]);
+    ogf->max_groups[1] = htonl(features->max_groups[1]);
+    ogf->max_groups[2] = htonl(features->max_groups[2]);
+    ogf->max_groups[3] = htonl(features->max_groups[3]);
+    ogf->actions[0] = htonl(features->actions[0]);
+    ogf->actions[1] = htonl(features->actions[1]);
+    ogf->actions[2] = htonl(features->actions[2]);
+    ogf->actions[3] = htonl(features->actions[3]);
+
+    return reply;
+}
+
+/* Decodes group features reply 'oh' into 'features'. */
+void
+ofputil_decode_group_features_reply(const struct ofp_header *oh,
+                                    struct ofputil_group_features *features)
+{
+    const struct ofp12_group_features_stats *ogf = ofpmsg_body(oh);
+
+    features->types = ntohl(ogf->types);
+    features->capabilities = ntohl(ogf->capabilities);
+    features->max_groups[0] = ntohl(ogf->max_groups[0]);
+    features->max_groups[1] = ntohl(ogf->max_groups[1]);
+    features->max_groups[2] = ntohl(ogf->max_groups[2]);
+    features->max_groups[3] = ntohl(ogf->max_groups[3]);
+    features->actions[0] = ntohl(ogf->actions[0]);
+    features->actions[1] = ntohl(ogf->actions[1]);
+    features->actions[2] = ntohl(ogf->actions[2]);
+    features->actions[3] = ntohl(ogf->actions[3]);
+}
+
+/* Parse a group status request message into a 32 bit OpenFlow 1.1
+ * group ID and stores the latter in '*group_id'.
+ * Returns 0 if successful, otherwise an OFPERR_* number. */
+enum ofperr
+ofputil_decode_group_stats_request(const struct ofp_header *request,
+                                   uint32_t *group_id)
+{
+    const struct ofp11_group_stats_request *gsr11 = ofpmsg_body(request);
+    *group_id = ntohl(gsr11->group_id);
+    return 0;
+}
+
+/* Converts a group stats reply in 'msg' into an abstract ofputil_group_stats
+ * in 'gs'.  Assigns freshly allocated memory to gs->bucket_stats for the
+ * caller to eventually free.
+ *
+ * Multiple group stats replies can be packed into a single OpenFlow message.
+ * Calling this function multiple times for a single 'msg' iterates through the
+ * replies.  The caller must initially leave 'msg''s layer pointers null and
+ * not modify them between calls.
+ *
+ * Returns 0 if successful, EOF if no replies were left in this 'msg',
+ * otherwise a positive errno value. */
+int
+ofputil_decode_group_stats_reply(struct ofpbuf *msg,
+                                 struct ofputil_group_stats *gs)
+{
+    struct ofp11_bucket_counter *obc;
+    struct ofp11_group_stats *ogs11;
+    enum ofpraw raw;
+    enum ofperr error;
+    size_t base_len;
+    size_t length;
+    size_t i;
+
+    gs->bucket_stats = NULL;
+    error = (msg->l2
+             ? ofpraw_decode(&raw, msg->l2)
+             : ofpraw_pull(&raw, msg));
+    if (error) {
+        return error;
+    }
+
+    if (!msg->size) {
+        return EOF;
+    }
+
+    if (raw == OFPRAW_OFPST11_GROUP_REPLY) {
+        base_len = sizeof *ogs11;
+        ogs11 = ofpbuf_try_pull(msg, sizeof *ogs11);
+        gs->duration_sec = gs->duration_nsec = UINT32_MAX;
+    } else if (raw == OFPRAW_OFPST13_GROUP_REPLY) {
+        struct ofp13_group_stats *ogs13;
+
+        base_len = sizeof *ogs13;
+        ogs13 = ofpbuf_try_pull(msg, sizeof *ogs13);
+        if (ogs13) {
+            ogs11 = &ogs13->gs;
+            gs->duration_sec = ntohl(ogs13->duration_sec);
+            gs->duration_nsec = ntohl(ogs13->duration_nsec);
+        } else {
+            ogs11 = NULL;
+        }
+    } else {
+        NOT_REACHED();
+    }
+
+    if (!ogs11) {
+        VLOG_WARN_RL(&bad_ofmsg_rl, "%s reply has %zu leftover bytes at end",
+                     ofpraw_get_name(raw), msg->size);
+        return OFPERR_OFPBRC_BAD_LEN;
+    }
+    length = ntohs(ogs11->length);
+    if (length < sizeof base_len) {
+        VLOG_WARN_RL(&bad_ofmsg_rl, "%s reply claims invalid length %zu",
+                     ofpraw_get_name(raw), length);
+        return OFPERR_OFPBRC_BAD_LEN;
+    }
+
+    gs->group_id = ntohl(ogs11->group_id);
+    gs->ref_count = ntohl(ogs11->ref_count);
+    gs->packet_count = ntohll(ogs11->packet_count);
+    gs->byte_count = ntohll(ogs11->byte_count);
+
+    gs->n_buckets = (length - base_len) / sizeof *obc;
+    obc = ofpbuf_try_pull(msg, gs->n_buckets * sizeof *obc);
+    if (!obc) {
+        VLOG_WARN_RL(&bad_ofmsg_rl, "%s reply has %zu leftover bytes at end",
+                     ofpraw_get_name(raw), msg->size);
+        return OFPERR_OFPBRC_BAD_LEN;
+    }
+
+    gs->bucket_stats = xmalloc(gs->n_buckets * sizeof *gs->bucket_stats);
+    for (i = 0; i < gs->n_buckets; i++) {
+        gs->bucket_stats[i].packet_count = ntohll(obc[i].packet_count);
+        gs->bucket_stats[i].byte_count = ntohll(obc[i].byte_count);
+    }
+
+    return 0;
+}
+
+/* Appends a group stats reply that contains the data in 'gds' to those already
+ * present in the list of ofpbufs in 'replies'.  'replies' should have been
+ * initialized with ofpmp_init(). */
+void
+ofputil_append_group_desc_reply(const struct ofputil_group_desc *gds,
+                                struct list *buckets,
+                                struct list *replies)
+{
+    struct ofpbuf *reply = ofpbuf_from_list(list_back(replies));
+    struct ofp11_group_desc_stats *ogds;
+    struct ofputil_bucket *bucket;
+    size_t start_ogds;
+
+    start_ogds = reply->size;
+    ofpbuf_put_zeros(reply, sizeof *ogds);
+    LIST_FOR_EACH (bucket, list_node, buckets) {
+        struct ofp11_bucket *ob;
+        size_t start_ob;
+
+        start_ob = reply->size;
+        ofpbuf_put_zeros(reply, sizeof *ob);
+        ofpacts_put_openflow11_actions(bucket->ofpacts,
+                                       bucket->ofpacts_len, reply);
+
+        ob = ofpbuf_at_assert(reply, start_ob, sizeof *ob);
+        ob->len = htons(reply->size - start_ob);
+        ob->weight = htons(bucket->weight);
+        ob->watch_port = ofputil_port_to_ofp11(bucket->watch_port);
+        ob->watch_group = htonl(bucket->watch_group);
+    }
+    ogds = ofpbuf_at_assert(reply, start_ogds, sizeof *ogds);
+    ogds->length = htons(reply->size - start_ogds);
+    ogds->type = gds->type;
+    ogds->group_id = htonl(gds->group_id);
+
+    ofpmp_postappend(replies, start_ogds);
+}
+
+static enum ofperr
+ofputil_pull_buckets(struct ofpbuf *msg, size_t buckets_length,
+                     struct list *buckets)
+{
+    struct ofp11_bucket *ob;
+
+    list_init(buckets);
+    while (buckets_length > 0) {
+        struct ofputil_bucket *bucket;
+        struct ofpbuf ofpacts;
+        enum ofperr error;
+        size_t ob_len;
+
+        ob = (buckets_length >= sizeof *ob
+              ? ofpbuf_try_pull(msg, sizeof *ob)
+              : NULL);
+        if (!ob) {
+            VLOG_WARN_RL(&bad_ofmsg_rl, "buckets end with %zu leftover bytes",
+                         buckets_length);
+        }
+
+        ob_len = ntohs(ob->len);
+        if (ob_len < sizeof *ob) {
+            VLOG_WARN_RL(&bad_ofmsg_rl, "OpenFlow message bucket length "
+                         "%zu is not valid", ob_len);
+            return OFPERR_OFPGMFC_BAD_BUCKET;
+        } else if (ob_len > buckets_length) {
+            VLOG_WARN_RL(&bad_ofmsg_rl, "OpenFlow message bucket length "
+                         "%zu exceeds remaining buckets data size %zu",
+                         ob_len, buckets_length);
+            return OFPERR_OFPGMFC_BAD_BUCKET;
+        }
+        buckets_length -= ob_len;
+
+        ofpbuf_init(&ofpacts, 0);
+        error = ofpacts_pull_openflow11_actions(msg, ob_len - sizeof *ob,
+                                                &ofpacts);
+        if (error) {
+            ofpbuf_uninit(&ofpacts);
+            ofputil_bucket_list_destroy(buckets);
+            return error;
+        }
+
+        bucket = xzalloc(sizeof *bucket);
+        bucket->weight = ntohs(ob->weight);
+        error = ofputil_port_from_ofp11(ob->watch_port, &bucket->watch_port);
+        if (error) {
+            ofpbuf_uninit(&ofpacts);
+            ofputil_bucket_list_destroy(buckets);
+            return OFPERR_OFPGMFC_BAD_WATCH;
+        }
+        bucket->watch_group = ntohl(ob->watch_group);
+        bucket->ofpacts = ofpbuf_steal_data(&ofpacts);
+        bucket->ofpacts_len = ofpacts.size;
+        list_push_back(buckets, &bucket->list_node);
+    }
+
+    return 0;
+}
+
+/* Converts a group description reply in 'msg' into an abstract
+ * ofputil_group_desc in 'gd'.
+ *
+ * Multiple group description replies can be packed into a single OpenFlow
+ * message.  Calling this function multiple times for a single 'msg' iterates
+ * through the replies.  The caller must initially leave 'msg''s layer pointers
+ * null and not modify them between calls.
+ *
+ * Returns 0 if successful, EOF if no replies were left in this 'msg',
+ * otherwise a positive errno value. */
+int
+ofputil_decode_group_desc_reply(struct ofputil_group_desc *gd,
+                                struct ofpbuf *msg)
+{
+    struct ofp11_group_desc_stats *ogds;
+    size_t length;
+
+    if (!msg->l2) {
+        ofpraw_pull_assert(msg);
+    }
+
+    if (!msg->size) {
+        return EOF;
+    }
+
+    ogds = ofpbuf_try_pull(msg, sizeof *ogds);
+    if (!ogds) {
+        VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST11_GROUP_DESC reply has %zu "
+                     "leftover bytes at end", msg->size);
+        return OFPERR_OFPBRC_BAD_LEN;
+    }
+    gd->type = ogds->type;
+    gd->group_id = ntohl(ogds->group_id);
+
+    length = ntohs(ogds->length);
+    if (length < sizeof *ogds || length - sizeof *ogds > msg->size) {
+        VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST11_GROUP_DESC reply claims invalid "
+                     "length %zu", length);
+        return OFPERR_OFPBRC_BAD_LEN;
+    }
+
+    return ofputil_pull_buckets(msg, length - sizeof *ogds, &gd->buckets);
+}
+
+/* Converts abstract group mod 'gm' into a message for OpenFlow version
+ * 'ofp_version' and returns the message. */
+struct ofpbuf *
+ofputil_encode_group_mod(enum ofp_version ofp_version,
+                         const struct ofputil_group_mod *gm)
+{
+    struct ofpbuf *b;
+    struct ofp11_group_mod *ogm;
+    size_t start_ogm;
+    size_t start_bucket;
+    struct ofputil_bucket *bucket;
+    struct ofp11_bucket *ob;
+
+    switch (ofp_version) {
+    case OFP10_VERSION: {
+        if (gm->command == OFPGC11_ADD) {
+            ovs_fatal(0, "add-group needs OpenFlow 1.1 or later "
+                         "(\'-O OpenFlow11\')");
+        } else if (gm->command == OFPGC11_MODIFY) {
+            ovs_fatal(0, "mod-group needs OpenFlow 1.1 or later "
+                         "(\'-O OpenFlow11\')");
+        } else {
+            ovs_fatal(0, "del-groups needs OpenFlow 1.1 or later "
+                         "(\'-O OpenFlow11\')");
+        }
+    }
+
+    case OFP11_VERSION:
+    case OFP12_VERSION:
+    case OFP13_VERSION: {
+        b = ofpraw_alloc(OFPRAW_OFPT11_GROUP_MOD, ofp_version, 0);
+        start_ogm = b->size;
+        ofpbuf_put_uninit(b, sizeof *ogm);
+
+        LIST_FOR_EACH (bucket, list_node, &gm->buckets) {
+            start_bucket = b->size;
+            ofpbuf_put_uninit(b, sizeof *ob);
+            if (bucket->ofpacts && bucket->ofpacts_len) {
+                ofpacts_put_openflow11_actions(bucket->ofpacts,
+                                bucket->ofpacts_len, b);
+            }
+            ob = ofpbuf_at_assert(b, start_bucket, sizeof *ob);
+            ob->len = htons(b->size - start_bucket);;
+            ob->weight = htons(bucket->weight);
+            ob->watch_port = ofputil_port_to_ofp11(bucket->watch_port);
+            ob->watch_group = htonl(bucket->watch_group);
+        }
+        ogm = ofpbuf_at_assert(b, start_ogm, sizeof *ogm);
+        ogm->command = htons(gm->command);
+        ogm->type = gm->type;
+        ogm->pad = 0;
+        ogm->group_id = htonl(gm->group_id);
+
+        break;
+    }
+
+    default:
+        NOT_REACHED();
+    }
+
+    return b;
+}
+
+/* Converts OpenFlow group mod message 'oh' into an abstract group mod in
+ * 'gm'.  Returns 0 if successful, otherwise an OpenFlow error code. */
+enum ofperr
+ofputil_decode_group_mod(const struct ofp_header *oh,
+                         struct ofputil_group_mod *gm)
+{
+    const struct ofp11_group_mod *ogm;
+    struct ofpbuf msg;
+
+    ofpbuf_use_const(&msg, oh, ntohs(oh->length));
+    ofpraw_pull_assert(&msg);
+
+    ogm = ofpbuf_pull(&msg, sizeof *ogm);
+    gm->command = ntohs(ogm->command);
+    gm->type = ogm->type;
+    gm->group_id = ntohl(ogm->group_id);
+
+    return ofputil_pull_buckets(&msg, msg.size, &gm->buckets);
+}
+
 /* Parse a queue status request message into 'oqsr'.
  * Returns 0 if successful, otherwise an OFPERR_* number. */
 enum ofperr
index d88d420..f5eec73 100644 (file)
@@ -40,6 +40,7 @@ OFPAT11_ACTION(OFPAT11_SET_QUEUE,    ofp11_action_set_queue, 0, "set_queue")
 //OFPAT11_ACTION(OFPAT11_SET_NW_TTL,   ofp11_action_nw_ttl, 0, "set_nw_ttl")
 OFPAT11_ACTION(OFPAT11_DEC_NW_TTL,   ofp_action_header,   0, NULL)
 OFPAT11_ACTION(OFPAT12_SET_FIELD,    ofp12_action_set_field, 1, "set_field")
+OFPAT11_ACTION(OFPAT11_GROUP,        ofp11_action_group,   0, "group")
 
 #ifndef NXAST_ACTION
 #define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME)
index 7e50db2..eae8ed5 100644 (file)
@@ -43,6 +43,14 @@ void ofputil_format_port(ofp_port_t port, struct ds *);
 void ofputil_port_to_string(ofp_port_t, char namebuf[OFP_MAX_PORT_NAME_LEN],
                             size_t bufsize);
 
+/* Group numbers. */
+enum { MAX_GROUP_NAME_LEN = INT_STRLEN(uint32_t) };
+bool ofputil_group_from_string(const char *, uint32_t *group_id);
+void ofputil_format_group(uint32_t group_id, struct ds *);
+void ofputil_group_to_string(uint32_t group_id,
+                             char namebuf[MAX_GROUP_NAME_LEN + 1],
+                             size_t bufsize);
+
 /* Converting OFPFW10_NW_SRC_MASK and OFPFW10_NW_DST_MASK wildcard bit counts
  * to and from IP bitmasks. */
 ovs_be32 ofputil_wcbits_to_netmask(int wcbits);
@@ -268,6 +276,7 @@ struct ofputil_flow_mod {
     uint16_t hard_timeout;
     uint32_t buffer_id;
     ofp_port_t out_port;
+    uint32_t out_group;
     enum ofputil_flow_mod_flags flags;
     struct ofpact *ofpacts;     /* Series of "struct ofpact"s. */
     size_t ofpacts_len;         /* Length of ofpacts, in bytes. */
@@ -287,6 +296,7 @@ struct ofputil_flow_stats_request {
     ovs_be64 cookie;
     ovs_be64 cookie_mask;
     ofp_port_t out_port;
+    uint32_t out_group;
     uint8_t table_id;
 };
 
@@ -867,4 +877,88 @@ int ofputil_decode_queue_stats(struct ofputil_queue_stats *qs, struct ofpbuf *ms
 void ofputil_append_queue_stat(struct list *replies,
                                const struct ofputil_queue_stats *oqs);
 
+/* Bucket for use in groups. */
+struct ofputil_bucket {
+    struct list list_node;
+    uint16_t weight;            /* Relative weight, for "select" groups. */
+    ofp_port_t watch_port;      /* Port whose state affects whether this bucket
+                                 * is live. Only required for fast failover
+                                 * groups. */
+    uint32_t watch_group;       /* Group whose state affects whether this
+                                 * bucket is live. Only required for fast
+                                 * failover groups. */
+    struct ofpact *ofpacts;     /* Series of "struct ofpact"s. */
+    size_t ofpacts_len;         /* Length of ofpacts, in bytes. */
+};
+
+/* Protocol-independent group_mod. */
+struct ofputil_group_mod {
+    uint16_t command;             /* One of OFPGC11_*. */
+    uint8_t type;                 /* One of OFPGT11_*. */
+    uint32_t group_id;            /* Group identifier. */
+    struct list buckets;          /* Contains "struct ofputil_bucket"s. */
+};
+
+struct bucket_counter {
+    uint64_t packet_count;   /* Number of packets processed by bucket. */
+    uint64_t byte_count;     /* Number of bytes processed by bucket. */
+};
+
+/* Group stats reply, independent of protocol. */
+struct ofputil_group_stats {
+    uint32_t group_id;    /* Group identifier. */
+    uint32_t ref_count;
+    uint64_t packet_count;      /* Packet count, UINT64_MAX if unknown. */
+    uint64_t byte_count;        /* Byte count, UINT64_MAX if unknown. */
+    uint32_t duration_sec;      /* UINT32_MAX if unknown. */
+    uint32_t duration_nsec;
+    uint32_t n_buckets;
+    struct bucket_counter *bucket_stats;
+};
+
+/* Group features reply, independent of protocol. */
+struct ofputil_group_features {
+    uint32_t  types;           /* Bitmap of OFPGT_* values supported. */
+    uint32_t  capabilities;    /* Bitmap of OFPGFC12_* capability supported. */
+    uint32_t  max_groups[4];   /* Maximum number of groups for each type. */
+    uint32_t  actions[4];      /* Bitmaps of OFPAT_* that are supported. */
+};
+
+/* Group desc reply, independent of protocol. */
+struct ofputil_group_desc {
+    uint8_t type;               /* One of OFPGT_*. */
+    uint32_t group_id;          /* Group identifier. */
+    struct list buckets;        /* Contains "struct ofputil_bucket"s. */
+};
+
+void ofputil_bucket_list_destroy(struct list *buckets);
+
+struct ofpbuf *ofputil_encode_group_stats_request(enum ofp_version,
+                                                  uint32_t group_id);
+enum ofperr ofputil_decode_group_stats_request(
+    const struct ofp_header *request, uint32_t *group_id);
+void ofputil_append_group_stats(struct list *replies,
+                                const struct ofputil_group_stats *);
+struct ofpbuf *ofputil_encode_group_features_request(enum ofp_version);
+struct ofpbuf *ofputil_encode_group_features_reply(
+    const struct ofputil_group_features *, const struct ofp_header *request);
+void ofputil_decode_group_features_reply(const struct ofp_header *,
+                                         struct ofputil_group_features *);
+struct ofpbuf *ofputil_encode_group_mod(enum ofp_version ofp_version,
+                                        const struct ofputil_group_mod *gm);
+
+enum ofperr ofputil_decode_group_mod(const struct ofp_header *,
+                                     struct ofputil_group_mod *);
+
+int ofputil_decode_group_stats_reply(struct ofpbuf *,
+                                     struct ofputil_group_stats *);
+
+int ofputil_decode_group_desc_reply(struct ofputil_group_desc *,
+                                    struct ofpbuf *);
+
+void ofputil_append_group_desc_reply(const struct ofputil_group_desc *,
+                                     struct list *buckets,
+                                     struct list *replies);
+struct ofpbuf *ofputil_encode_group_desc_request(enum ofp_version);
+
 #endif /* ofp-util.h */
index 39a12c9..17cbd82 100644 (file)
@@ -1154,6 +1154,7 @@ is_admitted_msg(const struct ofpbuf *b)
     case OFPTYPE_PORT_STATUS:
     case OFPTYPE_PACKET_OUT:
     case OFPTYPE_FLOW_MOD:
+    case OFPTYPE_GROUP_MOD:
     case OFPTYPE_PORT_MOD:
     case OFPTYPE_METER_MOD:
     case OFPTYPE_BARRIER_REQUEST:
index faf8e7b..37b4353 100644 (file)
@@ -41,14 +41,12 @@ VLOG_DEFINE_THIS_MODULE(timeval);
 
 struct clock {
     clockid_t id;               /* CLOCK_MONOTONIC or CLOCK_REALTIME. */
-    struct ovs_rwlock rwlock;   /* Mutual exclusion for 'cache'. */
 
     /* Features for use by unit tests.  Protected by 'rwlock'. */
+    struct ovs_rwlock rwlock;
     struct timespec warp;       /* Offset added for unit tests. */
     bool stopped;               /* Disables real-time updates if true.  */
 
-    /* Relevant only if CACHE_TIME is true. */
-    volatile sig_atomic_t tick; /* Has the timer ticked?  Set by signal. */
     struct timespec cache;      /* Last time read from kernel. */
 };
 
@@ -67,11 +65,6 @@ static long long int deadline = LLONG_MAX;
  * up. */
 DEFINE_STATIC_PER_THREAD_DATA(long long int, last_wakeup, 0);
 
-static void set_up_timer(void);
-static void set_up_signal(int flags);
-static void sigalrm_handler(int);
-static void block_sigalrm(sigset_t *);
-static void unblock_sigalrm(const sigset_t *);
 static void log_poll_interval(long long int last_wakeup);
 static struct rusage *get_recent_rusage(void);
 static void refresh_rusage(void);
@@ -83,7 +76,6 @@ init_clock(struct clock *c, clockid_t id)
 {
     memset(c, 0, sizeof *c);
     c->id = id;
-    ovs_rwlock_init(&c->rwlock);
     xclock_gettime(c->id, &c->cache);
 }
 
@@ -99,9 +91,6 @@ do_init_time(void)
                                   : CLOCK_REALTIME));
     init_clock(&wall_clock, CLOCK_REALTIME);
     boot_time = timespec_to_msec(&monotonic_clock.cache);
-
-    set_up_signal(SA_RESTART);
-    set_up_timer();
 }
 
 /* Initializes the timetracking module, if not already initialized. */
@@ -112,86 +101,16 @@ time_init(void)
     pthread_once(&once, do_init_time);
 }
 
-static void
-set_up_signal(int flags)
-{
-    struct sigaction sa;
-
-    memset(&sa, 0, sizeof sa);
-    sa.sa_handler = sigalrm_handler;
-    sigemptyset(&sa.sa_mask);
-    sa.sa_flags = flags;
-    xsigaction(SIGALRM, &sa, NULL);
-}
-
-static void
-set_up_timer(void)
-{
-    static timer_t timer_id;    /* "static" to avoid apparent memory leak. */
-    struct itimerspec itimer;
-
-    if (!CACHE_TIME) {
-        return;
-    }
-
-    if (timer_create(monotonic_clock.id, NULL, &timer_id)) {
-        VLOG_FATAL("timer_create failed (%s)", ovs_strerror(errno));
-    }
-
-    itimer.it_interval.tv_sec = 0;
-    itimer.it_interval.tv_nsec = TIME_UPDATE_INTERVAL * 1000 * 1000;
-    itimer.it_value = itimer.it_interval;
-
-    if (timer_settime(timer_id, 0, &itimer, NULL)) {
-        VLOG_FATAL("timer_settime failed (%s)", ovs_strerror(errno));
-    }
-}
-
-/* Set up the interval timer, to ensure that time advances even without calling
- * time_refresh().
- *
- * A child created with fork() does not inherit the parent's interval timer, so
- * this function needs to be called from the child after fork(). */
-void
-time_postfork(void)
-{
-    assert_single_threaded();
-    time_init();
-    set_up_timer();
-}
-
-/* Forces a refresh of the current time from the kernel.  It is not usually
- * necessary to call this function, since the time will be refreshed
- * automatically at least every TIME_UPDATE_INTERVAL milliseconds.  If
- * CACHE_TIME is false, we will always refresh the current time so this
- * function has no effect. */
-void
-time_refresh(void)
-{
-    monotonic_clock.tick = wall_clock.tick = true;
-}
-
 static void
 time_timespec__(struct clock *c, struct timespec *ts)
 {
     time_init();
-    for (;;) {
-        /* Use the cached time by preference, but fall through if there's been
-         * a clock tick.  */
-        ovs_rwlock_rdlock(&c->rwlock);
-        if (c->stopped || !c->tick) {
-            timespec_add(ts, &c->cache, &c->warp);
-            ovs_rwlock_unlock(&c->rwlock);
-            return;
-        }
-        ovs_rwlock_unlock(&c->rwlock);
 
-        /* Refresh the cache. */
-        ovs_rwlock_wrlock(&c->rwlock);
-        if (c->tick) {
-            c->tick = false;
-            xclock_gettime(c->id, &c->cache);
-        }
+    if (!c->stopped) {
+        xclock_gettime(c->id, ts);
+    } else {
+        ovs_rwlock_rdlock(&c->rwlock);
+        timespec_add(ts, &c->cache, &c->warp);
         ovs_rwlock_unlock(&c->rwlock);
     }
 }
@@ -268,7 +187,6 @@ time_alarm(unsigned int secs)
 
     assert_single_threaded();
     time_init();
-    time_refresh();
 
     now = time_msec();
     msecs = secs * 1000LL;
@@ -286,8 +204,6 @@ time_alarm(unsigned int secs)
  *        timeout is reached.  (Because of this property, this function will
  *        never return -EINTR.)
  *
- *      - As a side effect, refreshes the current time (like time_refresh()).
- *
  * Stores the number of milliseconds elapsed during poll in '*elapsed'. */
 int
 time_poll(struct pollfd *pollfds, int n_pollfds, long long int timeout_when,
@@ -295,18 +211,14 @@ time_poll(struct pollfd *pollfds, int n_pollfds, long long int timeout_when,
 {
     long long int *last_wakeup = last_wakeup_get();
     long long int start;
-    sigset_t oldsigs;
-    bool blocked;
     int retval;
 
     time_init();
-    time_refresh();
     if (*last_wakeup) {
         log_poll_interval(*last_wakeup);
     }
     coverage_clear();
     start = time_msec();
-    blocked = false;
 
     timeout_when = MIN(timeout_when, deadline);
 
@@ -327,7 +239,6 @@ time_poll(struct pollfd *pollfds, int n_pollfds, long long int timeout_when,
             retval = -errno;
         }
 
-        time_refresh();
         if (deadline <= time_msec()) {
             fatal_signal_handler(SIGALRM);
             if (retval < 0) {
@@ -339,14 +250,6 @@ time_poll(struct pollfd *pollfds, int n_pollfds, long long int timeout_when,
         if (retval != -EINTR) {
             break;
         }
-
-        if (!blocked && CACHE_TIME) {
-            block_sigalrm(&oldsigs);
-            blocked = true;
-        }
-    }
-    if (blocked) {
-        unblock_sigalrm(&oldsigs);
     }
     *last_wakeup = time_msec();
     refresh_rusage();
@@ -354,27 +257,6 @@ time_poll(struct pollfd *pollfds, int n_pollfds, long long int timeout_when,
     return retval;
 }
 
-static void
-sigalrm_handler(int sig_nr OVS_UNUSED)
-{
-    monotonic_clock.tick = wall_clock.tick = true;
-}
-
-static void
-block_sigalrm(sigset_t *oldsigs)
-{
-    sigset_t sigalrm;
-    sigemptyset(&sigalrm);
-    sigaddset(&sigalrm, SIGALRM);
-    xpthread_sigmask(SIG_BLOCK, &sigalrm, oldsigs);
-}
-
-static void
-unblock_sigalrm(const sigset_t *oldsigs)
-{
-    xpthread_sigmask(SIG_SETMASK, oldsigs, NULL);
-}
-
 long long int
 timespec_to_msec(const struct timespec *ts)
 {
@@ -570,6 +452,7 @@ timeval_stop_cb(struct unixctl_conn *conn,
 {
     ovs_rwlock_wrlock(&monotonic_clock.rwlock);
     monotonic_clock.stopped = true;
+    xclock_gettime(monotonic_clock.id, &monotonic_clock.cache);
     ovs_rwlock_unlock(&monotonic_clock.rwlock);
 
     unixctl_command_reply(conn, NULL);
index 8dd2e2b..d0962ee 100644 (file)
@@ -40,25 +40,6 @@ BUILD_ASSERT_DECL(TYPE_IS_SIGNED(time_t));
 #define TIME_MAX TYPE_MAXIMUM(time_t)
 #define TIME_MIN TYPE_MINIMUM(time_t)
 
-/* Interval between updates to the reported time, in ms.  This should not be
- * adjusted much below 10 ms or so with the current implementation, or too
- * much time will be wasted in signal handlers and calls to clock_gettime(). */
-#define TIME_UPDATE_INTERVAL 25
-
-/* True on systems that support a monotonic clock.  Compared to just getting
- * the value of a variable, clock_gettime() is somewhat expensive, even on
- * systems that try hard to optimize it (such as x86-64 Linux), so it's
- * worthwhile to minimize calls via caching. */
-#ifndef CACHE_TIME
-#if defined ESX
-#define CACHE_TIME 0
-#else
-#define CACHE_TIME 1
-#endif
-#endif /* ifndef CACHE_TIME */
-
-void time_postfork(void);
-void time_refresh(void);
 time_t time_now(void);
 time_t time_wall(void);
 long long int time_msec(void);
index 76c33cd..3cada4a 100644 (file)
@@ -30,6 +30,9 @@
 #include "coverage.h"
 #include "ovs-thread.h"
 #include "vlog.h"
+#ifdef HAVE_PTHREAD_SET_NAME_NP
+#include <pthread_np.h>
+#endif
 
 VLOG_DEFINE_THIS_MODULE(util);
 
index bcdb942..dca6cca 100644 (file)
@@ -46,22 +46,6 @@ AC_DEFUN([OVS_CHECK_NDEBUG],
      [ndebug=false])
    AM_CONDITIONAL([NDEBUG], [test x$ndebug = xtrue])])
 
-dnl Checks for --enable-cache-time and defines CACHE_TIME if it is specified.
-AC_DEFUN([OVS_CHECK_CACHE_TIME],
-  [AC_ARG_ENABLE(
-     [cache-time],
-     [AC_HELP_STRING([--enable-cache-time],
-                     [Override time caching default (for testing only)])],
-     [case "${enableval}" in
-        (yes) cache_time=1;;
-        (no)  cache_time=0;;
-        (*) AC_MSG_ERROR([bad value ${enableval} for --enable-cache-time]) ;;
-      esac
-      AC_DEFINE_UNQUOTED([CACHE_TIME], [$cache_time],
-          [Define to 1 to enable time caching, to 0 to disable time caching, or
-           leave undefined to use the default (as one should
-           ordinarily do).])])])
-
 dnl Checks for ESX.
 AC_DEFUN([OVS_CHECK_ESX],
   [AC_CHECK_HEADER([vmware.h],
index 9734718..0819b72 100644 (file)
@@ -125,6 +125,7 @@ mbridge_unref(struct mbridge *mbridge)
         mbridge_unregister_bundle(mbridge, mbundle->ofbundle);
     }
 
+    hmap_destroy(&mbridge->mbundles);
     free(mbridge);
 }
 
index db78af3..54f441b 100644 (file)
@@ -55,6 +55,8 @@ struct handler {
     struct list upcalls OVS_GUARDED;
     size_t n_upcalls OVS_GUARDED;
 
+    size_t n_new_upcalls;              /* Only changed by the dispatcher. */
+
     pthread_cond_t wake_cond;          /* Wakes 'thread' while holding
                                           'mutex'. */
 };
@@ -345,6 +347,37 @@ flow_miss_batch_destroy(struct flow_miss_batch *fmb)
     free(fmb);
 }
 
+/* Discards any flow miss batches queued up in 'udpif' for 'ofproto' (because
+ * 'ofproto' is being destroyed).
+ *
+ * 'ofproto''s xports must already have been removed, otherwise new flow miss
+ * batches could still end up getting queued. */
+void
+flow_miss_batch_ofproto_destroyed(struct udpif *udpif,
+                                  const struct ofproto_dpif *ofproto)
+{
+    struct flow_miss_batch *fmb, *next_fmb;
+
+    ovs_mutex_lock(&udpif->fmb_mutex);
+    LIST_FOR_EACH_SAFE (fmb, next_fmb, list_node, &udpif->fmbs) {
+        struct flow_miss *miss, *next_miss;
+
+        HMAP_FOR_EACH_SAFE (miss, next_miss, hmap_node, &fmb->misses) {
+            if (miss->ofproto == ofproto) {
+                hmap_remove(&fmb->misses, &miss->hmap_node);
+                miss_destroy(miss);
+            }
+        }
+
+        if (hmap_is_empty(&fmb->misses)) {
+            list_remove(&fmb->list_node);
+            flow_miss_batch_destroy(fmb);
+            udpif->n_fmbs--;
+        }
+    }
+    ovs_mutex_unlock(&udpif->fmb_mutex);
+}
+
 /* Retreives the next drop key which ofproto-dpif needs to process.  The caller
  * is responsible for destroying it with drop_key_destroy(). */
 struct drop_key *
@@ -515,6 +548,10 @@ static void
 recv_upcalls(struct udpif *udpif)
 {
     static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60);
+    size_t n_udpif_new_upcalls = 0;
+    struct handler *handler;
+    int n;
+
     for (;;) {
         struct upcall *upcall;
         int error;
@@ -535,7 +572,6 @@ recv_upcalls(struct udpif *udpif)
         } else if (upcall->type == MISS_UPCALL) {
             struct dpif_upcall *dupcall = &upcall->dpif_upcall;
             uint32_t hash = udpif->secret;
-            struct handler *handler;
             struct nlattr *nla;
             size_t n_bytes, left;
 
@@ -561,8 +597,11 @@ recv_upcalls(struct udpif *udpif)
             ovs_mutex_lock(&handler->mutex);
             if (handler->n_upcalls < MAX_QUEUE_LENGTH) {
                 list_push_back(&handler->upcalls, &upcall->list_node);
-                handler->n_upcalls++;
-                xpthread_cond_signal(&handler->wake_cond);
+                handler->n_new_upcalls = ++handler->n_upcalls;
+
+                if (handler->n_new_upcalls >= FLOW_MISS_MAX_BATCH) {
+                    xpthread_cond_signal(&handler->wake_cond);
+                }
                 ovs_mutex_unlock(&handler->mutex);
                 if (!VLOG_DROP_DBG(&rl)) {
                     struct ds ds = DS_EMPTY_INITIALIZER;
@@ -581,10 +620,13 @@ recv_upcalls(struct udpif *udpif)
         } else {
             ovs_mutex_lock(&udpif->upcall_mutex);
             if (udpif->n_upcalls < MAX_QUEUE_LENGTH) {
-                udpif->n_upcalls++;
+                n_udpif_new_upcalls = ++udpif->n_upcalls;
                 list_push_back(&udpif->upcalls, &upcall->list_node);
                 ovs_mutex_unlock(&udpif->upcall_mutex);
-                seq_change(udpif->wait_seq);
+
+                if (n_udpif_new_upcalls >= FLOW_MISS_MAX_BATCH) {
+                    seq_change(udpif->wait_seq);
+                }
             } else {
                 ovs_mutex_unlock(&udpif->upcall_mutex);
                 COVERAGE_INC(upcall_queue_overflow);
@@ -592,6 +634,18 @@ recv_upcalls(struct udpif *udpif)
             }
         }
     }
+    for (n = 0; n < udpif->n_handlers; ++n) {
+        handler = &udpif->handlers[n];
+        if (handler->n_new_upcalls) {
+            handler->n_new_upcalls = 0;
+            ovs_mutex_lock(&handler->mutex);
+            xpthread_cond_signal(&handler->wake_cond);
+            ovs_mutex_unlock(&handler->mutex);
+        }
+    }
+    if (n_udpif_new_upcalls) {
+        seq_change(udpif->wait_seq);
+    }
 }
 
 static struct flow_miss *
@@ -630,7 +684,7 @@ execute_flow_miss(struct flow_miss *miss, struct dpif_op *ops, size_t *n_ops)
 
     flow_wildcards_init_catchall(&wc);
     rule_dpif_lookup(ofproto, &miss->flow, &wc, &rule);
-    rule_credit_stats(rule, &miss->stats);
+    rule_dpif_credit_stats(rule, &miss->stats);
     xlate_in_init(&xin, ofproto, &miss->flow, rule, miss->stats.tcp_flags,
                   NULL);
     xin.may_learn = true;
@@ -638,7 +692,7 @@ execute_flow_miss(struct flow_miss *miss, struct dpif_op *ops, size_t *n_ops)
     xlate_actions(&xin, &miss->xout);
     flow_wildcards_or(&miss->xout.wc, &miss->xout.wc, &wc);
 
-    if (rule->up.cr.priority == FAIL_OPEN_PRIORITY) {
+    if (rule_dpif_fail_open(rule)) {
         LIST_FOR_EACH (packet, list_node, &miss->packets) {
             struct ofputil_packet_in *pin;
 
@@ -671,7 +725,7 @@ execute_flow_miss(struct flow_miss *miss, struct dpif_op *ops, size_t *n_ops)
             xlate_actions_for_side_effects(&xin);
         }
     }
-    rule_release(rule);
+    rule_dpif_release(rule);
 
     if (miss->xout.odp_actions.size) {
         LIST_FOR_EACH (packet, list_node, &miss->packets) {
index f597672..8e8264e 100644 (file)
@@ -109,6 +109,9 @@ struct flow_miss_batch {
 
 struct flow_miss_batch *flow_miss_batch_next(struct udpif *);
 void flow_miss_batch_destroy(struct flow_miss_batch *);
+
+void flow_miss_batch_ofproto_destroyed(struct udpif *,
+                                       const struct ofproto_dpif *);
 \f
 /* Drop keys are odp flow keys which have drop flows installed in the kernel.
  * These are datapath flows which have no associated ofproto, if they did we
index eeccbc5..e7cec14 100644 (file)
@@ -121,7 +121,7 @@ struct xport {
     struct xport *peer;              /* Patch port peer or null. */
 
     enum ofputil_port_config config; /* OpenFlow port configuration. */
-    int stp_port_no;                 /* STP port number or 0 if not in use. */
+    int stp_port_no;                 /* STP port number or -1 if not in use. */
 
     struct hmap skb_priorities;      /* Map of 'skb_priority_to_dscp's. */
 
@@ -621,7 +621,7 @@ xport_lookup(const struct ofport_dpif *ofport)
 static struct stp_port *
 xport_get_stp_port(const struct xport *xport)
 {
-    return xport->xbridge->stp && xport->stp_port_no
+    return xport->xbridge->stp && xport->stp_port_no != -1
         ? stp_get_port(xport->xbridge->stp, xport->stp_port_no)
         : NULL;
 }
@@ -1224,6 +1224,7 @@ xlate_normal(struct xlate_ctx *ctx)
     struct xbundle *in_xbundle;
     struct xport *in_port;
     struct mac_entry *mac;
+    void *mac_port;
     uint16_t vlan;
     uint16_t vid;
 
@@ -1286,8 +1287,11 @@ xlate_normal(struct xlate_ctx *ctx)
     /* Determine output bundle. */
     ovs_rwlock_rdlock(&ctx->xbridge->ml->rwlock);
     mac = mac_learning_lookup(ctx->xbridge->ml, flow->dl_dst, vlan);
-    if (mac) {
-        struct xbundle *mac_xbundle = xbundle_lookup(mac->port.p);
+    mac_port = mac ? mac->port.p : NULL;
+    ovs_rwlock_unlock(&ctx->xbridge->ml->rwlock);
+
+    if (mac_port) {
+        struct xbundle *mac_xbundle = xbundle_lookup(mac_port);
         if (mac_xbundle && mac_xbundle != in_xbundle) {
             xlate_report(ctx, "forwarding to learned port");
             output_normal(ctx, mac_xbundle, vlan);
@@ -1310,7 +1314,6 @@ xlate_normal(struct xlate_ctx *ctx)
         }
         ctx->xout->nf_output_iface = NF_OUT_FLOOD;
     }
-    ovs_rwlock_unlock(&ctx->xbridge->ml->rwlock);
 }
 
 /* Compose SAMPLE action for sFlow or IPFIX.  The given probability is
@@ -1665,21 +1668,24 @@ compose_output_action(struct xlate_ctx *ctx, ofp_port_t ofp_port)
 
 static void
 xlate_recursively(struct xlate_ctx *ctx, struct rule_dpif *rule)
-    OVS_RELEASES(rule->up.evict)
+    OVS_RELEASES(rule)
 {
     struct rule_dpif *old_rule = ctx->rule;
+    const struct ofpact *ofpacts;
+    size_t ofpacts_len;
 
     if (ctx->xin->resubmit_stats) {
-        rule_credit_stats(rule, ctx->xin->resubmit_stats);
+        rule_dpif_credit_stats(rule, ctx->xin->resubmit_stats);
     }
 
     ctx->recurse++;
     ctx->rule = rule;
-    do_xlate_actions(rule->up.ofpacts, rule->up.ofpacts_len, ctx);
+    rule_dpif_get_actions(rule, &ofpacts, &ofpacts_len);
+    do_xlate_actions(ofpacts, ofpacts_len, ctx);
     ctx->rule = old_rule;
     ctx->recurse--;
 
-    rule_release(rule);
+    rule_dpif_release(rule);
 }
 
 static void
@@ -1719,10 +1725,9 @@ xlate_table_action(struct xlate_ctx *ctx,
              * OFPTC_TABLE_MISS_DROP
              * When OF1.0, OFPTC_TABLE_MISS_CONTINUE is used. What to do? */
             xport = get_ofp_port(ctx->xbridge, ctx->xin->flow.in_port.ofp_port);
-            rule = choose_miss_rule(xport ? xport->config : 0,
-                                    ctx->xbridge->miss_rule,
-                                    ctx->xbridge->no_packet_in_rule);
-            ovs_rwlock_rdlock(&rule->up.evict);
+            choose_miss_rule(xport ? xport->config : 0,
+                             ctx->xbridge->miss_rule,
+                             ctx->xbridge->no_packet_in_rule, &rule);
             xlate_recursively(ctx, rule);
         }
 
@@ -1808,7 +1813,7 @@ execute_controller_action(struct xlate_ctx *ctx, int len,
     pin->reason = reason;
     pin->controller_id = controller_id;
     pin->table_id = ctx->table_id;
-    pin->cookie = ctx->rule ? ctx->rule->up.flow_cookie : 0;
+    pin->cookie = ctx->rule ? rule_dpif_get_flow_cookie(ctx->rule) : 0;
 
     pin->send_len = len;
     flow_get_metadata(&ctx->xin->flow, &pin->fmd);
@@ -2116,8 +2121,8 @@ xlate_fin_timeout(struct xlate_ctx *ctx,
                   const struct ofpact_fin_timeout *oft)
 {
     if (ctx->xin->tcp_flags & (TCP_FIN | TCP_RST) && ctx->rule) {
-        ofproto_rule_reduce_timeouts(&ctx->rule->up, oft->fin_idle_timeout,
-                                     oft->fin_hard_timeout);
+        rule_dpif_reduce_timeouts(ctx->rule, oft->fin_idle_timeout,
+                                  oft->fin_hard_timeout);
     }
 }
 
@@ -2181,6 +2186,10 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
                                 ofpact_get_OUTPUT(a)->max_len, true);
             break;
 
+        case OFPACT_GROUP:
+            /* XXX not yet implemented */
+            break;
+
         case OFPACT_CONTROLLER:
             controller = ofpact_get_CONTROLLER(a);
             execute_controller_action(ctx, controller->max_len,
@@ -2595,8 +2604,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
         ofpacts = xin->ofpacts;
         ofpacts_len = xin->ofpacts_len;
     } else if (xin->rule) {
-        ofpacts = xin->rule->up.ofpacts;
-        ofpacts_len = xin->rule->up.ofpacts_len;
+        rule_dpif_get_actions(xin->rule, &ofpacts, &ofpacts_len);
     } else {
         NOT_REACHED();
     }
index ba24e92..a54a9e4 100644 (file)
@@ -21,6 +21,8 @@
 #include "ofpbuf.h"
 #include "ofproto-dpif-mirror.h"
 #include "ofproto-dpif.h"
+#include "ofproto.h"
+#include "stp.h"
 
 struct bfd;
 struct bond;
index d4c8f73..b52d4ee 100644 (file)
@@ -83,7 +83,29 @@ BUILD_ASSERT_DECL(N_TABLES >= 2 && N_TABLES <= 255);
 struct flow_miss;
 struct facet;
 
+struct rule_dpif {
+    struct rule up;
+
+    /* These statistics:
+     *
+     *   - Do include packets and bytes from facets that have been deleted or
+     *     whose own statistics have been folded into the rule.
+     *
+     *   - Do include packets and bytes sent "by hand" that were accounted to
+     *     the rule without any facet being involved (this is a rare corner
+     *     case in rule_execute()).
+     *
+     *   - Do not include packet or bytes that can be obtained from any facet's
+     *     packet_count or byte_count member or that can be obtained from the
+     *     datapath by, e.g., dpif_flow_get() for any subfacet.
+     */
+    struct ovs_mutex stats_mutex;
+    uint64_t packet_count OVS_GUARDED;  /* Number of packets received. */
+    uint64_t byte_count OVS_GUARDED;    /* Number of bytes received. */
+};
+
 static void rule_get_stats(struct rule *, uint64_t *packets, uint64_t *bytes);
+static struct rule_dpif *rule_dpif_cast(const struct rule *);
 
 struct ofbundle {
     struct hmap_node hmap_node; /* In struct ofproto's "bundles" hmap. */
@@ -205,8 +227,7 @@ static void subfacet_uninstall(struct subfacet *);
  * Flow expiration works in terms of subfacets, so a facet must have at
  * least one subfacet or it will never expire, leaking memory. */
 struct facet {
-    /* Owners. */
-    struct hmap_node hmap_node;  /* In owning ofproto's 'facets' hmap. */
+    /* Owner. */
     struct ofproto_dpif *ofproto;
 
     /* Owned data. */
@@ -822,7 +843,7 @@ type_run(const char *type)
             HMAP_FOR_EACH (ofport, up.hmap_node, &ofproto->up.ports) {
                 int stp_port = ofport->stp_port
                     ? stp_port_no(ofport->stp_port)
-                    : 0;
+                    : -1;
                 xlate_ofport_set(ofproto, ofport->bundle, ofport,
                                  ofport->up.ofp_port, ofport->odp_port,
                                  ofport->up.netdev, ofport->cfm,
@@ -1359,7 +1380,7 @@ add_internal_flow(struct ofproto_dpif *ofproto, int id,
 
     if (rule_dpif_lookup_in_table(ofproto, &fm.match.flow, NULL, TBL_INTERNAL,
                                   rulep)) {
-        ovs_rwlock_unlock(&(*rulep)->up.evict);
+        rule_dpif_release(*rulep);
     } else {
         NOT_REACHED();
     }
@@ -1421,13 +1442,24 @@ destruct(struct ofproto *ofproto_)
     struct rule_dpif *rule, *next_rule;
     struct ofputil_packet_in *pin, *next_pin;
     struct ofputil_flow_mod *fm, *next_fm;
+    struct facet *facet, *next_facet;
+    struct cls_cursor cursor;
     struct oftable *table;
 
+    ovs_rwlock_rdlock(&ofproto->facets.rwlock);
+    cls_cursor_init(&cursor, &ofproto->facets, NULL);
+    ovs_rwlock_unlock(&ofproto->facets.rwlock);
+    CLS_CURSOR_FOR_EACH_SAFE (facet, next_facet, cr, &cursor) {
+        facet_remove(facet);
+    }
+
     ofproto->backer->need_revalidate = REV_RECONFIGURE;
     ovs_rwlock_wrlock(&xlate_rwlock);
     xlate_remove_ofproto(ofproto);
     ovs_rwlock_unlock(&xlate_rwlock);
 
+    flow_miss_batch_ofproto_destroyed(ofproto->backer->udpif, ofproto);
+
     hmap_remove(&all_ofproto_dpifs, &ofproto->all_ofproto_dpifs_node);
     complete_operations(ofproto);
 
@@ -1500,14 +1532,9 @@ run_fast(struct ofproto *ofproto_)
     }
 
     ovs_mutex_lock(&ofproto->flow_mod_mutex);
-    if (ofproto->n_flow_mods) {
-        flow_mods = ofproto->flow_mods;
-        list_moved(&flow_mods);
-        list_init(&ofproto->flow_mods);
-        ofproto->n_flow_mods = 0;
-    } else {
-        list_init(&flow_mods);
-    }
+    list_move(&flow_mods, &ofproto->flow_mods);
+    list_init(&ofproto->flow_mods);
+    ofproto->n_flow_mods = 0;
     ovs_mutex_unlock(&ofproto->flow_mod_mutex);
 
     LIST_FOR_EACH_SAFE (fm, next_fm, list_node, &flow_mods) {
@@ -1523,14 +1550,9 @@ run_fast(struct ofproto *ofproto_)
     }
 
     ovs_mutex_lock(&ofproto->pin_mutex);
-    if (ofproto->n_pins) {
-        pins = ofproto->pins;
-        list_moved(&pins);
-        list_init(&ofproto->pins);
-        ofproto->n_pins = 0;
-    } else {
-        list_init(&pins);
-    }
+    list_move(&pins, &ofproto->pins);
+    list_init(&ofproto->pins);
+    ofproto->n_pins = 0;
     ovs_mutex_unlock(&ofproto->pin_mutex);
 
     LIST_FOR_EACH_SAFE (pin, next_pin, list_node, &pins) {
@@ -3109,7 +3131,7 @@ port_del(struct ofproto *ofproto_, ofp_port_t ofp_port)
     sset_find_and_delete(&ofproto->ghost_ports,
                          netdev_get_name(ofport->up.netdev));
     ofproto->backer->need_revalidate = REV_RECONFIGURE;
-    if (!ofport->is_tunnel) {
+    if (!ofport->is_tunnel && !netdev_vport_is_patch(ofport->up.netdev)) {
         error = dpif_port_del(ofproto->backer->dpif, ofport->odp_port);
         if (!error) {
             /* The caller is going to close ofport->up.netdev.  If this is a
@@ -3856,7 +3878,7 @@ subfacet_max_idle(const struct dpif_backer *backer)
      * pass made by update_stats(), because the former function never looks at
      * uninstallable subfacets.
      */
-    enum { BUCKET_WIDTH = ROUND_UP(100, TIME_UPDATE_INTERVAL) };
+    enum { BUCKET_WIDTH = 100 };
     enum { N_BUCKETS = 5000 / BUCKET_WIDTH };
     int buckets[N_BUCKETS] = { 0 };
     int total, subtotal, bucket;
@@ -4179,7 +4201,7 @@ facet_is_controller_flow(struct facet *facet)
         is_controller = ofpacts_len > 0
             && ofpacts->type == OFPACT_CONTROLLER
             && ofpact_next(ofpacts) >= ofpact_end(ofpacts, ofpacts_len);
-        rule_release(rule);
+        rule_dpif_release(rule);
         return is_controller;
     }
     return false;
@@ -4273,7 +4295,7 @@ facet_check_consistency(struct facet *facet)
     rule_dpif_lookup(facet->ofproto, &facet->flow, NULL, &rule);
     xlate_in_init(&xin, facet->ofproto, &facet->flow, rule, 0, NULL);
     xlate_actions(&xin, &xout);
-    rule_release(rule);
+    rule_dpif_release(rule);
 
     ok = ofpbuf_equal(&facet->xout.odp_actions, &xout.odp_actions)
         && facet->xout.slow == xout.slow;
@@ -4371,7 +4393,7 @@ facet_revalidate(struct facet *facet)
         || memcmp(&facet->xout.wc, &xout.wc, sizeof xout.wc)) {
         facet_remove(facet);
         xlate_out_uninit(&xout);
-        rule_release(new_rule);
+        rule_dpif_release(new_rule);
         return false;
     }
 
@@ -4403,7 +4425,7 @@ facet_revalidate(struct facet *facet)
     facet->used = MAX(facet->used, new_rule->up.created);
 
     xlate_out_uninit(&xout);
-    rule_release(new_rule);
+    rule_dpif_release(new_rule);
     return true;
 }
 
@@ -4431,12 +4453,12 @@ flow_push_stats(struct ofproto_dpif *ofproto, struct flow *flow,
     }
 
     rule_dpif_lookup(ofproto, flow, NULL, &rule);
-    rule_credit_stats(rule, stats);
+    rule_dpif_credit_stats(rule, stats);
     xlate_in_init(&xin, ofproto, flow, rule, stats->tcp_flags, NULL);
     xin.resubmit_stats = stats;
     xin.may_learn = may_learn;
     xlate_actions_for_side_effects(&xin);
-    rule_release(rule);
+    rule_dpif_release(rule);
 }
 
 static void
@@ -4502,14 +4524,42 @@ push_all_stats(void)
 }
 
 void
-rule_credit_stats(struct rule_dpif *rule, const struct dpif_flow_stats *stats)
+rule_dpif_credit_stats(struct rule_dpif *rule,
+                       const struct dpif_flow_stats *stats)
 {
     ovs_mutex_lock(&rule->stats_mutex);
     rule->packet_count += stats->n_packets;
     rule->byte_count += stats->n_bytes;
-    ofproto_rule_update_used(&rule->up, stats->used);
+    rule->up.used = MAX(rule->up.used, stats->used);
     ovs_mutex_unlock(&rule->stats_mutex);
 }
+
+bool
+rule_dpif_fail_open(const struct rule_dpif *rule)
+{
+    return rule->up.cr.priority == FAIL_OPEN_PRIORITY;
+}
+
+ovs_be64
+rule_dpif_get_flow_cookie(const struct rule_dpif *rule)
+{
+    return rule->up.flow_cookie;
+}
+
+void
+rule_dpif_reduce_timeouts(struct rule_dpif *rule, uint16_t idle_timeout,
+                     uint16_t hard_timeout)
+{
+    ofproto_rule_reduce_timeouts(&rule->up, idle_timeout, hard_timeout);
+}
+
+void
+rule_dpif_get_actions(const struct rule_dpif *rule,
+                      const struct ofpact **ofpacts, size_t *ofpacts_len)
+{
+    *ofpacts = rule->up.ofpacts;
+    *ofpacts_len = rule->up.ofpacts_len;
+}
 \f
 /* Subfacets. */
 
@@ -4778,16 +4828,15 @@ rule_dpif_lookup(struct ofproto_dpif *ofproto, const struct flow *flow,
                      flow->in_port.ofp_port);
     }
 
-    *rule = choose_miss_rule(port ? port->up.pp.config : 0, ofproto->miss_rule,
-                             ofproto->no_packet_in_rule);
-    ovs_rwlock_rdlock(&(*rule)->up.evict);
+    choose_miss_rule(port ? port->up.pp.config : 0, ofproto->miss_rule,
+                     ofproto->no_packet_in_rule, rule);
 }
 
 bool
 rule_dpif_lookup_in_table(struct ofproto_dpif *ofproto,
                           const struct flow *flow, struct flow_wildcards *wc,
                           uint8_t table_id, struct rule_dpif **rule)
-    OVS_TRY_RDLOCK(true, (*rule)->up.evict)
+    OVS_TRY_RDLOCK(true, (*rule)->up.rwlock)
 {
     struct cls_rule *cls_rule;
     struct classifier *cls;
@@ -4822,7 +4871,7 @@ rule_dpif_lookup_in_table(struct ofproto_dpif *ofproto,
     }
 
     *rule = rule_dpif_cast(rule_from_cls_rule(cls_rule));
-    if (*rule && ovs_rwlock_tryrdlock(&(*rule)->up.evict)) {
+    if (*rule && ovs_rwlock_tryrdlock(&(*rule)->up.rwlock)) {
         /* The rule is in the process of being removed.  Best we can do is
          * pretend it isn't there. */
         *rule = NULL;
@@ -4835,19 +4884,21 @@ rule_dpif_lookup_in_table(struct ofproto_dpif *ofproto,
 /* Given a port configuration (specified as zero if there's no port), chooses
  * which of 'miss_rule' and 'no_packet_in_rule' should be used in case of a
  * flow table miss. */
-struct rule_dpif *
+void
 choose_miss_rule(enum ofputil_port_config config, struct rule_dpif *miss_rule,
-                 struct rule_dpif *no_packet_in_rule)
+                 struct rule_dpif *no_packet_in_rule, struct rule_dpif **rule)
+    OVS_NO_THREAD_SAFETY_ANALYSIS
 {
-    return config & OFPUTIL_PC_NO_PACKET_IN ? no_packet_in_rule : miss_rule;
+    *rule = config & OFPUTIL_PC_NO_PACKET_IN ? no_packet_in_rule : miss_rule;
+    ovs_rwlock_rdlock(&(*rule)->up.rwlock);
 }
 
 void
-rule_release(struct rule_dpif *rule)
+rule_dpif_release(struct rule_dpif *rule)
     OVS_NO_THREAD_SAFETY_ANALYSIS
 {
     if (rule) {
-        ovs_rwlock_unlock(&rule->up.evict);
+        ovs_rwlock_unlock(&rule->up.rwlock);
     }
 }
 
@@ -4866,6 +4917,11 @@ complete_operation(struct rule_dpif *rule)
     }
 }
 
+static struct rule_dpif *rule_dpif_cast(const struct rule *rule)
+{
+    return rule ? CONTAINER_OF(rule, struct rule_dpif, up) : NULL;
+}
+
 static struct rule *
 rule_alloc(void)
 {
@@ -4942,7 +4998,7 @@ rule_dpif_execute(struct rule_dpif *rule, const struct flow *flow,
     struct xlate_in xin;
 
     dpif_flow_stats_extract(flow, packet, time_msec(), &stats);
-    rule_credit_stats(rule, &stats);
+    rule_dpif_credit_stats(rule, &stats);
 
     xlate_in_init(&xin, ofproto, flow, rule, stats.tcp_flags, packet);
     xin.resubmit_stats = &stats;
@@ -5563,7 +5619,7 @@ ofproto_trace(struct ofproto_dpif *ofproto, const struct flow *flow,
         xlate_out_uninit(&trace.xout);
     }
 
-    rule_release(rule);
+    rule_dpif_release(rule);
 }
 
 static void
@@ -6394,4 +6450,10 @@ const struct ofproto_class ofproto_dpif_class = {
     NULL,                       /* meter_set */
     NULL,                       /* meter_get */
     NULL,                       /* meter_del */
+    NULL,                       /* group_alloc */
+    NULL,                       /* group_construct */
+    NULL,                       /* group_destruct */
+    NULL,                       /* group_dealloc */
+    NULL,                       /* group_modify */
+    NULL,                       /* group_get_stats */
 };
index 15e58e9..7efc8d7 100644 (file)
 
 #include "hmapx.h"
 #include "odp-util.h"
-#include "ofproto/ofproto-provider.h"
+#include "ofp-util.h"
 #include "ovs-thread.h"
 #include "timer.h"
 #include "util.h"
 #include "ovs-thread.h"
 
 union user_action_cookie;
+struct dpif_flow_stats;
 struct ofproto_dpif;
 struct ofport_dpif;
 struct dpif_backer;
+struct OVS_LOCKABLE rule_dpif;
 
 /* Ofproto-dpif -- DPIF based ofproto implementation.
  *
@@ -58,48 +60,36 @@ struct dpif_backer;
  *   Ofproto-dpif-xlate is responsible for translating translating OpenFlow
  *   actions into datapath actions. */
 
-struct rule_dpif {
-    struct rule up;
-
-    /* These statistics:
-     *
-     *   - Do include packets and bytes from facets that have been deleted or
-     *     whose own statistics have been folded into the rule.
-     *
-     *   - Do include packets and bytes sent "by hand" that were accounted to
-     *     the rule without any facet being involved (this is a rare corner
-     *     case in rule_execute()).
-     *
-     *   - Do not include packet or bytes that can be obtained from any facet's
-     *     packet_count or byte_count member or that can be obtained from the
-     *     datapath by, e.g., dpif_flow_get() for any subfacet.
-     */
-    struct ovs_mutex stats_mutex;
-    uint64_t packet_count OVS_GUARDED;  /* Number of packets received. */
-    uint64_t byte_count OVS_GUARDED;    /* Number of bytes received. */
-};
-
-static inline struct rule_dpif *rule_dpif_cast(const struct rule *rule)
-{
-    return rule ? CONTAINER_OF(rule, struct rule_dpif, up) : NULL;
-}
-
 void rule_dpif_lookup(struct ofproto_dpif *, const struct flow *,
                       struct flow_wildcards *, struct rule_dpif **rule)
-    OVS_ACQ_RDLOCK((*rule)->up.evict);
+    OVS_ACQ_RDLOCK(*rule);
 
 bool rule_dpif_lookup_in_table(struct ofproto_dpif *, const struct flow *,
                                struct flow_wildcards *, uint8_t table_id,
                                struct rule_dpif **rule)
-    OVS_TRY_RDLOCK(true, (*rule)->up.evict);
+    OVS_TRY_RDLOCK(true, *rule);
+
+void rule_dpif_release(struct rule_dpif *rule) OVS_RELEASES(rule);
+
+void rule_dpif_credit_stats(struct rule_dpif *rule ,
+                            const struct dpif_flow_stats *);
+
+bool rule_dpif_fail_open(const struct rule_dpif *rule);
+
+void rule_dpif_get_actions(const struct rule_dpif *rule,
+                           const struct ofpact **ofpacts,
+                           size_t *ofpacts_len);
 
-void rule_release(struct rule_dpif *rule) OVS_RELEASES(rule->up.evict);
+ovs_be64 rule_dpif_get_flow_cookie(const struct rule_dpif *rule);
 
-void rule_credit_stats(struct rule_dpif *, const struct dpif_flow_stats *);
+void rule_dpif_reduce_timeouts(struct rule_dpif *rule, uint16_t idle_timeout,
+                               uint16_t hard_timeout);
 
-struct rule_dpif *choose_miss_rule(enum ofputil_port_config,
-                                   struct rule_dpif *miss_rule,
-                                   struct rule_dpif *no_packet_in_rule);
+void choose_miss_rule(enum ofputil_port_config,
+                      struct rule_dpif *miss_rule,
+                      struct rule_dpif *no_packet_in_rule,
+                      struct rule_dpif **rule)
+    OVS_ACQ_RDLOCK(*rule);
 
 bool ofproto_has_vlan_splinters(const struct ofproto_dpif *);
 ofp_port_t vsp_realdev_to_vlandev(const struct ofproto_dpif *,
index d6a8a0b..0b8a5e5 100644 (file)
@@ -69,6 +69,7 @@ struct ofproto {
     uint16_t max_ports;         /* Max possible OpenFlow port num, plus one. */
 
     /* Flow tables. */
+    long long int eviction_group_timer; /* For rate limited reheapification. */
     struct oftable *tables;
     int n_tables;
 
@@ -111,6 +112,12 @@ struct ofproto {
     unsigned long int *vlan_bitmap; /* 4096-bit bitmap of in-use VLANs. */
     bool vlans_changed;             /* True if new VLANs are in use. */
     int min_mtu;                    /* Current MTU of non-internal ports. */
+
+    /* Groups. */
+    struct ovs_rwlock groups_rwlock;
+    struct hmap groups OVS_GUARDED;   /* Contains "struct ofgroup"s. */
+    uint32_t n_groups[4] OVS_GUARDED; /* # of existing groups of each type. */
+    struct ofputil_group_features ogf;
 };
 
 void ofproto_init_tables(struct ofproto *, int n_tables);
@@ -216,7 +223,8 @@ struct rule {
 
     struct ofoperation *pending; /* Operation now in progress, if nonnull. */
 
-    ovs_be64 flow_cookie;        /* Controller-issued identifier. */
+    ovs_be64 flow_cookie;        /* Controller-issued identifier. Guarded by
+                                    rwlock. */
     struct hindex_node cookie_node; /* In owning ofproto's 'cookies' index. */
 
     long long int created;       /* Creation time. */
@@ -233,15 +241,18 @@ struct rule {
     struct heap_node evg_node;   /* In eviction_group's "rules" heap. */
     struct eviction_group *eviction_group; /* NULL if not in any group. */
 
-    /* The evict lock is used to prevent rules from being evicted while child
-     * threads are using them to xlate flows.  A read lock means the rule is
-     * currently being used.  A write lock means the rule is in the process of
-     * being evicted and should be considered gone.  A rule will not be evicted
-     * unless both its own and its classifiers write locks are held.
-     * Therefore, while holding a classifier readlock, one can be assured that
-     * even write locked rules are safe. */
-    struct ovs_rwlock evict;
+    /* The rwlock is used to protect those elements in struct rule which are
+     * accessed by multiple threads.  While maintaining a pointer to struct
+     * rule, threads are required to hold a readlock.  The main ofproto code is
+     * guaranteed not to evict the rule, or change any of the elements "Guarded
+     * by rwlock" without holding the writelock.
+     *
+     * A rule will not be evicted unless both its own and its classifier's
+     * write locks are held.  Therefore, while holding a classifier readlock,
+     * one can be assured that write locked rules are safe to reference. */
+    struct ovs_rwlock rwlock;
 
+    /* Guarded by rwlock. */
     struct ofpact *ofpacts;      /* Sequence of "struct ofpacts". */
     unsigned int ofpacts_len;    /* Size of 'ofpacts', in bytes. */
 
@@ -276,7 +287,6 @@ rule_from_cls_rule(const struct cls_rule *cls_rule)
     return cls_rule ? CONTAINER_OF(cls_rule, struct rule, cr) : NULL;
 }
 
-void ofproto_rule_update_used(struct rule *, long long int used);
 void ofproto_rule_expire(struct rule *rule, uint8_t reason);
 void ofproto_rule_delete(struct ofproto *, struct classifier *cls,
                          struct rule *) OVS_REQ_WRLOCK(cls->rwlock);
@@ -289,16 +299,50 @@ bool ofproto_rule_has_out_port(const struct rule *, ofp_port_t out_port);
 void ofoperation_complete(struct ofoperation *, enum ofperr);
 
 bool ofoperation_has_out_port(const struct ofoperation *, ofp_port_t out_port);
+bool ofproto_rule_has_out_group(const struct rule *, uint32_t group_id);
 
 bool ofproto_rule_is_hidden(const struct rule *);
 
+/* A group within a "struct ofproto".
+ *
+ * With few exceptions, ofproto implementations may look at these fields but
+ * should not modify them. */
+struct ofgroup {
+    /* The rwlock is used to prevent groups from being deleted while child
+     * threads are using them to xlate flows.  A read lock means the
+     * group is currently being used.  A write lock means the group is
+     * in the process of being deleted or updated.  Note that since
+     * a read lock on the groups container is held while searching, and
+     * a group is ever write locked only while holding a write lock
+     * on the container, the user's of groups will never face a group
+     * in the write locked state. */
+    struct ovs_rwlock rwlock;
+    struct hmap_node hmap_node; /* In struct ofproto's "groups" hmap. */
+    struct ofproto *ofproto;    /* The ofproto that contains this group. */
+    uint32_t group_id;
+    enum ofp11_group_type type; /* One of OFPGT_*. */
+
+    long long int created;      /* Creation time. */
+    long long int modified;     /* Time of last modification. */
+
+    struct list buckets;        /* Contains "struct ofputil_bucket"s. */
+    uint32_t n_buckets;
+};
+
+bool ofproto_group_lookup(const struct ofproto *ofproto, uint32_t group_id,
+                          struct ofgroup **group)
+    OVS_TRY_RDLOCK(true, (*group)->rwlock);
+
+void ofproto_group_release(struct ofgroup *group)
+    OVS_RELEASES(group->rwlock);
+
 /* ofproto class structure, to be defined by each ofproto implementation.
  *
  *
  * Data Structures
  * ===============
  *
- * These functions work primarily with three different kinds of data
+ * These functions work primarily with four different kinds of data
  * structures:
  *
  *   - "struct ofproto", which represents an OpenFlow switch.
@@ -307,6 +351,9 @@ bool ofproto_rule_is_hidden(const struct rule *);
  *
  *   - "struct rule", which represents an OpenFlow flow within an ofproto.
  *
+ *   - "struct ofgroup", which represents an OpenFlow 1.1+ group within an
+ *     ofproto.
+ *
  * Each of these data structures contains all of the implementation-independent
  * generic state for the respective concept, called the "base" state.  None of
  * them contains any extra space for ofproto implementations to use.  Instead,
@@ -328,9 +375,10 @@ bool ofproto_rule_is_hidden(const struct rule *);
  *   ofproto  ->alloc       ->construct       ->destruct       ->dealloc
  *   ofport   ->port_alloc  ->port_construct  ->port_destruct  ->port_dealloc
  *   rule     ->rule_alloc  ->rule_construct  ->rule_destruct  ->rule_dealloc
+ *   group    ->group_alloc ->group_construct ->group_destruct ->group_dealloc
  *
- * "ofproto" and "ofport" have this exact life cycle.  The "rule" data
- * structure also follow this life cycle with some additional elaborations
+ * "ofproto", "ofport", and "group" have this exact life cycle.  The "rule"
+ * data structure also follow this life cycle with some additional elaborations
  * described under "Rule Life Cycle" below.
  *
  * Any instance of a given data structure goes through the following life
@@ -1451,6 +1499,21 @@ struct ofproto_class {
     /* Deletes a meter, making the 'ofproto_meter_id' invalid for any
      * further calls. */
     void (*meter_del)(struct ofproto *, ofproto_meter_id);
+
+
+/* ## -------------------- ## */
+/* ## OpenFlow 1.1+ groups ## */
+/* ## -------------------- ## */
+
+    struct ofgroup *(*group_alloc)(void);
+    enum ofperr (*group_construct)(struct ofgroup *);
+    void (*group_destruct)(struct ofgroup *);
+    void (*group_dealloc)(struct ofgroup *);
+
+    enum ofperr (*group_modify)(struct ofgroup *, struct ofgroup *victim);
+
+    enum ofperr (*group_get_stats)(const struct ofgroup *,
+                                   struct ofputil_group_stats *);
 };
 
 extern const struct ofproto_class ofproto_dpif_class;
index 1173936..b94fd8e 100644 (file)
@@ -155,10 +155,10 @@ static void oftable_enable_eviction(struct oftable *,
                                     const struct mf_subfield *fields,
                                     size_t n_fields);
 
-static void oftable_remove_rule(struct rule *rule) OVS_RELEASES(rule->evict);
+static void oftable_remove_rule(struct rule *rule) OVS_RELEASES(rule->rwlock);
 static void oftable_remove_rule__(struct ofproto *ofproto,
                                   struct classifier *cls, struct rule *rule)
-    OVS_REQ_WRLOCK(cls->rwlock) OVS_RELEASES(rule->evict);
+    OVS_REQ_WRLOCK(cls->rwlock) OVS_RELEASES(rule->rwlock);
 static void oftable_insert_rule(struct rule *);
 
 /* A set of rules within a single OpenFlow table (oftable) that have the same
@@ -184,7 +184,7 @@ struct eviction_group {
 };
 
 static bool choose_rule_to_evict(struct oftable *table, struct rule **rulep)
-    OVS_TRY_WRLOCK(true, (*rulep)->evict);
+    OVS_TRY_WRLOCK(true, (*rulep)->rwlock);
 static void ofproto_evict(struct ofproto *);
 static uint32_t rule_eviction_priority(struct rule *);
 static void eviction_group_add_rule(struct rule *);
@@ -212,7 +212,8 @@ static enum ofperr modify_flows__(struct ofproto *, struct ofconn *,
                                   const struct ofp_header *, struct list *);
 static void delete_flow__(struct rule *rule, struct ofopgroup *,
                           enum ofp_flow_removed_reason)
-    OVS_RELEASES(rule->evict);
+    OVS_RELEASES(rule->rwlock);
+static enum ofperr add_group(struct ofproto *, struct ofputil_group_mod *);
 static bool handle_openflow(struct ofconn *, const struct ofpbuf *);
 static enum ofperr handle_flow_mod__(struct ofproto *, struct ofconn *,
                                      struct ofputil_flow_mod *,
@@ -439,6 +440,7 @@ ofproto_create(const char *datapath_name, const char *datapath_type,
     shash_init(&ofproto->port_by_name);
     simap_init(&ofproto->ofp_requests);
     ofproto->max_ports = ofp_to_u16(OFPP_MAX);
+    ofproto->eviction_group_timer = LLONG_MIN;
     ofproto->tables = NULL;
     ofproto->n_tables = 0;
     hindex_init(&ofproto->cookies);
@@ -456,6 +458,8 @@ ofproto_create(const char *datapath_name, const char *datapath_type,
     ofproto->vlan_bitmap = NULL;
     ofproto->vlans_changed = false;
     ofproto->min_mtu = INT_MAX;
+    ovs_rwlock_init(&ofproto->groups_rwlock);
+    hmap_init(&ofproto->groups);
 
     error = ofproto->ofproto_class->construct(ofproto);
     if (error) {
@@ -1090,7 +1094,7 @@ ofproto_delete_rule(struct ofproto *ofproto, struct classifier *cls,
 
     group = ofopgroup_create_unattached(ofproto);
     ofoperation_create(group, rule, OFOPERATION_DELETE, OFPRR_DELETE);
-    ovs_rwlock_wrlock(&rule->evict);
+    ovs_rwlock_wrlock(&rule->rwlock);
     oftable_remove_rule__(ofproto, cls, rule);
     ofproto->ofproto_class->rule_delete(rule);
     ofopgroup_submit(group);
@@ -1124,6 +1128,8 @@ ofproto_flush__(struct ofproto *ofproto)
     }
 }
 
+static void delete_group(struct ofproto *ofproto, uint32_t group_id);
+
 static void
 ofproto_destroy__(struct ofproto *ofproto)
 {
@@ -1137,6 +1143,10 @@ ofproto_destroy__(struct ofproto *ofproto)
         free(ofproto->meters);
     }
 
+    delete_group(ofproto, OFPG_ALL);
+    ovs_rwlock_destroy(&ofproto->groups_rwlock);
+    hmap_destroy(&ofproto->groups);
+
     connmgr_destroy(ofproto->connmgr);
 
     hmap_remove(&all_ofprotos, &ofproto->hmap_node);
@@ -1269,6 +1279,39 @@ ofproto_run(struct ofproto *p)
         VLOG_ERR_RL(&rl, "%s: run failed (%s)", p->name, ovs_strerror(error));
     }
 
+    /* Restore the eviction group heap invariant occasionally. */
+    if (p->eviction_group_timer < time_msec()) {
+        size_t i;
+
+        p->eviction_group_timer = time_msec() + 1000;
+
+        for (i = 0; i < p->n_tables; i++) {
+            struct oftable *table = &p->tables[i];
+            struct eviction_group *evg;
+            struct cls_cursor cursor;
+            struct cls_rule cr;
+            struct rule *rule;
+
+            if (!table->eviction_fields) {
+                continue;
+            }
+
+            HEAP_FOR_EACH (evg, size_node, &table->eviction_groups_by_size) {
+                heap_rebuild(&evg->rules);
+            }
+
+            ovs_rwlock_rdlock(&table->cls.rwlock);
+            cls_cursor_init(&cursor, &table->cls, &cr);
+            CLS_CURSOR_FOR_EACH (rule, cr, &cursor) {
+                if (!rule->eviction_group
+                    && (rule->idle_timeout || rule->hard_timeout)) {
+                    eviction_group_add_rule(rule);
+                }
+            }
+            ovs_rwlock_unlock(&table->cls.rwlock);
+        }
+    }
+
     if (p->ofproto_class->port_poll) {
         char *devname;
 
@@ -1838,8 +1881,8 @@ ofport_open(struct ofproto *ofproto,
     pp->state = netdev_get_carrier(netdev) ? 0 : OFPUTIL_PS_LINK_DOWN;
     netdev_get_features(netdev, &pp->curr, &pp->advertised,
                         &pp->supported, &pp->peer);
-    pp->curr_speed = netdev_features_to_bps(pp->curr, 0);
-    pp->max_speed = netdev_features_to_bps(pp->supported, 0);
+    pp->curr_speed = netdev_features_to_bps(pp->curr, 0) / 1000;
+    pp->max_speed = netdev_features_to_bps(pp->supported, 0) / 1000;
 
     return netdev;
 }
@@ -2220,7 +2263,7 @@ ofproto_rule_destroy__(struct rule *rule)
         cls_rule_destroy(&rule->cr);
         free(rule->ofpacts);
         ovs_mutex_destroy(&rule->timeout_mutex);
-        ovs_rwlock_destroy(&rule->evict);
+        ovs_rwlock_destroy(&rule->rwlock);
         rule->ofproto->ofproto_class->rule_dealloc(rule);
     }
 }
@@ -2249,6 +2292,14 @@ ofproto_rule_has_out_port(const struct rule *rule, ofp_port_t port)
             || ofpacts_output_to_port(rule->ofpacts, rule->ofpacts_len, port));
 }
 
+/* Returns true if 'rule' has group and equals group_id. */
+bool
+ofproto_rule_has_out_group(const struct rule *rule, uint32_t group_id)
+{
+    return (group_id == OFPG11_ANY
+            || ofpacts_output_to_group(rule->ofpacts, rule->ofpacts_len, group_id));
+}
+
 /* Returns true if a rule related to 'op' has an OpenFlow OFPAT_OUTPUT or
  * OFPAT_ENQUEUE action that outputs to 'out_port'. */
 bool
@@ -2792,7 +2843,9 @@ ofproto_rule_change_cookie(struct ofproto *ofproto, struct rule *rule,
     if (new_cookie != rule->flow_cookie) {
         cookies_remove(ofproto, rule);
 
+        ovs_rwlock_wrlock(&rule->rwlock);
         rule->flow_cookie = new_cookie;
+        ovs_rwlock_unlock(&rule->rwlock);
 
         cookies_insert(ofproto, rule);
     }
@@ -2890,7 +2943,8 @@ static enum ofperr
 collect_rules_loose(struct ofproto *ofproto, uint8_t table_id,
                     const struct match *match,
                     ovs_be64 cookie, ovs_be64 cookie_mask,
-                    ofp_port_t out_port, struct list *rules)
+                    ofp_port_t out_port, uint32_t out_group,
+                    struct list *rules)
 {
     struct oftable *table;
     struct cls_rule cr;
@@ -2943,6 +2997,7 @@ collect_rules_loose(struct ofproto *ofproto, uint8_t table_id,
             }
             if (!ofproto_rule_is_hidden(rule)
                 && ofproto_rule_has_out_port(rule, out_port)
+                && ofproto_rule_has_out_group(rule, out_group)
                     && !((rule->flow_cookie ^ cookie) & cookie_mask)) {
                 list_push_back(rules, &rule->ofproto_node);
             }
@@ -2970,7 +3025,8 @@ static enum ofperr
 collect_rules_strict(struct ofproto *ofproto, uint8_t table_id,
                      const struct match *match, unsigned int priority,
                      ovs_be64 cookie, ovs_be64 cookie_mask,
-                     ofp_port_t out_port, struct list *rules)
+                     ofp_port_t out_port, uint32_t out_group,
+                     struct list *rules)
 {
     struct oftable *table;
     struct cls_rule cr;
@@ -3023,6 +3079,7 @@ collect_rules_strict(struct ofproto *ofproto, uint8_t table_id,
             }
             if (!ofproto_rule_is_hidden(rule)
                 && ofproto_rule_has_out_port(rule, out_port)
+                && ofproto_rule_has_out_group(rule, out_group)
                     && !((rule->flow_cookie ^ cookie) & cookie_mask)) {
                 list_push_back(rules, &rule->ofproto_node);
             }
@@ -3062,7 +3119,7 @@ handle_flow_stats_request(struct ofconn *ofconn,
 
     error = collect_rules_loose(ofproto, fsr.table_id, &fsr.match,
                                 fsr.cookie, fsr.cookie_mask,
-                                fsr.out_port, &rules);
+                                fsr.out_port, fsr.out_group, &rules);
     if (error) {
         return error;
     }
@@ -3189,7 +3246,7 @@ handle_aggregate_stats_request(struct ofconn *ofconn,
 
     error = collect_rules_loose(ofproto, request.table_id, &request.match,
                                 request.cookie, request.cookie_mask,
-                                request.out_port, &rules);
+                                request.out_port, request.out_group, &rules);
     if (error) {
         return error;
     }
@@ -3363,7 +3420,7 @@ evict_rule_from_table(struct ofproto *ofproto, struct oftable *table)
     } else if (!choose_rule_to_evict(table, &rule)) {
         return OFPERR_OFPFMFC_TABLE_FULL;
     } else if (rule->pending) {
-        ovs_rwlock_unlock(&rule->evict);
+        ovs_rwlock_unlock(&rule->rwlock);
         return OFPROTO_POSTPONE;
     } else {
         struct ofopgroup *group;
@@ -3456,6 +3513,7 @@ add_flow(struct ofproto *ofproto, struct ofconn *ofconn,
     error = ofproto_check_ofpacts(ofproto, fm->ofpacts, fm->ofpacts_len,
                                   &fm->match.flow, table_id);
     if (error) {
+        cls_rule_destroy(&cr);
         return error;
     }
 
@@ -3519,7 +3577,7 @@ add_flow(struct ofproto *ofproto, struct ofconn *ofconn,
     rule->monitor_flags = 0;
     rule->add_seqno = 0;
     rule->modify_seqno = 0;
-    ovs_rwlock_init(&rule->evict);
+    ovs_rwlock_init(&rule->rwlock);
 
     /* Construct rule, initializing derived state. */
     error = ofproto->ofproto_class->rule_construct(rule);
@@ -3613,8 +3671,12 @@ modify_flows__(struct ofproto *ofproto, struct ofconn *ofconn,
             op->ofpacts = rule->ofpacts;
             op->ofpacts_len = rule->ofpacts_len;
             op->meter_id = rule->meter_id;
+
+            ovs_rwlock_wrlock(&rule->rwlock);
             rule->ofpacts = xmemdup(fm->ofpacts, fm->ofpacts_len);
             rule->ofpacts_len = fm->ofpacts_len;
+            ovs_rwlock_unlock(&rule->rwlock);
+
             rule->meter_id = find_meter(rule->ofpacts, rule->ofpacts_len);
             rule->ofproto->ofproto_class->rule_modify_actions(rule,
                                                               reset_counters);
@@ -3652,7 +3714,7 @@ modify_flows_loose(struct ofproto *ofproto, struct ofconn *ofconn,
 
     error = collect_rules_loose(ofproto, fm->table_id, &fm->match,
                                 fm->cookie, fm->cookie_mask,
-                                OFPP_ANY, &rules);
+                                OFPP_ANY, OFPG11_ANY, &rules);
     if (error) {
         return error;
     } else if (list_is_empty(&rules)) {
@@ -3677,8 +3739,7 @@ modify_flow_strict(struct ofproto *ofproto, struct ofconn *ofconn,
 
     error = collect_rules_strict(ofproto, fm->table_id, &fm->match,
                                  fm->priority, fm->cookie, fm->cookie_mask,
-                                 OFPP_ANY, &rules);
-
+                                 OFPP_ANY, OFPG11_ANY, &rules);
     if (error) {
         return error;
     } else if (list_is_empty(&rules)) {
@@ -3718,7 +3779,7 @@ delete_flows__(struct ofproto *ofproto, struct ofconn *ofconn,
 
     group = ofopgroup_create(ofproto, ofconn, request, UINT32_MAX);
     LIST_FOR_EACH_SAFE (rule, next, ofproto_node, rules) {
-        ovs_rwlock_wrlock(&rule->evict);
+        ovs_rwlock_wrlock(&rule->rwlock);
         delete_flow__(rule, group, reason);
     }
     ofopgroup_submit(group);
@@ -3737,7 +3798,7 @@ delete_flows_loose(struct ofproto *ofproto, struct ofconn *ofconn,
 
     error = collect_rules_loose(ofproto, fm->table_id, &fm->match,
                                 fm->cookie, fm->cookie_mask,
-                                fm->out_port, &rules);
+                                fm->out_port, fm->out_group, &rules);
     return (error ? error
             : !list_is_empty(&rules) ? delete_flows__(ofproto, ofconn, request,
                                                       &rules, OFPRR_DELETE)
@@ -3755,7 +3816,7 @@ delete_flow_strict(struct ofproto *ofproto, struct ofconn *ofconn,
 
     error = collect_rules_strict(ofproto, fm->table_id, &fm->match,
                                  fm->priority, fm->cookie, fm->cookie_mask,
-                                 fm->out_port, &rules);
+                                 fm->out_port, fm->out_group, &rules);
     return (error ? error
             : list_is_singleton(&rules) ? delete_flows__(ofproto, ofconn,
                                                          request, &rules,
@@ -3789,20 +3850,6 @@ ofproto_rule_send_removed(struct rule *rule, uint8_t reason)
     connmgr_send_flow_removed(rule->ofproto->connmgr, &fr);
 }
 
-void
-ofproto_rule_update_used(struct rule *rule, long long int used)
-{
-    if (used > rule->used) {
-        struct eviction_group *evg = rule->eviction_group;
-
-        rule->used = used;
-        if (evg) {
-            heap_change(&evg->rules, &rule->evg_node,
-                        rule_eviction_priority(rule));
-        }
-    }
-}
-
 /* Sends an OpenFlow "flow removed" message with the given 'reason' (either
  * OFPRR_HARD_TIMEOUT or OFPRR_IDLE_TIMEOUT), and then removes 'rule' from its
  * ofproto.
@@ -3818,7 +3865,8 @@ ofproto_rule_expire(struct rule *rule, uint8_t reason)
     struct ofproto *ofproto = rule->ofproto;
     struct classifier *cls = &ofproto->tables[rule->table_id].cls;
 
-    ovs_assert(reason == OFPRR_HARD_TIMEOUT || reason == OFPRR_IDLE_TIMEOUT);
+    ovs_assert(reason == OFPRR_HARD_TIMEOUT || reason == OFPRR_IDLE_TIMEOUT
+               || reason == OFPRR_DELETE || reason == OFPRR_GROUP_DELETE);
     ofproto_rule_send_removed(rule, reason);
 
     ovs_rwlock_wrlock(&cls->rwlock);
@@ -3860,10 +3908,6 @@ ofproto_rule_reduce_timeouts(struct rule *rule,
     reduce_timeout(idle_timeout, &rule->idle_timeout);
     reduce_timeout(hard_timeout, &rule->hard_timeout);
     ovs_mutex_unlock(&rule->timeout_mutex);
-
-    if (!rule->eviction_group) {
-        eviction_group_add_rule(rule);
-    }
 }
 \f
 static enum ofperr
@@ -4675,6 +4719,406 @@ handle_meter_request(struct ofconn *ofconn, const struct ofp_header *request,
     return 0;
 }
 
+bool
+ofproto_group_lookup(const struct ofproto *ofproto, uint32_t group_id,
+                     struct ofgroup **group)
+    OVS_TRY_RDLOCK(true, (*group)->rwlock)
+{
+    ovs_rwlock_rdlock(&ofproto->groups_rwlock);
+    HMAP_FOR_EACH_IN_BUCKET (*group, hmap_node,
+                             hash_int(group_id, 0), &ofproto->groups) {
+        if ((*group)->group_id == group_id) {
+            ovs_rwlock_rdlock(&(*group)->rwlock);
+            ovs_rwlock_unlock(&ofproto->groups_rwlock);
+            return true;
+        }
+    }
+    ovs_rwlock_unlock(&ofproto->groups_rwlock);
+    return false;
+}
+
+void
+ofproto_group_release(struct ofgroup *group)
+    OVS_RELEASES(group->rwlock)
+{
+    ovs_rwlock_unlock(&group->rwlock);
+}
+
+static bool
+ofproto_group_write_lookup(const struct ofproto *ofproto, uint32_t group_id,
+                           struct ofgroup **group)
+    OVS_TRY_WRLOCK(true, ofproto->groups_rwlock)
+    OVS_TRY_WRLOCK(true, (*group)->rwlock)
+{
+    ovs_rwlock_wrlock(&ofproto->groups_rwlock);
+    HMAP_FOR_EACH_IN_BUCKET (*group, hmap_node,
+                             hash_int(group_id, 0), &ofproto->groups) {
+        if ((*group)->group_id == group_id) {
+            ovs_rwlock_wrlock(&(*group)->rwlock);
+            return true;
+        }
+    }
+    ovs_rwlock_unlock(&ofproto->groups_rwlock);
+    return false;
+}
+
+static bool
+ofproto_group_exists(const struct ofproto *ofproto, uint32_t group_id)
+    OVS_REQ_RDLOCK(ofproto->groups_rwlock)
+{
+    struct ofgroup *grp;
+
+    HMAP_FOR_EACH_IN_BUCKET (grp, hmap_node,
+                             hash_int(group_id, 0), &ofproto->groups) {
+        if (grp->group_id == group_id) {
+            return true;
+        }
+    }
+    return false;
+}
+
+static void
+append_group_stats(struct ofgroup *group, struct list *replies)
+    OVS_REQ_RDLOCK(group->rwlock)
+{
+    struct ofputil_group_stats ogs;
+    struct ofproto *ofproto = group->ofproto;
+    long long int now = time_msec();
+    int error;
+
+    ogs.bucket_stats = xmalloc(group->n_buckets * sizeof *ogs.bucket_stats);
+
+    error = (ofproto->ofproto_class->group_get_stats
+             ? ofproto->ofproto_class->group_get_stats(group, &ogs)
+             : EOPNOTSUPP);
+    if (error) {
+        ogs.ref_count = UINT32_MAX;
+        ogs.packet_count = UINT64_MAX;
+        ogs.byte_count = UINT64_MAX;
+        ogs.n_buckets = group->n_buckets;
+        memset(ogs.bucket_stats, 0xff,
+               ogs.n_buckets * sizeof *ogs.bucket_stats);
+    }
+
+    ogs.group_id = group->group_id;
+    calc_duration(group->created, now, &ogs.duration_sec, &ogs.duration_nsec);
+
+    ofputil_append_group_stats(replies, &ogs);
+
+    free(ogs.bucket_stats);
+}
+
+static enum ofperr
+handle_group_stats_request(struct ofconn *ofconn,
+                           const struct ofp_header *request)
+{
+    struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
+    struct list replies;
+    enum ofperr error;
+    struct ofgroup *group;
+    uint32_t group_id;
+
+    error = ofputil_decode_group_stats_request(request, &group_id);
+    if (error) {
+        return error;
+    }
+
+    ofpmp_init(&replies, request);
+
+    if (group_id == OFPG_ALL) {
+        ovs_rwlock_rdlock(&ofproto->groups_rwlock);
+        HMAP_FOR_EACH (group, hmap_node, &ofproto->groups) {
+            ovs_rwlock_rdlock(&group->rwlock);
+            append_group_stats(group, &replies);
+            ovs_rwlock_unlock(&group->rwlock);
+        }
+        ovs_rwlock_unlock(&ofproto->groups_rwlock);
+    } else {
+        if (ofproto_group_lookup(ofproto, group_id, &group)) {
+            append_group_stats(group, &replies);
+            ofproto_group_release(group);
+        }
+    }
+
+    ofconn_send_replies(ofconn, &replies);
+
+    return 0;
+}
+
+static enum ofperr
+handle_group_desc_stats_request(struct ofconn *ofconn,
+                                const struct ofp_header *request)
+{
+    struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
+    struct list replies;
+    struct ofputil_group_desc gds;
+    struct ofgroup *group;
+
+    ofpmp_init(&replies, request);
+
+    ovs_rwlock_rdlock(&ofproto->groups_rwlock);
+    HMAP_FOR_EACH (group, hmap_node, &ofproto->groups) {
+        gds.group_id = group->group_id;
+        gds.type = group->type;
+        ofputil_append_group_desc_reply(&gds, &group->buckets, &replies);
+    }
+    ovs_rwlock_unlock(&ofproto->groups_rwlock);
+
+    ofconn_send_replies(ofconn, &replies);
+
+    return 0;
+}
+
+static enum ofperr
+handle_group_features_stats_request(struct ofconn *ofconn,
+                                    const struct ofp_header *request)
+{
+    struct ofproto *p = ofconn_get_ofproto(ofconn);
+    struct ofpbuf *msg;
+
+    msg = ofputil_encode_group_features_reply(&p->ogf, request);
+    if (msg) {
+        ofconn_send_reply(ofconn, msg);
+    }
+
+    return 0;
+}
+
+/* Implements OFPGC11_ADD
+ * in which no matching flow already exists in the flow table.
+ *
+ * Adds the flow specified by 'ofm', which is followed by 'n_actions'
+ * ofp_actions, to the ofproto's flow table.  Returns 0 on success, an OpenFlow
+ * error code on failure, or OFPROTO_POSTPONE if the operation cannot be
+ * initiated now but may be retried later.
+ *
+ * Upon successful return, takes ownership of 'fm->ofpacts'.  On failure,
+ * ownership remains with the caller.
+ *
+ * 'ofconn' is used to retrieve the packet buffer specified in ofm->buffer_id,
+ * if any. */
+static enum ofperr
+add_group(struct ofproto *ofproto, struct ofputil_group_mod *gm)
+{
+    struct ofgroup *ofgroup;
+    enum ofperr error;
+
+    if (gm->group_id > OFPG_MAX) {
+        return OFPERR_OFPGMFC_INVALID_GROUP;
+    }
+    if (gm->type > OFPGT11_FF) {
+        return OFPERR_OFPGMFC_BAD_TYPE;
+    }
+
+    /* Allocate new group and initialize it. */
+    ofgroup = ofproto->ofproto_class->group_alloc();
+    if (!ofgroup) {
+        VLOG_WARN_RL(&rl, "%s: failed to create group", ofproto->name);
+        return OFPERR_OFPGMFC_OUT_OF_GROUPS;
+    }
+
+    ovs_rwlock_init(&ofgroup->rwlock);
+    ofgroup->ofproto  = ofproto;
+    ofgroup->group_id = gm->group_id;
+    ofgroup->type     = gm->type;
+    ofgroup->created = ofgroup->modified = time_msec();
+
+    list_move(&ofgroup->buckets, &gm->buckets);
+    ofgroup->n_buckets = list_size(&ofgroup->buckets);
+
+    /* Construct called BEFORE any locks are held. */
+    error = ofproto->ofproto_class->group_construct(ofgroup);
+    if (error) {
+        goto free_out;
+    }
+
+    /* We wrlock as late as possible to minimize the time we jam any other
+     * threads: No visible state changes before acquiring the lock. */
+    ovs_rwlock_wrlock(&ofproto->groups_rwlock);
+
+    if (ofproto->n_groups[gm->type] >= ofproto->ogf.max_groups[gm->type]) {
+        error = OFPERR_OFPGMFC_OUT_OF_GROUPS;
+        goto unlock_out;
+    }
+
+    if (ofproto_group_exists(ofproto, gm->group_id)) {
+        error = OFPERR_OFPGMFC_GROUP_EXISTS;
+        goto unlock_out;
+    }
+
+    if (!error) {
+        /* Insert new group. */
+        hmap_insert(&ofproto->groups, &ofgroup->hmap_node,
+                    hash_int(ofgroup->group_id, 0));
+        ofproto->n_groups[ofgroup->type]++;
+
+        ovs_rwlock_unlock(&ofproto->groups_rwlock);
+        return error;
+    }
+
+ unlock_out:
+    ovs_rwlock_unlock(&ofproto->groups_rwlock);
+    ofproto->ofproto_class->group_destruct(ofgroup);
+ free_out:
+    ofputil_bucket_list_destroy(&ofgroup->buckets);
+    ofproto->ofproto_class->group_dealloc(ofgroup);
+
+    return error;
+}
+
+/* Implements OFPFC_MODIFY.  Returns 0 on success or an OpenFlow error code on
+ * failure.
+ *
+ * 'ofconn' is used to retrieve the packet buffer specified in fm->buffer_id,
+ * if any. */
+static enum ofperr
+modify_group(struct ofproto *ofproto, struct ofputil_group_mod *gm)
+{
+    struct ofgroup *ofgroup;
+    struct ofgroup *victim;
+    enum ofperr error;
+
+    if (gm->group_id > OFPG_MAX) {
+        return OFPERR_OFPGMFC_INVALID_GROUP;
+    }
+
+    if (gm->type > OFPGT11_FF) {
+        return OFPERR_OFPGMFC_BAD_TYPE;
+    }
+
+    victim = ofproto->ofproto_class->group_alloc();
+    if (!victim) {
+        VLOG_WARN_RL(&rl, "%s: failed to allocate group", ofproto->name);
+        return OFPERR_OFPGMFC_OUT_OF_GROUPS;
+    }
+
+    if (!ofproto_group_write_lookup(ofproto, gm->group_id, &ofgroup)) {
+        error = OFPERR_OFPGMFC_UNKNOWN_GROUP;
+        goto free_out;
+    }
+    /* Both group's and its container's write locks held now.
+     * Also, n_groups[] is protected by ofproto->groups_rwlock. */
+    if (ofgroup->type != gm->type
+        && ofproto->n_groups[gm->type] >= ofproto->ogf.max_groups[gm->type]) {
+        error = OFPERR_OFPGMFC_OUT_OF_GROUPS;
+        goto unlock_out;
+    }
+
+    *victim = *ofgroup;
+    list_move(&victim->buckets, &ofgroup->buckets);
+
+    ofgroup->type = gm->type;
+    list_move(&ofgroup->buckets, &gm->buckets);
+    ofgroup->n_buckets = list_size(&ofgroup->buckets);
+
+    error = ofproto->ofproto_class->group_modify(ofgroup, victim);
+    if (!error) {
+        ofputil_bucket_list_destroy(&victim->buckets);
+        ofproto->n_groups[victim->type]--;
+        ofproto->n_groups[ofgroup->type]++;
+        ofgroup->modified = time_msec();
+    } else {
+        ofputil_bucket_list_destroy(&ofgroup->buckets);
+
+        *ofgroup = *victim;
+        list_move(&ofgroup->buckets, &victim->buckets);
+    }
+
+ unlock_out:
+    ovs_rwlock_unlock(&ofgroup->rwlock);
+    ovs_rwlock_unlock(&ofproto->groups_rwlock);
+ free_out:
+    ofproto->ofproto_class->group_dealloc(victim);
+    return error;
+}
+
+static void
+delete_group__(struct ofproto *ofproto, struct ofgroup *ofgroup)
+    OVS_RELEASES(ofproto->groups_rwlock)
+{
+    /* Must wait until existing readers are done,
+     * while holding the container's write lock at the same time. */
+    ovs_rwlock_wrlock(&ofgroup->rwlock);
+    hmap_remove(&ofproto->groups, &ofgroup->hmap_node);
+    /* No-one can find this group any more. */
+    ofproto->n_groups[ofgroup->type]--;
+    ovs_rwlock_unlock(&ofproto->groups_rwlock);
+
+    ofproto->ofproto_class->group_destruct(ofgroup);
+    ofputil_bucket_list_destroy(&ofgroup->buckets);
+    ovs_rwlock_unlock(&ofgroup->rwlock);
+    ovs_rwlock_destroy(&ofgroup->rwlock);
+    ofproto->ofproto_class->group_dealloc(ofgroup);
+}
+
+/* Implements OFPGC_DELETE. */
+static void
+delete_group(struct ofproto *ofproto, uint32_t group_id)
+{
+    struct ofgroup *ofgroup;
+
+    ovs_rwlock_wrlock(&ofproto->groups_rwlock);
+    if (group_id == OFPG_ALL) {
+        for (;;) {
+            struct hmap_node *node = hmap_first(&ofproto->groups);
+            if (!node) {
+                break;
+            }
+            ofgroup = CONTAINER_OF(node, struct ofgroup, hmap_node);
+            delete_group__(ofproto, ofgroup);
+            /* Lock for each node separately, so that we will not jam the
+             * other threads for too long time. */
+            ovs_rwlock_wrlock(&ofproto->groups_rwlock);
+        }
+    } else {
+        HMAP_FOR_EACH_IN_BUCKET (ofgroup, hmap_node,
+                                 hash_int(group_id, 0), &ofproto->groups) {
+            if (ofgroup->group_id == group_id) {
+                delete_group__(ofproto, ofgroup);
+                return;
+            }
+        }
+    }
+    ovs_rwlock_unlock(&ofproto->groups_rwlock);
+}
+
+static enum ofperr
+handle_group_mod(struct ofconn *ofconn, const struct ofp_header *oh)
+{
+    struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
+    struct ofputil_group_mod gm;
+    enum ofperr error;
+
+    error = reject_slave_controller(ofconn);
+    if (error) {
+        return error;
+    }
+
+    error = ofputil_decode_group_mod(oh, &gm);
+    if (error) {
+        return error;
+    }
+
+    switch (gm.command) {
+    case OFPGC11_ADD:
+        return add_group(ofproto, &gm);
+
+    case OFPGC11_MODIFY:
+        return modify_group(ofproto, &gm);
+
+    case OFPGC11_DELETE:
+        delete_group(ofproto, gm.group_id);
+        return 0;
+
+    default:
+        if (gm.command > OFPGC11_DELETE) {
+            VLOG_WARN_RL(&rl, "%s: Invalid group_mod command type %d",
+                         ofproto->name, gm.command);
+        }
+        return OFPERR_OFPGMFC_BAD_COMMAND;
+    }
+}
+
 static enum ofperr
 handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg)
 {
@@ -4710,6 +5154,9 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg)
     case OFPTYPE_FLOW_MOD:
         return handle_flow_mod(ofconn, oh);
 
+    case OFPTYPE_GROUP_MOD:
+        return handle_group_mod(ofconn, oh);
+
     case OFPTYPE_METER_MOD:
         return handle_meter_mod(ofconn, oh);
 
@@ -4778,12 +5225,18 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg)
     case OFPTYPE_METER_FEATURES_STATS_REQUEST:
         return handle_meter_features_request(ofconn, oh);
 
-        /* FIXME: Change the following once they are implemented: */
-    case OFPTYPE_QUEUE_GET_CONFIG_REQUEST:
-    case OFPTYPE_GET_ASYNC_REQUEST:
     case OFPTYPE_GROUP_STATS_REQUEST:
+        return handle_group_stats_request(ofconn, oh);
+
     case OFPTYPE_GROUP_DESC_STATS_REQUEST:
+        return handle_group_desc_stats_request(ofconn, oh);
+
     case OFPTYPE_GROUP_FEATURES_STATS_REQUEST:
+        return handle_group_features_stats_request(ofconn, oh);
+
+        /* FIXME: Change the following once they are implemented: */
+    case OFPTYPE_QUEUE_GET_CONFIG_REQUEST:
+    case OFPTYPE_GET_ASYNC_REQUEST:
     case OFPTYPE_TABLE_FEATURES_STATS_REQUEST:
         return OFPERR_OFPBRC_BAD_TYPE;
 
@@ -5003,7 +5456,7 @@ ofopgroup_complete(struct ofopgroup *group)
                     }
                 }
             } else {
-                ovs_rwlock_wrlock(&rule->evict);
+                ovs_rwlock_wrlock(&rule->rwlock);
                 oftable_remove_rule(rule);
                 ofproto_rule_destroy__(rule);
             }
@@ -5032,8 +5485,12 @@ ofopgroup_complete(struct ofopgroup *group)
                 ovs_mutex_unlock(&rule->timeout_mutex);
                 if (op->ofpacts) {
                     free(rule->ofpacts);
+
+                    ovs_rwlock_wrlock(&rule->rwlock);
                     rule->ofpacts = op->ofpacts;
                     rule->ofpacts_len = op->ofpacts_len;
+                    ovs_rwlock_unlock(&rule->rwlock);
+
                     op->ofpacts = NULL;
                     op->ofpacts_len = 0;
                 }
@@ -5221,7 +5678,7 @@ choose_rule_to_evict(struct oftable *table, struct rule **rulep)
         struct rule *rule;
 
         HEAP_FOR_EACH (rule, evg_node, &evg->rules) {
-            if (!ovs_rwlock_trywrlock(&rule->evict)) {
+            if (!ovs_rwlock_trywrlock(&rule->rwlock)) {
                 *rulep = rule;
                 return true;
             }
@@ -5262,7 +5719,7 @@ ofproto_evict(struct ofproto *ofproto)
             }
 
             if (rule->pending) {
-                ovs_rwlock_unlock(&rule->evict);
+                ovs_rwlock_unlock(&rule->rwlock);
                 break;
             }
 
@@ -5570,12 +6027,9 @@ oftable_enable_eviction(struct oftable *table,
 static void
 oftable_remove_rule__(struct ofproto *ofproto, struct classifier *cls,
                       struct rule *rule)
-    OVS_REQ_WRLOCK(cls->rwlock) OVS_RELEASES(rule->evict)
+    OVS_REQ_WRLOCK(cls->rwlock) OVS_RELEASES(rule->rwlock)
 {
     classifier_remove(cls, &rule->cr);
-    if (rule->meter_id) {
-        list_remove(&rule->meter_list_node);
-    }
     cookies_remove(ofproto, rule);
     eviction_group_remove_rule(rule);
     ovs_mutex_lock(&ofproto->expirable_mutex);
@@ -5585,8 +6039,9 @@ oftable_remove_rule__(struct ofproto *ofproto, struct classifier *cls,
     ovs_mutex_unlock(&ofproto->expirable_mutex);
     if (!list_is_empty(&rule->meter_list_node)) {
         list_remove(&rule->meter_list_node);
+        list_init(&rule->meter_list_node);
     }
-    ovs_rwlock_unlock(&rule->evict);
+    ovs_rwlock_unlock(&rule->rwlock);
 }
 
 static void
index 7bc8520..2911e71 100644 (file)
@@ -12,9 +12,6 @@ EXTRA_DIST += \
        rhel/etc_logrotate.d_openvswitch \
        rhel/etc_sysconfig_network-scripts_ifdown-ovs \
        rhel/etc_sysconfig_network-scripts_ifup-ovs \
-       rhel/kmodtool-openvswitch-el5.sh \
-       rhel/openvswitch-kmod-rhel5.spec \
-       rhel/openvswitch-kmod-rhel5.spec.in \
        rhel/openvswitch-kmod-rhel6.spec \
        rhel/openvswitch-kmod-rhel6.spec.in \
        rhel/openvswitch-kmod.files \
@@ -32,9 +29,6 @@ update_rhel_spec = \
     < $(srcdir)/rhel/$(@F).in > $(@F).tmp || exit 1; \
   if cmp -s $(@F).tmp $@; then touch $@; rm $(@F).tmp; else mv $(@F).tmp $@; fi
 
-$(srcdir)/rhel/openvswitch-kmod-rhel5.spec: rhel/openvswitch-kmod-rhel5.spec.in $(top_builddir)/config.status
-       $(update_rhel_spec)
-
 $(srcdir)/rhel/openvswitch-kmod-rhel6.spec: rhel/openvswitch-kmod-rhel6.spec.in $(top_builddir)/config.status
        $(update_rhel_spec)
 
diff --git a/rhel/kmodtool-openvswitch-el5.sh b/rhel/kmodtool-openvswitch-el5.sh
deleted file mode 100755 (executable)
index ce1d54a..0000000
+++ /dev/null
@@ -1,273 +0,0 @@
-#!/bin/bash
-
-# kmodtool - Helper script for building kernel module RPMs
-# Copyright (c) 2003-2008 Ville Skyttä <ville.skytta@iki.fi>,
-#                         Thorsten Leemhuis <fedora@leemhuis.info>
-#                         Jon Masters <jcm@redhat.com>
-#
-# Permission is hereby granted, free of charge, to any person obtaining
-# a copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the Software, and to
-# permit persons to whom the Software is furnished to do so, subject to
-# the following conditions:
-#
-# The above copyright notice and this permission notice shall be
-# included in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-shopt -s extglob
-
-myprog="kmodtool"
-myver="0.10.10_kmp3"
-knownvariants=@(BOOT|PAE|@(big|huge)mem|debug|enterprise|kdump|?(large)smp|uml|xen[0U]?(-PAE)|xen)
-kmod_name=
-kver=
-verrel=
-variant=
-kmp=
-
-get_verrel ()
-{
-  verrel=${1:-$(uname -r)}
-  verrel=${verrel%%$knownvariants}
-}
-
-print_verrel ()
-{
-  get_verrel $@
-  echo "${verrel}"
-}
-
-get_variant ()
-{
-  get_verrel $@
-  variant=${1:-$(uname -r)}
-  variant=${variant##$verrel}
-  variant=${variant:-'""'}
-}
-
-print_variant ()
-{
-  get_variant $@
-  echo "${variant}"
-}
-
-get_rpmtemplate ()
-{
-    local variant="${1}"
-    local dashvariant="${variant:+-${variant}}"
-    case "$verrel" in
-        *.el*) kdep="kernel${dashvariant}-%{_target_cpu} = ${verrel}" ;;
-        *.EL*) kdep="kernel${dashvariant}-%{_target_cpu} = ${verrel}" ;;
-        *)     kdep="kernel-%{_target_cpu} = ${verrel}${variant}"     ;;
-    esac
-
-    echo "%package       -n kmod-${kmod_name}${dashvariant}"
-
-    if [ -z "$kmp_provides_summary" ]; then
-        echo "Summary:          ${kmod_name} kernel module(s)"
-    fi
-
-    if [ -z "$kmp_provides_group" ]; then
-        echo "Group:            System Environment/Kernel"
-    fi
-
-    if [ ! -z "$kmp_version" ]; then
-        echo "Version: %{kmp_version}"
-    fi
-
-    if [ ! -z "$kmp_release" ]; then
-        echo "Release: %{kmp_release}"
-    fi
-    
-    if [ ! -z "$kmp" ]; then
-        echo "%global _use_internal_dependency_generator 0"
-    fi
-    
-    cat <<EOF
-Provides:         kernel-modules = ${verrel}${variant}
-Provides:         ${kmod_name}-kmod = %{?epoch:%{epoch}:}%{version}-%{release}
-EOF
-    
-    if [ -z "$kmp" ]; then
-        echo "Requires:         ${kdep}"
-    fi
-
-#
-# RHEL5 - Remove common package requirement on general kmod packages.
-# Requires: ${kmod_name}-kmod-common >= %{?epoch:%{epoch}:}%{version}
-#
-
-    cat <<EOF
-Requires(post):   /sbin/depmod
-Requires(postun): /sbin/depmod
-EOF
-
-if [ "no" != "$kmp_nobuildreqs" ]
-then
-    echo "BuildRequires: kernel${dashvariant}-devel-%{_target_cpu} = ${verrel}"
-fi
-
-if [ "" != "$kmp_override_preamble" ]
-then
-    cat "$kmp_override_preamble"
-fi
-
-cat <<EOF
-%description   -n kmod-${kmod_name}${dashvariant}
-This package provides the ${kmod_name} kernel modules built for the Linux
-kernel ${verrel}${variant} for the %{_target_cpu} family of processors.
-%post          -n kmod-${kmod_name}${dashvariant}
-if [ -e "/boot/System.map-${verrel}${variant}" ]; then
-    /sbin/depmod -aeF "/boot/System.map-${verrel}${variant}" "${verrel}${variant}" > /dev/null || :
-fi
-EOF
-    
-    if [ ! -z "$kmp" ]; then
-        cat <<EOF
-
-#modules=( \$(rpm -ql kmod-${kmod_name}${dashvariant} | grep '\.ko$') )
-modules=( \$(find /lib/modules/${verrel}${variant}/extra/${kmod_name} \
-          | grep '\.ko$') )
-if [ -x "/sbin/weak-modules" ]; then
-    printf '%s\n' "\${modules[@]}" \
-    | /sbin/weak-modules --add-modules
-fi
-%preun         -n kmod-${kmod_name}${dashvariant}
-rpm -ql kmod-${kmod_name}${dashvariant} | grep '\.ko$' \
-    > /var/run/rpm-kmod-${kmod_name}${dashvariant}-modules
-EOF
-        
-    fi
-    
-    cat <<EOF
-%postun        -n kmod-${kmod_name}${dashvariant}
-/sbin/depmod -aF /boot/System.map-${verrel}${variant} ${verrel}${variant} &> /dev/null || :
-EOF
-    
-    if [ ! -z "$kmp" ]; then
-        cat <<EOF
-modules=( \$(cat /var/run/rpm-kmod-${kmod_name}${dashvariant}-modules) )
-#rm /var/run/rpm-kmod-${kmod_name}${dashvariant}-modules
-if [ -x "/sbin/weak-modules" ]; then
-    printf '%s\n' "\${modules[@]}" \
-    | /sbin/weak-modules --remove-modules
-fi
-EOF
-    fi
-
-echo "%files         -n kmod-${kmod_name}${dashvariant}"
-
-if [ "" == "$kmp_override_filelist" ];
-then
-    echo "%defattr(644,root,root,755)"
-    echo "/lib/modules/${verrel}${variant}/"
-    echo "%config /etc/depmod.d/kmod-${kmod_name}.conf"
-    #BZ252188 - I've commented this out for the moment since RHEL5 doesn't
-    #           really support external firmware e.g. at install time. If
-    #           you really want it, use an override filelist solution.
-    #echo "/lib/firmware/"
-else
-    cat "$kmp_override_filelist"
-fi
-}
-
-print_rpmtemplate ()
-{
-  kmod_name="${1}"
-  shift
-  kver="${1}"
-  get_verrel "${1}"
-  shift
-  if [ -z "${kmod_name}" ] ; then
-    echo "Please provide the kmodule-name as first parameter." >&2
-    exit 2
-  elif [ -z "${kver}" ] ; then
-    echo "Please provide the kver as second parameter." >&2
-    exit 2
-  elif [ -z "${verrel}" ] ; then
-    echo "Couldn't find out the verrel." >&2
-    exit 2
-  fi
-  
-  for variant in "$@" ; do
-      if [ "default" == "$variant" ];
-      then
-            get_rpmtemplate ""
-      else
-            get_rpmtemplate "${variant}"
-      fi
-  done
-}
-
-usage ()
-{
-  cat <<EOF
-You called: ${invocation}
-
-Usage: ${myprog} <command> <option>+
- Commands:
-  verrel <uname>                               
-    - Get "base" version-release.
-  variant <uname>                               
-    - Get variant from uname.
-  rpmtemplate <mainpgkname> <uname> <variants> 
-    - Return a template for use in a source RPM
-  rpmtemplate_kmp <mainpgkname> <uname> <variants>
-    - Return a template for use in a source RPM with KMP dependencies
-  version  
-    - Output version number and exit.
-EOF
-}
-
-invocation="$(basename ${0}) $@"
-while [ "${1}" ] ; do
-  case "${1}" in
-    verrel)
-      shift
-      print_verrel $@
-      exit $?
-      ;;
-    variant)
-      shift
-      print_variant $@
-      exit $?
-      ;;
-    rpmtemplate)
-      shift
-      print_rpmtemplate "$@"
-      exit $?
-      ;;
-    rpmtemplate_kmp)
-      shift
-      kmp=1
-      print_rpmtemplate "$@"
-      exit $?
-      ;;
-    version)
-      echo "${myprog} ${myver}"
-      exit 0
-      ;;
-    *)
-      echo "Error: Unknown option '${1}'." >&2
-      usage >&2
-      exit 2
-      ;;
-  esac
-done
-
-# Local variables:
-# mode: sh
-# sh-indentation: 2
-# indent-tabs-mode: nil
-# End:
-# ex: ts=2 sw=2 et
diff --git a/rhel/openvswitch-kmod-rhel5.spec.in b/rhel/openvswitch-kmod-rhel5.spec.in
deleted file mode 100644 (file)
index ae73ea6..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-# Spec file for Open vSwitch kernel modules on Red Hat Enterprise
-# Linux 5.
-
-# Copyright (C) 2009, 2010, 2011, 2012 Nicira, Inc.
-#
-# Copying and distribution of this file, with or without modification,
-# are permitted in any medium without royalty provided the copyright
-# notice and this notice are preserved.  This file is offered as-is,
-# without warranty of any kind.
-
-%define kmod_name openvswitch
-%{!?kversion: %define kversion 2.6.18-238.12.1.el5}
-
-Name:    %{kmod_name}-kmod
-Version: @VERSION@
-Release: 1%{?dist}
-Group:   System Environment/Kernel
-License: GPLv2
-Summary: Open vSwitch kernel modules
-URL:     http://openvswitch.org/
-
-BuildRequires: redhat-rpm-config
-BuildRoot:     %{_tmppath}/%{name}-%{version}-%{release}-build-%(%{__id_u} -n)
-ExclusiveArch: i686 x86_64
-
-# Sources.
-Source0:  %{kmod_name}-%{version}.tar.gz
-Source10: kmodtool-%{kmod_name}-el5.sh
-
-# Define the variants for each architecture.
-%define basevar ""
-%ifarch i686
-%define paevar PAE
-%endif
-%ifarch i686 x86_64
-%define xenvar xen
-%endif
-
-# If kvariants isn't defined on the rpmbuild line, build all variants for this architecture.
-%{!?kvariants: %define kvariants %{?basevar} %{?xenvar} %{?paevar}}
-
-# Magic hidden here.
-%{expand:%(sh %{SOURCE10} rpmtemplate_kmp %{kmod_name} %{kversion} %{kvariants})}
-
-# Disable the building of the debug package(s).
-%define debug_package %{nil}
-
-# Define the filter.
-%define __find_requires sh %{_builddir}/%{buildsubdir}/filter-requires.sh
-
-%description
-Open vSwitch Linux kernel module.
-
-%prep
-%setup -q -c -T -a 0
-for kvariant in %{kvariants} ; do
-    %{__cp} -a %{kmod_name}-%{version} _kmod_build_$kvariant
-done
-echo "/usr/lib/rpm/redhat/find-requires | %{__sed} -e '/^ksym.*/d'" > filter-requires.sh
-echo "override %{kmod_name} * weak-updates/%{kmod_name}" > kmod-%{kmod_name}.conf
-
-%build
-for kvariant in %{kvariants} ; do
-    KSRC=%{_usrsrc}/kernels/%{kversion}${kvariant:+-$kvariant}-%{_target_cpu}
-    cd _kmod_build_$kvariant
-    ../openvswitch-%{version}/configure --with-linux="$KSRC"
-    %{__make} -C datapath/linux %{?_smp_mflags}
-    cd ..
-done
-
-%install
-%{__rm} -rf %{buildroot}
-export INSTALL_MOD_PATH=%{buildroot}
-export INSTALL_MOD_DIR=extra/%{kmod_name}
-for kvariant in %{kvariants} ; do
-    KSRC=%{_usrsrc}/kernels/%{kversion}${kvariant:+-$kvariant}-%{_target_cpu}
-    %{__make} -C "${KSRC}" modules_install M="`pwd`"/_kmod_build_$kvariant/datapath/linux
-done
-%{__install} -d %{buildroot}%{_sysconfdir}/depmod.d/
-%{__install} kmod-%{kmod_name}.conf %{buildroot}%{_sysconfdir}/depmod.d/
-# Set the module(s) to be executable, so that they will be stripped when packaged.
-find %{buildroot} -type f -name \*.ko -exec %{__chmod} u+x \{\} \;
-
-%clean
-%{__rm} -rf %{buildroot}
index f531bf9..60d3640 100644 (file)
@@ -32,7 +32,6 @@ TESTSUITE_AT = \
        tests/json.at \
        tests/jsonrpc.at \
        tests/jsonrpc-py.at \
-       tests/timeval.at \
        tests/tunnel.at \
        tests/lockfile.at \
        tests/reconnect.at \
@@ -122,7 +121,6 @@ valgrind_wrappers = \
        tests/valgrind/test-reconnect \
        tests/valgrind/test-sha1 \
        tests/valgrind/test-stp \
-       tests/valgrind/test-timeval \
        tests/valgrind/test-type-props \
        tests/valgrind/test-unix-socket \
        tests/valgrind/test-uuid \
@@ -293,10 +291,6 @@ noinst_PROGRAMS += tests/test-sha1
 tests_test_sha1_SOURCES = tests/test-sha1.c
 tests_test_sha1_LDADD = lib/libopenvswitch.a $(SSL_LIBS)
 
-noinst_PROGRAMS += tests/test-timeval
-tests_test_timeval_SOURCES = tests/test-timeval.c
-tests_test_timeval_LDADD = lib/libopenvswitch.a $(SSL_LIBS)
-
 noinst_PROGRAMS += tests/test-strtok_r
 tests_test_strtok_r_SOURCES = tests/test-strtok_r.c
 
index 62fc9eb..f99cc3a 100644 (file)
@@ -285,6 +285,7 @@ AT_SETUP([learning action - self-modifying flow])
 OVS_VSWITCHD_START
 ADD_OF_PORTS([br0], 1, 2, 3)
 
+ovs-appctl time/stop
 # Set up flow table for TCPv4 port learning.
 AT_CHECK([[ovs-ofctl add-flow br0 'actions=load:3->NXM_NX_REG0[0..15],learn(table=0,priority=65535,NXM_OF_ETH_SRC[],NXM_OF_VLAN_TCI[0..11],output:NXM_NX_REG0[0..15]),output:2']])
 
index f554aba..4a62793 100644 (file)
@@ -1585,13 +1585,6 @@ OFPST_QUEUE reply (xid=0x1): 6 queues
 ])
 AT_CLEANUP
 
-AT_SETUP([OFPST_PORT_DESC request - OF1.0])
-AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
-AT_CHECK([ovs-ofctl ofp-print "0110000c00000001000d0000"], [0], [dnl
-OFPST_PORT_DESC request (xid=0x1):
-])
-AT_CLEANUP
-
 AT_SETUP([OFPST_QUEUE reply - OF1.1])
 AT_KEYWORDS([ofp-print OFPT_STATS_REPLY])
 AT_CHECK([ovs-ofctl ofp-print "\
@@ -1679,6 +1672,120 @@ OFPST_QUEUE reply (OF1.3) (xid=0x1): 6 queues
 ])
 AT_CLEANUP
 
+AT_SETUP([OFPST_GROUP request])
+AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
+AT_CHECK([ovs-ofctl ofp-print "\
+02 12 00 18 00 00 00 02 00 06 00 00 00 00 00 00 \
+ff ff ff ff 00 00 00 00 \
+"], [0], [OFPST_GROUP request (OF1.1) (xid=0x2): group_id=ANY
+])
+AT_CLEANUP
+
+AT_SETUP([OFPST_GROUP reply - OF1.1])
+AT_KEYWORDS([ofp-print OFPT_STATS_REPLY])
+AT_CHECK([ovs-ofctl ofp-print "\
+02 13 00 a0 00 00 00 02 00 06 00 00 00 00 00 00 \
+00 50 00 00 87 65 43 21 00 00 00 04 00 00 00 00 \
+00 00 00 00 00 00 88 88 00 00 00 00 00 77 77 77 \
+00 00 00 00 00 00 11 11 00 00 00 00 00 22 22 22 \
+00 00 00 00 00 00 11 11 00 00 00 00 00 22 22 22 \
+00 00 00 00 00 00 66 66 00 00 00 00 00 33 33 33 \
+00 40 00 00 00 00 00 05 00 00 00 02 00 00 00 00 \
+00 00 00 00 00 00 88 88 00 00 00 00 00 77 77 77 \
+00 00 00 00 00 00 11 11 00 00 00 00 00 22 22 22 \
+00 00 00 00 00 00 11 11 00 00 00 00 00 22 22 22 \
+"], [0], [dnl
+OFPST_GROUP reply (OF1.1) (xid=0x2):
+ group_id=2271560481,ref_count=4,packet_count=34952,byte_count=7829367,bucket0:packet_count=4369,byte_count=2236962,bucket1:packet_count=4369,byte_count=2236962,bucket2:packet_count=26214,byte_count=3355443
+ group_id=5,ref_count=2,packet_count=34952,byte_count=7829367,bucket0:packet_count=4369,byte_count=2236962,bucket1:packet_count=4369,byte_count=2236962
+])
+AT_CLEANUP
+
+AT_SETUP([OFPST_GROUP reply - OF1.3])
+AT_KEYWORDS([ofp-print OFPT_STATS_REPLY])
+AT_CHECK([ovs-ofctl ofp-print "\
+04 13 00 b0 00 00 00 02 00 06 00 00 00 00 00 00 \
+00 58 00 00 87 65 43 21 00 00 00 04 00 00 00 00 \
+00 00 00 00 00 00 88 88 00 00 00 00 00 77 77 77 \
+00 00 00 12 1d cd 65 00 \
+00 00 00 00 00 00 11 11 00 00 00 00 00 22 22 22 \
+00 00 00 00 00 00 11 11 00 00 00 00 00 22 22 22 \
+00 00 00 00 00 00 66 66 00 00 00 00 00 33 33 33 \
+00 48 00 00 00 00 00 05 00 00 00 02 00 00 00 00 \
+00 00 00 00 00 00 88 88 00 00 00 00 00 77 77 77 \
+00 00 00 10 1d cd 65 00 \
+00 00 00 00 00 00 11 11 00 00 00 00 00 22 22 22 \
+00 00 00 00 00 00 11 11 00 00 00 00 00 22 22 22 \
+"], [0], [dnl
+OFPST_GROUP reply (OF1.3) (xid=0x2):
+ group_id=2271560481,duration=18.5s,ref_count=4,packet_count=34952,byte_count=7829367,bucket0:packet_count=4369,byte_count=2236962,bucket1:packet_count=4369,byte_count=2236962,bucket2:packet_count=26214,byte_count=3355443
+ group_id=5,duration=16.5s,ref_count=2,packet_count=34952,byte_count=7829367,bucket0:packet_count=4369,byte_count=2236962,bucket1:packet_count=4369,byte_count=2236962
+])
+AT_CLEANUP
+
+AT_SETUP([OFPST_GROUP_DESC request])
+AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
+AT_CHECK([ovs-ofctl ofp-print "\
+02 12 00 10 00 00 00 02 00 07 00 00 00 00 00 00 \
+"], [0], [OFPST_GROUP_DESC request (OF1.1) (xid=0x2):
+])
+AT_CLEANUP
+
+AT_SETUP([OFPST_GROUP_DESC reply])
+AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
+AT_CHECK([ovs-ofctl ofp-print "\
+02 13 00 78 00 00 00 02 00 07 00 00 00 00 00 00 \
+00 68 01 00 00 00 20 00 \
+00 20 00 64 00 00 00 01 ff ff ff ff 00 00 00 00 \
+00 00 00 10 00 00 00 01 00 00 00 00 00 00 00 00 \
+00 20 00 c8 00 00 00 02 ff ff ff ff 00 00 00 00 \
+00 00 00 10 00 00 00 02 00 00 00 00 00 00 00 00 \
+00 20 00 c8 00 00 00 03 ff ff ff ff 00 00 00 00 \
+00 00 00 10 00 00 00 03 00 00 00 00 00 00 00 00 \
+"], [0], [dnl
+OFPST_GROUP_DESC reply (OF1.1) (xid=0x2):
+ group_id=8192,type=select,bucket=weight:100,watch_port:1,actions=output:1,bucket=weight:200,watch_port:2,actions=output:2,bucket=weight:200,watch_port:3,actions=output:3
+])
+AT_CLEANUP
+
+AT_SETUP([OFPST_GROUP_FEATURES request])
+AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
+AT_CHECK([ovs-ofctl ofp-print "\
+03 12 00 10 00 00 00 02 00 08 00 00 00 00 00 00 \
+"], [0], [OFPST_GROUP_FEATURES request (OF1.2) (xid=0x2):
+])
+AT_CLEANUP
+
+AT_SETUP([OFPST_GROUP_FEATURES reply])
+AT_KEYWORDS([ofp-print OFPT_STATS_REPLY])
+AT_CHECK([ovs-ofctl ofp-print "\
+03 13 00 38 00 00 00 02 00 08 00 00 00 00 00 00 \
+00 00 00 0f 00 00 00 0f \
+00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 04 \
+00 00 00 01 00 00 00 03 00 00 00 07 00 00 00 0f \
+"], [0], [dnl
+OFPST_GROUP_FEATURES reply (OF1.2) (xid=0x2):
+ Group table:
+    Types:  0xf
+    Capabilities:  0xf
+    All group :
+        max_groups = 0x1 actions=0x00000001
+    Select group :
+        max_groups = 0x2 actions=0x00000003
+    Indirect group :
+        max_groups = 0x3 actions=0x00000007
+    Fast Failover group :
+        max_groups = 0x4 actions=0x0000000f
+])
+AT_CLEANUP
+
+AT_SETUP([OFPST_PORT_DESC request - OF1.0])
+AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
+AT_CHECK([ovs-ofctl ofp-print "0110000c00000001000d0000"], [0], [dnl
+OFPST_PORT_DESC request (xid=0x1):
+])
+AT_CLEANUP
+
 AT_SETUP([OFPST_PORT_DESC reply - OF1.0])
 AT_KEYWORDS([ofp-print OFPT_STATS_REPLY])
 AT_CHECK([ovs-ofctl ofp-print "\
@@ -2068,6 +2175,22 @@ NXT_FLOW_MOD (xid=0x2): ADD NXM_NX_TUN_ID(00000000000001c8), NXM_NX_REG0(0000007
 ])
 AT_CLEANUP
 
+AT_SETUP([OFPT_GROUP_MOD])
+AT_KEYWORDS([ofp-print])
+AT_CHECK([ovs-ofctl ofp-print "\
+02 0f 00 70 11 22 33 44 00 00 01 00 87 65 43 21 \
+00 20 00 64 00 00 00 01 ff ff ff ff 00 00 00 00 \
+00 00 00 10 00 00 00 01 00 00 00 00 00 00 00 00 \
+00 20 00 c8 00 00 00 02 ff ff ff ff 00 00 00 00 \
+00 00 00 10 00 00 00 02 00 00 00 00 00 00 00 00 \
+00 20 00 c8 00 00 00 03 ff ff ff ff 00 00 00 00 \
+00 00 00 10 00 00 00 03 00 00 00 00 00 00 00 00 \
+"], [0], [dnl
+OFPT_GROUP_MOD (OF1.1) (xid=0x11223344):
+ ADD group_id=2271560481,type=select,bucket=weight:100,watch_port:1,actions=output:1,bucket=weight:200,watch_port:2,actions=output:2,bucket=weight:200,watch_port:3,actions=output:3
+])
+AT_CLEANUP
+
 AT_SETUP([NXT_FLOW_REMOVED])
 AT_KEYWORDS([ofp-print])
 AT_CHECK([ovs-ofctl ofp-print "\
index 7f01a2d..f67c3ab 100644 (file)
@@ -645,6 +645,7 @@ NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=64 in_port=1 tun_id=0x6
 udp,metadata=0,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=85,tp_dst=86 udp_csum:43a1
 ])
 
+ovs-appctl time/stop
 AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
 
 dnl Checksum SCTP.
@@ -1841,6 +1842,7 @@ AT_SETUP([ofproto-dpif - NetFlow flow expiration])
 OVS_VSWITCHD_START([set Bridge br0 fail-mode=standalone])
 ADD_OF_PORTS([br0], 1, 2)
 
+ovs-appctl time/stop
 ON_EXIT([kill `cat test-netflow.pid`])
 AT_CHECK([test-netflow --log-file --detach --no-chdir --pidfile 0:127.0.0.1 > netflow.log], [0], [], [ignore])
 AT_CAPTURE_FILE([netflow.log])
@@ -1996,6 +1998,7 @@ get_ages () {
 AT_CHECK([ovs-ofctl add-flow br0 hard_timeout=199,idle_timeout=188,actions=drop])
 get_ages duration1 hard1 idle1
 
+ovs-appctl time/stop
 # Warp time forward by 10 seconds, then modify the flow's actions.
 ovs-appctl time/warp 10000
 get_ages duration2 hard2 idle2
@@ -2059,6 +2062,8 @@ AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip], [0],
 [NXST_FLOW reply:
  idle_timeout=60, actions=fin_timeout(idle_timeout=5)
 ])
+
+ovs-appctl time/stop
 # Check that a TCP SYN packet does not change the timeout.  (Because
 # flow stats updates are mainly what implements the fin_timeout
 # feature, we warp forward a couple of times to ensure that flow stats
@@ -2263,6 +2268,7 @@ AT_SETUP([ofproto-dpif - port duration])
 OVS_VSWITCHD_START([set Bridge br0 protocols=OpenFlow13])
 ADD_OF_PORTS([br0], 1, 2)
 
+ovs-appctl time/stop
 ovs-appctl time/warp 10000
 
 AT_CHECK([ovs-ofctl -O openflow13 dump-ports br0], [0], [stdout])
@@ -2474,6 +2480,7 @@ AT_CHECK([ovs-appctl netdev-dummy/set-admin-state up], 0, [OK
 ADD_OF_PORTS([br0], [7])
 AT_CHECK([ovs-ofctl add-flow br0 action=normal])
 AT_CHECK([ovs-ofctl add-flow br1 action=normal])
+ovs-appctl time/stop
 ovs-appctl time/warp 5000
 AT_CHECK([ovs-appctl netdev-dummy/receive p7 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
 AT_CHECK([ovs-appctl netdev-dummy/receive p7 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
@@ -2619,6 +2626,7 @@ AT_DATA([flows.txt], [dnl
 table=0 in_port=1 actions=load:2->NXM_NX_REG0[[0..15]],learn(table=1,priority=65535,NXM_OF_ETH_SRC[[]],NXM_OF_VLAN_TCI[[0..11]],output:NXM_NX_REG0[[0..15]]),output:2
 ])
 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
+ovs-appctl time/stop
 # We send each packet twice because the first packet in each flow causes the
 # flow table to change and thus revalidations, which (depending on timing)
 # can keep a megaflow from being installed.  The revalidations are done by
index fe258c2..99f6879 100644 (file)
@@ -96,7 +96,6 @@ do_fork(void)
 {
     switch (fork()) {
     case 0:
-        time_postfork();
         lockfile_postfork();
         return CHILD;
 
diff --git a/tests/test-timeval.c b/tests/test-timeval.c
deleted file mode 100644 (file)
index 9896cf7..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (c) 2009, 2010, 2011 Nicira, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <config.h>
-
-#include "timeval.h"
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "command-line.h"
-#include "daemon.h"
-#include "util.h"
-
-#undef NDEBUG
-#include <assert.h>
-
-static long long int
-gettimeofday_in_msec(void)
-{
-    struct timeval tv;
-
-    xgettimeofday(&tv);
-    return timeval_to_msec(&tv);
-}
-
-static void
-do_test(void)
-{
-    /* Wait until we are awakened by a signal (typically EINTR due to the
-     * setitimer()).  Then ensure that, if time has really advanced by
-     * TIME_UPDATE_INTERVAL, then time_msec() reports that it advanced.
-     */
-    long long int start_time_msec, start_time_wall;
-    long long int start_gtod;
-
-    start_time_msec = time_msec();
-    start_time_wall = time_wall_msec();
-    start_gtod = gettimeofday_in_msec();
-    for (;;) {
-        /* Wait up to 1 second.  Using select() to do the timeout avoids
-         * interfering with the interval timer. */
-        struct timeval timeout;
-        int retval;
-
-        timeout.tv_sec = 1;
-        timeout.tv_usec = 0;
-        retval = select(0, NULL, NULL, NULL, &timeout);
-        if (retval != -1) {
-            ovs_fatal(0, "select returned %d", retval);
-        } else if (errno != EINTR) {
-            ovs_fatal(errno, "select reported unexpected error");
-        }
-
-        if (gettimeofday_in_msec() - start_gtod >= TIME_UPDATE_INTERVAL) {
-            /* gettimeofday() and time_msec() have different granularities in
-             * their time sources.  Depending on the rounding used this could
-             * result in a slight difference, so we allow for 1 ms of slop. */
-            assert(time_msec() - start_time_msec >= TIME_UPDATE_INTERVAL - 1);
-            assert(time_wall_msec() - start_time_wall >=
-                                                      TIME_UPDATE_INTERVAL - 1);
-            break;
-        }
-    }
-}
-
-static void
-usage(void)
-{
-    ovs_fatal(0, "usage: %s TEST, where TEST is \"plain\" or \"daemon\"",
-              program_name);
-}
-
-int
-main(int argc, char *argv[])
-{
-    proctitle_init(argc, argv);
-    set_program_name(argv[0]);
-
-    if (argc != 2) {
-        usage();
-    } else if (!strcmp(argv[1], "plain")) {
-        /* If we're not caching time there isn't much to test and SIGALRM won't
-         * be around to pull us out of the select() call, so just skip out */
-        if (!CACHE_TIME) {
-            exit (77);
-        }
-
-        do_test();
-    } else if (!strcmp(argv[1], "daemon")) {
-        /* Test that time still advances even in a daemon.  This is an
-         * interesting test because fork() cancels the interval timer. */
-        char cwd[1024], *pidfile;
-        FILE *success;
-
-        if (!CACHE_TIME) {
-            exit (77);
-        }
-
-        assert(getcwd(cwd, sizeof cwd) == cwd);
-
-        unlink("test-timeval.success");
-
-        /* Daemonize, with a pidfile in the current directory. */
-        set_detach();
-        pidfile = xasprintf("%s/test-timeval.pid", cwd);
-        set_pidfile(pidfile);
-        free(pidfile);
-        set_no_chdir();
-        daemonize();
-
-        /* Run the test. */
-        do_test();
-
-        /* Report success by writing out a file, since the ultimate invoker of
-         * test-timeval can't wait on the daemonized process. */
-        success = fopen("test-timeval.success", "w");
-        if (!success) {
-            ovs_fatal(errno, "test-timeval.success: create failed");
-        }
-        fprintf(success, "success\n");
-        fclose(success);
-    } else {
-        usage();
-    }
-
-    return 0;
-}
index c9bcad9..43efc09 100644 (file)
@@ -92,7 +92,6 @@ m4_include([tests/uuid.at])
 m4_include([tests/json.at])
 m4_include([tests/jsonrpc.at])
 m4_include([tests/jsonrpc-py.at])
-m4_include([tests/timeval.at])
 m4_include([tests/tunnel.at])
 m4_include([tests/lockfile.at])
 m4_include([tests/reconnect.at])
diff --git a/tests/timeval.at b/tests/timeval.at
deleted file mode 100644 (file)
index 0d61bff..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-AT_BANNER([timeval unit tests])
-
-AT_SETUP([check that time advances])
-AT_KEYWORDS([timeval])
-AT_CHECK([test-timeval plain], [0])
-AT_CLEANUP
-
-AT_SETUP([check that time advances after daemonize()])
-AT_KEYWORDS([timeval])
-AT_CHECK([test-timeval daemon], [0])
-AT_CHECK(
-  [# First try a quick sleep, so that the test completes very quickly
-   # in the normal case.  POSIX doesn't require fractional times to
-   # work, so this might not work.
-   sleep 0.1; if test -e test-timeval.success; then echo success; exit 0; fi
-   # Then wait up to 2 seconds.
-   sleep 1; if test -e test-timeval.success; then echo success; exit 0; fi
-   sleep 1; if test -e test-timeval.success; then echo success; exit 0; fi
-   echo failure; exit 1],
-  [0], [success
-], [])
-AT_CLEANUP
index 85b2e44..4859ab9 100644 (file)
@@ -190,6 +190,29 @@ statistics are printed for all queues on \fIport\fR; if only
 \fIport\fR is omitted, then statistics are printed for \fIqueue\fR on
 every port where it exists.
 .
+.SS "OpenFlow 1.1+ Switch Management Commands"
+.
+The following commands work only with switches that support OpenFlow
+1.1 or later.  Because support for OpenFlow 1.1 and later is still
+experimental in Open vSwitch, it is necessary to explicitly enable
+these protocol versions in \fBovs\-ofctl\fR (using \fB\-O\fR) and in
+the switch itself (with the \fBprotocols\fR column in the \fBBridge\fR
+table).  For more information, see ``Q: What versions of OpenFlow does
+Open vSwitch support?'' in the Open vSwitch FAQ.
+.
+.IP "\fBdump\-groups \fIswitch"
+Prints to the console all group entries in \fIswitch\fR's tables. Each line
+of output is a group entry as described in \fBGroup Syntax\fR below.
+.
+.IP "\fBdump\-group\-features \fIswitch"
+Prints to the console the group features of the \fIswitch\fR.
+.
+.IP "\fBdump\-group-stats \fIswitch \fR[\fIgroups\fR]"
+Prints to the console statistics for the specified \fIgroups in the
+\fIswitch\fR's tables.  If \fIgroups\fR is omitted then statistics for all
+groups are printed.  See \fBGroup Syntax\fR, below, for the syntax of
+\fIgroups\fR.
+.
 .SS "OpenFlow Switch Flow Table Commands"
 .
 These commands manage the flow table in an OpenFlow switch.  In each
@@ -258,6 +281,30 @@ keyword \fBLOCAL\fR (the preferred way to refer to the OpenFlow
 ``local'' port), or the keyword \fBNONE\fR to indicate that the packet
 was generated by the switch itself.
 .
+.SS "OpenFlow Switch Group Table Commands"
+.
+These commands manage the group table in an OpenFlow switch.  In each
+case, \fIgroup\fR specifies a group entry in the format described in
+\fBGroup Syntax\fR, below, and \fIfile\fR is a text file that contains
+zero or more groups in the same syntax, one per line.
+
+.IP "\fBadd\-group \fIswitch group\fR"
+.IQ "\fBadd\-group \fIswitch \fB\- < \fIfile\fR"
+.IQ "\fBadd\-groups \fIswitch file\fR"
+Add each group entry to \fIswitch\fR's tables.
+.
+.IP "\fBmod\-group \fIswitch group\fR"
+.IQ "\fBmod\-group \fIswitch \fB\- < \fIfile\fR"
+Modify the action buckets in entries from \fIswitch\fR's tables for
+each group entry.
+.
+.IP "\fBdel\-groups \fIswitch\fR"
+.IQ "\fBdel\-groups \fIswitch \fR[\fIgroup\fR]"
+.IQ "\fBdel\-groups \fIswitch \fB\- < \fIfile\fR"
+Deletes entries from \fIswitch\fR's group table.  With only a
+\fIswitch\fR argument, deletes all groups.  Otherwise, deletes the group
+for each group entry.
+.
 .SS "OpenFlow Switch Monitoring Commands"
 .
 .IP "\fBsnoop \fIswitch\fR"
@@ -1232,6 +1279,7 @@ For best performance, segregate learned flows into a table (using
 possibly for a lowest-priority ``catch-all'' flow, that is, a flow
 with no match criteria.  (This is why the default \fBtable\fR is 1, to
 keep the learned flows separate from the primary flow table 0.)
+.RE
 .
 .RS
 .IP \fBapply_actions(\fR[\fIaction\fR][\fB,\fIaction\fR...]\fB)
@@ -1251,7 +1299,6 @@ a \fB0x\fR prefix to specify them in hexadecimal.
 .
 .IP \fBgoto_table\fR:\fItable\fR
 Indicates the next table in the process pipeline.
-.RE
 .
 .IP "\fBfin_timeout(\fIargument\fR[\fB,\fIargument\fR]\fB)"
 This action changes the idle timeout or hard timeout, or both, of this
@@ -1439,6 +1486,75 @@ of \fBduration\fR.  (This is separate from \fBduration\fR because
 The integer number of seconds that have passed without any packets
 passing through the flow.
 .
+.SS "Group Syntax"
+.PP
+Some \fBovs\-ofctl\fR commands accept an argument that describes a group or
+groups.  Such flow descriptions comprise a series
+\fIfield\fB=\fIvalue\fR assignments, separated by commas or white
+space.  (Embedding spaces into a group description normally requires
+quoting to prevent the shell from breaking the description into
+multiple arguments.). Unless noted otherwise only the last instance
+of each field is honoured.
+.PP
+.IP \fBgroup_id=\fIid\fR
+The integer group id of group.
+When this field is specified in \fBdel-groups\fR or \fBdump-groups\fR,
+the keyword "all" may be used to designate all groups.
+.
+This field is required.
+
+
+.IP \fBtype=\fItype\fR
+The type of the group.  This \fBadd-group\fR, \fBadd-groups\fR and
+\fBdel-groups\fR command require this field.  The following keywords
+designated the allowed types:
+.RS
+.IP \fBall\fR
+Execute all buckets in the group.
+.IP \fBselect\fR
+Execute one bucket in the group.
+The switch should select the bucket in such a way that should implement
+equal load sharing is achieved.  The switch may optionally select the
+bucket based on bucket weights.
+.IP \fBindirect\fR
+Executes the one bucket in the group.
+.IP \fBff\fR
+.IQ \fBfast_failover\fR
+Executes the first live bucket in the group which is associated with
+a live port or group.
+.RE
+
+.IP \fBbucket\fR=\fIbucket_parameters\fR
+The \fBadd-group\fR, \fBadd-groups\fR and \fBmod-group\fR commands
+require at least one bucket field. Bucket fields must appear after
+all other fields.
+.
+Multiple bucket fields to specify multiple buckets.
+The order in which buckets are specified corresponds to their order in
+the group. If the type of the group is "indirect" then only one group may
+be specified.
+.
+\fIbucket_parameters\fR consists of a list of \fIfield\fB=\fIvalue\fR
+assignments, separated by commas or white space followed by a
+comma-separated list of actions.
+The syntax of actions are same
+to \fBactions=\fR field described in \fBFlow Syntax\fR above.
+The fields for \fIbucket_parameters\fR are:
+.
+.RS
+.IP \fBweight=\fIvalue\fR
+The relative weight of the bucket as an integer. This may be used by the switch
+during bucket select for groups whose \fBtype\fR is \fBselect\fR.
+.IP \fBwatch_port=\fIport\fR
+Port used to determine liveness of group.
+This or the \fBwatch_group\fR field is required
+for groups whose \fBtype\fR is \fBff\fR or \fBfast_failover\fR.
+.IP \fBwatch_group=\fIgroup_id\fR
+Group identifier of group used to determine liveness of group.
+This or the \fBwatch_port\fR field is required
+for groups whose \fBtype\fR is \fBff\fR or \fBfast_failover\fR.
+.RE
+.
 .SH OPTIONS
 .TP
 \fB\-\-strict\fR
index 547d50c..9294752 100644 (file)
@@ -301,6 +301,13 @@ usage(void)
            "  monitor SWITCH [MISSLEN] [invalid_ttl] [watch:[...]]\n"
            "                              print packets received from SWITCH\n"
            "  snoop SWITCH                snoop on SWITCH and its controller\n"
+           "  add-group SWITCH GROUP      add group described by GROUP\n"
+           "  add-group SWITCH FILE       add group from FILE\n"
+           "  mod-group SWITCH GROUP      modify specific group\n"
+           "  del-groups SWITCH [GROUP]   delete matching GROUPs\n"
+           "  dump-group-features SWITCH  print group features\n"
+           "  dump-groups SWITCH          print group description\n"
+           "  dump-group-stats SWITCH [GROUP]  print group statistics\n"
            "\nFor OpenFlow switches and controllers:\n"
            "  probe TARGET                probe whether TARGET is up\n"
            "  ping TARGET [N]             latency of N-byte echos\n"
@@ -1842,6 +1849,153 @@ ofctl_benchmark(int argc OVS_UNUSED, char *argv[])
            count * message_size / (duration / 1000.0));
 }
 
+static void
+ofctl_group_mod__(const char *remote, struct ofputil_group_mod *gms,
+                 size_t n_gms)
+{
+    struct ofputil_group_mod *gm;
+    struct ofpbuf *request;
+
+    struct vconn *vconn;
+    size_t i;
+
+    open_vconn(remote, &vconn);
+
+    for (i = 0; i < n_gms; i++) {
+        gm = &gms[i];
+        request = ofputil_encode_group_mod(vconn_get_version(vconn), gm);
+        if (request) {
+            transact_noreply(vconn, request);
+        }
+    }
+
+    vconn_close(vconn);
+
+}
+
+
+static void
+ofctl_group_mod_file(int argc OVS_UNUSED, char *argv[], uint16_t command)
+{
+    struct ofputil_group_mod *gms = NULL;
+    enum ofputil_protocol usable_protocols;
+    size_t n_gms = 0;
+    char *error;
+
+    error = parse_ofp_group_mod_file(argv[2], command, &gms, &n_gms,
+                                     &usable_protocols);
+    if (error) {
+        ovs_fatal(0, "%s", error);
+    }
+    ofctl_group_mod__(argv[1], gms, n_gms);
+    free(gms);
+}
+
+static void
+ofctl_group_mod(int argc, char *argv[], uint16_t command)
+{
+    if (argc > 2 && !strcmp(argv[2], "-")) {
+        ofctl_group_mod_file(argc, argv, command);
+    } else {
+        enum ofputil_protocol usable_protocols;
+        struct ofputil_group_mod gm;
+        char *error;
+
+        error = parse_ofp_group_mod_str(&gm, command, argc > 2 ? argv[2] : "",
+                                        &usable_protocols);
+        if (error) {
+            ovs_fatal(0, "%s", error);
+        }
+        ofctl_group_mod__(argv[1], &gm, 1);
+    }
+}
+
+static void
+ofctl_add_group(int argc, char *argv[])
+{
+    ofctl_group_mod(argc, argv, OFPGC11_ADD);
+}
+
+static void
+ofctl_add_groups(int argc, char *argv[])
+{
+    ofctl_group_mod_file(argc, argv, OFPGC11_ADD);
+}
+
+static void
+ofctl_mod_group(int argc, char *argv[])
+{
+    ofctl_group_mod(argc, argv, OFPGC11_MODIFY);
+}
+
+static void
+ofctl_del_groups(int argc, char *argv[])
+{
+    ofctl_group_mod(argc, argv, OFPGC11_DELETE);
+}
+
+static void
+ofctl_dump_group_stats(int argc, char *argv[])
+{
+    enum ofputil_protocol usable_protocols;
+    struct ofputil_group_mod gm;
+    struct ofpbuf *request;
+    struct vconn *vconn;
+    uint32_t group_id;
+    char *error;
+
+    memset(&gm, 0, sizeof gm);
+
+    error = parse_ofp_group_mod_str(&gm, OFPGC11_DELETE,
+                                    argc > 2 ? argv[2] : "",
+                                    &usable_protocols);
+    if (error) {
+        ovs_fatal(0, "%s", error);
+    }
+
+    group_id = gm.group_id;
+
+    open_vconn(argv[1], &vconn);
+    request = ofputil_encode_group_stats_request(vconn_get_version(vconn),
+                                                 group_id);
+    if (request) {
+        dump_stats_transaction(vconn, request);
+    }
+
+    vconn_close(vconn);
+}
+
+static void
+ofctl_dump_group_desc(int argc OVS_UNUSED, char *argv[])
+{
+    struct ofpbuf *request;
+    struct vconn *vconn;
+
+    open_vconn(argv[1], &vconn);
+
+    request = ofputil_encode_group_desc_request(vconn_get_version(vconn));
+    if (request) {
+        dump_stats_transaction(vconn, request);
+    }
+
+    vconn_close(vconn);
+}
+
+static void
+ofctl_dump_group_features(int argc OVS_UNUSED, char *argv[])
+{
+    struct ofpbuf *request;
+    struct vconn *vconn;
+
+    open_vconn(argv[1], &vconn);
+    request = ofputil_encode_group_features_request(vconn_get_version(vconn));
+    if (request) {
+        dump_stats_transaction(vconn, request);
+    }
+
+    vconn_close(vconn);
+}
+
 static void
 ofctl_help(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 {
@@ -3004,6 +3158,14 @@ static const struct command all_commands[] = {
     { "probe", 1, 1, ofctl_probe },
     { "ping", 1, 2, ofctl_ping },
     { "benchmark", 3, 3, ofctl_benchmark },
+
+    { "add-group", 1, 2, ofctl_add_group },
+    { "add-groups", 1, 2, ofctl_add_groups },
+    { "mod-group", 1, 2, ofctl_mod_group },
+    { "del-groups", 1, 2, ofctl_del_groups },
+    { "dump-groups", 1, 1, ofctl_dump_group_desc },
+    { "dump-group-stats", 1, 2, ofctl_dump_group_stats },
+    { "dump-group-features", 1, 1, ofctl_dump_group_features },
     { "help", 0, INT_MAX, ofctl_help },
 
     /* Undocumented commands for testing. */
index f993ba1..5e54e0b 100644 (file)
@@ -548,7 +548,6 @@ bridge_reconfigure_ofp(void)
     long long int deadline;
     struct bridge *br;
 
-    time_refresh();
     deadline = time_msec() + OFP_PORT_ACTION_WINDOW;
 
     /* The kernel will reject any attempt to add a given port to a datapath if
@@ -567,7 +566,6 @@ bridge_reconfigure_ofp(void)
             list_remove(&garbage->list_node);
             free(garbage);
 
-            time_refresh();
             if (time_msec() >= deadline) {
                 return false;
             }
@@ -580,7 +578,6 @@ bridge_reconfigure_ofp(void)
 
         HMAP_FOR_EACH_SAFE (if_cfg, next, hmap_node, &br->if_cfg_todo) {
             iface_create(br, if_cfg, OFPP_NONE);
-            time_refresh();
             if (time_msec() >= deadline) {
                 return false;
             }
index e625940..9a48eb1 100644 (file)
              An Ethernet tunnel over the experimental, UDP-based VXLAN
              protocol described at
              <code>http://tools.ietf.org/html/draft-mahalingam-dutt-dcops-vxlan-03</code>.
-             VXLAN is currently supported only with the Linux kernel datapath
-             with kernel version 2.6.26 or later.
            </p>
            <p>
              Open vSwitch uses UDP destination port 4789.  The source port used for
           <dt><code>lisp</code></dt>
           <dd>
             A layer 3 tunnel over the experimental, UDP-based Locator/ID
-            Separation Protocol (RFC 6830). LISP is currently supported only
-            with the Linux kernel datapath with kernel version 2.6.26 or later.
+            Separation Protocol (RFC 6830).
           </dd>
 
           <dt><code>patch</code></dt>