Merge branch 'mainstream'
authorGiuseppe Lettieri <g.lettieri@iet.unipi.it>
Wed, 27 Feb 2013 09:01:41 +0000 (10:01 +0100)
committerGiuseppe Lettieri <g.lettieri@iet.unipi.it>
Wed, 27 Feb 2013 09:01:41 +0000 (10:01 +0100)
134 files changed:
AUTHORS
FAQ
Makefile.am
NEWS
OPENFLOW-1.1+
README
README-lisp [new file with mode: 0644]
configure.ac
datapath/CAPWAP.txt [deleted file]
datapath/Modules.mk
datapath/actions.c
datapath/datapath.c
datapath/datapath.h
datapath/flow.c
datapath/flow.h
datapath/linux/.gitignore
datapath/linux/compat/include/linux/netdevice.h
datapath/tunnel.c
datapath/tunnel.h
datapath/vport-capwap.c [deleted file]
datapath/vport-capwap.h [deleted file]
datapath/vport-gre.c
datapath/vport-lisp.c [new file with mode: 0644]
datapath/vport-vxlan.c
datapath/vport.c
datapath/vport.h
debian/changelog
debian/control
include/linux/openvswitch.h
include/openflow/nicira-ext.h
include/openflow/openflow-1.1.h
include/openvswitch/tunnel.h
lib/automake.mk
lib/autopath.c [deleted file]
lib/autopath.h [deleted file]
lib/bond.c
lib/bond.h
lib/classifier.c
lib/classifier.h
lib/dpif-linux.c
lib/dpif-netdev.c
lib/dpif.h
lib/flow.c
lib/flow.h
lib/list.h
lib/match.c
lib/match.h
lib/meta-flow.c
lib/meta-flow.h
lib/netdev-dummy.c
lib/netdev-linux.c
lib/netdev-vport.c
lib/netlink-socket.c
lib/nx-match.c
lib/odp-util.c
lib/odp-util.h
lib/ofp-actions.c
lib/ofp-actions.h
lib/ofp-msgs.c
lib/ofp-msgs.h
lib/ofp-parse.c
lib/ofp-print.c
lib/ofp-util.c
lib/ofp-util.def
lib/ofp-util.h
lib/ofpbuf.c
lib/ofpbuf.h
lib/ovsdb-idl.c
lib/packets.c
lib/packets.h
lib/poll-loop.c
lib/process.c
lib/simap.c
lib/simap.h
lib/socket-util.c
lib/stream-unix.c
lib/timeval.c
lib/unixctl.c
lib/util.c
lib/vlog.c
lib/vlog.h
lib/worker.c
ofproto/connmgr.c
ofproto/connmgr.h
ofproto/in-band.c
ofproto/ofproto-dpif.c
ofproto/ofproto.c
ofproto/ofproto.h
ofproto/tunnel.c
ovsdb/file.c
ovsdb/ovsdb-tool.c
python/ovs/db/types.py
python/ovs/stream.py
rhel/etc_logrotate.d_openvswitch
tests/automake.mk
tests/autopath.at [deleted file]
tests/jsonrpc-py.at
tests/jsonrpc.at
tests/lacp.at
tests/learn.at
tests/library.at
tests/odp.at
tests/ofp-actions.at
tests/ofp-print.at
tests/ofproto-dpif.at
tests/ofproto-macros.at
tests/ofproto.at
tests/ovs-ofctl.at
tests/ovsdb-execution.at
tests/ovsdb-idl.at
tests/ovsdb-macros.at
tests/ovsdb-monitor.at
tests/ovsdb-server.at
tests/ovsdb-tool.at
tests/test-bundle.c
tests/test-classifier.c
tests/test-multipath.c
tests/test-odp.c
tests/test-unix-socket.py [new file with mode: 0644]
tests/testsuite.at
tests/tunnel.at
tests/vconn.at
utilities/bugtool/ovs-bugtool.8.in
utilities/bugtool/ovs-bugtool.in
utilities/ovs-ctl.in
utilities/ovs-dpctl.c
utilities/ovs-ofctl.8.in
utilities/ovs-ofctl.c
utilities/ovs-pki.in
vswitchd/bridge.c
vswitchd/vswitch.ovsschema
vswitchd/vswitch.xml
xenserver/etc_logrotate.d_openvswitch
xenserver/openvswitch-xen.spec.in

diff --git a/AUTHORS b/AUTHORS
index 2e55522..4b5e6fe 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -48,6 +48,7 @@ Keith Amidon            keith@nicira.com
 Krishna Kondaka         kkondaka@vmware.com
 Kyle Mestery            kmestery@cisco.com
 Leo Alterman            lalterman@nicira.com
+Lorand Jakab            lojakab@cisco.com
 Luca Giraudo            lgiraudo@nicira.com
 Martin Casado           casado@nicira.com
 Mehak Mahajan           mmahajan@nicira.com
@@ -61,6 +62,7 @@ Pravin B Shelar         pshelar@nicira.com
 Raju Subramanian        rsubramanian@nicira.com
 Ravi Kerur              Ravi.Kerur@telekom.com
 Reid Price              reid@nicira.com
+Rich Lane               rlane@bigswitch.com
 Rob Hoes                rob.hoes@citrix.com
 Romain Lenglet          romain.lenglet@berabera.info
 Sajjad Lateef           slateef@nicira.com
@@ -111,6 +113,7 @@ Bryan Fulton            bryan@nicira.com
 Bryan Osoro             bosoro@nicira.com
 Cedric Hobbs            cedric@nicira.com
 Dave Walker             DaveWalker@ubuntu.com
+David Palma             palma@onesource.pt
 Derek Cormier           derek.cormier@lab.ntt.co.jp
 Duffie Cooley           dcooley@nicira.com
 DK Moon                 dkmoon@nicira.com
diff --git a/FAQ b/FAQ
index 1a2c4f8..a99f808 100644 (file)
--- a/FAQ
+++ b/FAQ
@@ -167,7 +167,7 @@ Q: What features are not available in the Open vSwitch kernel datapath
 
 A: The kernel module in upstream Linux 3.3 and later does not include
    tunnel virtual ports, that is, interfaces with type "gre",
-   "ipsec_gre", "gre64", "ipsec_gre64", "vxlan", or "capwap".  It is
+   "ipsec_gre", "gre64", "ipsec_gre64", "vxlan", or "lisp".  It is
    possible to create tunnels in Linux and attach them to Open vSwitch
    as system devices.  However, they cannot be dynamically created
    through the OVSDB protocol or set the tunnel ids as a flow action.
@@ -320,6 +320,55 @@ A: No.  ERSPAN is an undocumented proprietary protocol.  As an
    alternative, Open vSwitch supports mirroring to a GRE tunnel (see
    above).
 
+Q: Why are there so many different ways to dump flows?
+
+A: Open vSwitch uses different kinds of flows for different purposes:
+
+      - OpenFlow flows are the most important kind of flow.  OpenFlow
+        controllers use these flows to define a switch's policy.
+        OpenFlow flows support wildcards, priorities, and multiple
+        tables.
+
+        When in-band control is in use, Open vSwitch sets up a few
+        "hidden" flows, with priority higher than a controller or the
+        user can configure, that are not visible via OpenFlow.  (See
+        the "Controller" section of the FAQ for more information
+        about hidden flows.)
+
+      - The Open vSwitch software switch implementation uses a second
+        kind of flow internally.  These flows, called "exact-match"
+        or "datapath" or "kernel" flows, do not support wildcards or
+        priorities and comprise only a single table, which makes them
+        suitable for caching.   OpenFlow flows and exact-match flows
+        also support different actions and number ports differently.
+
+        Exact-match flows are an implementation detail that is
+        subject to change in future versions of Open vSwitch.  Even
+        with the current version of Open vSwitch, hardware switch
+        implementations do not necessarily use exact-match flows.
+
+  Each of the commands for dumping flows has a different purpose:
+
+      - "ovs-ofctl dump-flows <br>" dumps OpenFlow flows, excluding
+        hidden flows.  This is the most commonly useful form of flow
+        dump.  (Unlike the other commands, this should work with any
+        OpenFlow switch, not just Open vSwitch.)
+
+      - "ovs-appctl bridge/dump-flows <br>" dumps OpenFlow flows,
+        including hidden flows.  This is occasionally useful for
+        troubleshooting suspected issues with in-band control.
+
+      - "ovs-dpctl dump-flows [dp]" dumps the exact-match flow table
+        entries for a Linux kernel-based datapath.  In Open vSwitch
+        1.10 and later, ovs-vswitchd merges multiple switches into a
+        single datapath, so it will show all the flows on all your
+        kernel-based switches.  This command can occasionally be
+        useful for debugging.
+
+      - "ovs-appctl dpif/dump-flows <br>", new in Open vSwitch 1.10,
+        dumps exact-match flows for only the specified bridge,
+        regardless of the type.
+
 
 Configuration Problems
 ----------------------
@@ -447,6 +496,12 @@ A: Wireless base stations generally only allow packets with the source
    point, so the same problems will show up with the Linux bridge or
    any other way to do bridging.
 
+Q: I can't seem to add my PPP interface to an Open vSwitch bridge.
+
+A: PPP most commonly carries IP packets, but Open vSwitch works only
+   with Ethernet frames.  The correct way to interface PPP to an
+   Ethernet network is usually to use routing instead of switching.
+
 Q: Is there any documentation on the database tables and fields?
 
 A: Yes.  ovs-vswitchd.conf.db(5) is a comprehensive reference.
@@ -520,6 +575,11 @@ A: Suppose that you want to set up bridge br0 connected to physical
 
        ovs-vsctl -- --all destroy QoS -- --all destroy Queue
 
+   If you do want to keep some QoS or Queue records, or the Open
+   vSwitch you are using is older than version 1.8 (which added the
+   --all option), then you will have to destroy QoS and Queue records
+   individually.
+
 Q: I configured Quality of Service (QoS) in my OpenFlow network by
    adding records to the QoS and Queue table, but the results aren't
    what I expect.
@@ -743,8 +803,16 @@ A: The configuration for VLANs in the Open vSwitch database (e.g. via
    You can use "normal switching" as a component of your OpenFlow
    actions, e.g. by putting "normal" into the lists of actions on
    ovs-ofctl or by outputting to OFPP_NORMAL from an OpenFlow
-   controller.  This will only be suitable for some situations,
-   though.
+   controller.  In situations where this is not suitable, you can
+   implement VLAN handling yourself, e.g.:
+
+       - If a packet comes in on an access port, and the flow table
+         needs to send it out on a trunk port, then the flow can add
+         the appropriate VLAN tag with the "mod_vlan_vid" action.
+
+       - If a packet comes in on a trunk port, and the flow table
+         needs to send it out on an access port, then the flow can
+         strip the VLAN tag with the "strip_vlan" action.
 
 Q: I configured ports on a bridge as access ports with different VLAN
    tags, like this:
@@ -938,9 +1006,6 @@ A: Yes, Open vSwitch makes individual bond interfaces visible as
          controller is not configured, this happens implicitly to
          every packet.)
 
-       - The "autopath" Nicira extension action.  However, "autopath"
-         is deprecated and scheduled for removal in February 2013.
-
        - Mirrors configured for output to a bonded port.
 
    It would make a lot of sense for Open vSwitch to present a bond as
@@ -948,6 +1013,88 @@ A: Yes, Open vSwitch makes individual bond interfaces visible as
    implementation of such a feature, please bring it up on the Open
    vSwitch development mailing list at dev@openvswitch.org.
 
+Q: I have a sophisticated network setup involving Open vSwitch, VMs or
+   multiple hosts, and other components.  The behavior isn't what I
+   expect.  Help!
+
+A: To debug network behavior problems, trace the path of a packet,
+   hop-by-hop, from its origin in one host to a remote host.  If
+   that's correct, then trace the path of the response packet back to
+   the origin.
+
+   Usually a simple ICMP echo request and reply ("ping") packet is
+   good enough.  Start by initiating an ongoing "ping" from the origin
+   host to a remote host.  If you are tracking down a connectivity
+   problem, the "ping" will not display any successful output, but
+   packets are still being sent.  (In this case the packets being sent
+   are likely ARP rather than ICMP.)
+
+   Tools available for tracing include the following:
+
+       - "tcpdump" and "wireshark" for observing hops across network
+         devices, such as Open vSwitch internal devices and physical
+         wires.
+
+       - "ovs-appctl dpif/dump-flows <br>" in Open vSwitch 1.10 and
+         later or "ovs-dpctl dump-flows <br>" in earlier versions.
+         These tools allow one to observe the actions being taken on
+         packets in ongoing flows.
+
+         See ovs-vswitchd(8) for "ovs-appctl dpif/dump-flows"
+         documentation, ovs-dpctl(8) for "ovs-dpctl dump-flows"
+         documentation, and "Why are there so many different ways to
+         dump flows?" above for some background.
+
+       - "ovs-appctl ofproto/trace" to observe the logic behind how
+         ovs-vswitchd treats packets.  See ovs-vswitchd(8) for
+         documentation.  You can out more details about a given flow
+         that "ovs-dpctl dump-flows" displays, by cutting and pasting
+         a flow from the output into an "ovs-appctl ofproto/trace"
+         command.
+
+       - SPAN, RSPAN, and ERSPAN features of physical switches, to
+         observe what goes on at these physical hops.
+
+   Starting at the origin of a given packet, observe the packet at
+   each hop in turn.  For example, in one plausible scenario, you
+   might:
+
+       1. "tcpdump" the "eth" interface through which an ARP egresses
+          a VM, from inside the VM.
+
+       2. "tcpdump" the "vif" or "tap" interface through which the ARP
+          ingresses the host machine.
+
+       3. Use "ovs-dpctl dump-flows" to spot the ARP flow and observe
+          the host interface through which the ARP egresses the
+          physical machine.  You may need to use "ovs-dpctl show" to
+          interpret the port numbers.  If the output seems surprising,
+          you can use "ovs-appctl ofproto/trace" to observe details of
+          how ovs-vswitchd determined the actions in the "ovs-dpctl
+          dump-flows" output.
+
+       4. "tcpdump" the "eth" interface through which the ARP egresses
+          the physical machine.
+
+       5. "tcpdump" the "eth" interface through which the ARP
+          ingresses the physical machine, at the remote host that
+          receives the ARP.
+
+       6. Use "ovs-dpctl dump-flows" to spot the ARP flow on the
+          remote host that receives the ARP and observe the VM "vif"
+          or "tap" interface to which the flow is directed.  Again,
+          "ovs-dpctl show" and "ovs-appctl ofproto/trace" might help.
+
+       7. "tcpdump" the "vif" or "tap" interface to which the ARP is
+          directed.
+
+       8. "tcpdump" the "eth" interface through which the ARP
+          ingresses a VM, from inside the VM.
+
+   It is likely that during one of these steps you will figure out the
+   problem.  If not, then follow the ARP reply back to the origin, in
+   reverse.
+
 Contact 
 -------
 
index bd5e2fc..5dce7aa 100644 (file)
@@ -56,6 +56,7 @@ EXTRA_DIST = \
        OPENFLOW-1.1+ \
        PORTING \
        README-gcov \
+       README-lisp \
        REPORTING-BUGS \
        SubmittingPatches \
        WHY-OVS \
diff --git a/NEWS b/NEWS
index 1164962..35b9212 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,40 +1,69 @@
-post-v1.9.0
---------------------
+post-v1.10.0
+---------------------
+    - Stable bond mode has been removed.
+    - The autopath action has been removed.
+    - CAPWAP tunneling support removed.
+    - New support for the data encapsulation format of the LISP tunnel
+      protocol (RFC 6830).  An external control plane or manual flow
+      setup is required for EID-to-RLOC mapping.
+
+
+v1.10.0 - xx xxx xxxx
+---------------------
     - Bridge compatibility support has been removed.  Any uses that
       rely on ovs-brcompatd will have to stick with Open vSwitch 1.9.x
       or adapt to native Open vSwitch support (e.g. use ovs-vsctl instead
       of brctl).
     - The maximum size of the MAC learning table is now configurable.
-    - New support for the VXLAN tunnel protocol (see the IETF draft here:
-      http://tools.ietf.org/html/draft-mahalingam-dutt-dcops-vxlan-02).
     - With the Linux datapath, packets for new flows are now queued
       separately on a per-port basis, so it should no longer be
       possible for a large number of new flows arriving on one port to
       prevent new flows from being processed on other ports.
     - Many "ovs-vsctl" database commands now accept an --if-exists option.
       Please refer to the ovs-vsctl manpage for details.
-    - New "vlog/disable-rate-limit" and "vlog/enable-rate-limit" commands
-      available through ovs-appctl allow control over logging rate limits.
-    - The OpenFlow "dp_desc" may now be configured by setting the value of 
-      other-config:dp-desc in the Bridge table.
-    - Path MTU discovery is no longer supported.
+    - OpenFlow:
+      - Experimental support for newer versions of OpenFlow.  See
+        the "What versions of OpenFlow does Open vSwitch support?"
+        question in the FAQ for more details.
+      - The OpenFlow "dp_desc" may now be configured by setting the
+        value of other-config:dp-desc in the Bridge table.
+      - It is possible to request the OpenFlow port number with the
+        "ofport_request" column in the Interface table.
+    - Tunneling:
+      - New support for the VXLAN tunnel protocol (see the IETF draft here:
+        http://tools.ietf.org/html/draft-mahalingam-dutt-dcops-vxlan-03).
+      - Tunneling requires the version of the kernel module paired with
+        Open vSwitch 1.9.0 or later.
+      - Inheritance of the Don't Fragment bit in IP tunnels (df_inherit)
+        is no longer supported.
+      - Path MTU discovery is no longer supported.
+    - ovs-dpctl:
+      - The "dump-flows" and "del-flows" no longer require an argument
+        if only one datapath exists.
+    - ovs-appctl:
+      - New "vlog/disable-rate-limit" and "vlog/enable-rate-limit"
+        commands available allow control over logging rate limits.
+      - New "dpif/dump-dps", "dpif/show", and "dpif/dump-flows" command
+        that mimic the equivalent ovs-dpctl commands.
+    - The ofproto library is now responsible for assigning OpenFlow port
+      numbers.  An ofproto implementation should assign them when
+      port_construct() is called.
+    - All dpif-based bridges of a particular type share a common
+      datapath called "ovs-<type>", e.g. "ovs-system".  The ovs-dpctl
+      commands will now return information on that shared datapath.  To
+      get the equivalent bridge-specific information, use the new
+      "ovs-appctl dpif/*" commands.
     - Backward-incompatible changes:
       - Earlier Open vSwitch versions treated ANY as a wildcard in flow
         syntax.  OpenFlow 1.1 adds a port named ANY, which introduces a
         conflict.  ANY was rarely used in flow syntax, so we chose to
         retire that meaning of ANY in favor of the OpenFlow 1.1 meaning.
-    - Inheritance of the Don't Fragment bit in IP tunnels (df_inherit) is
-      no longer supported.
-    - Patch ports are implemented in userspace.
-    - Tunneling requires the version of the kernel module paired with Open
-      vSwitch 1.9.0 or later.
+    - Patch ports no longer require kernel support, so they now work
+      with FreeBSD and the kernel module built into Linux 3.3 and later.
 
 
 v1.9.0 - xx xxx xxxx
 --------------------
-    - The tunneling code no longer assumes input and output keys are symmetric.
-      If they are not, PMTUD needs to be disabled for tunneling to work. Note
-      this only applies to flow-based keys.
     - Datapath:
       - Support for ipv6 set action.
       - SKB mark matching and setting.
@@ -49,8 +78,14 @@ v1.9.0 - xx xxx xxxx
       - Allow bitwise masking for SHA and THA fields in ARP, SLL and TLL
         fields in IPv6 neighbor discovery messages, and IPv6 flow label.
       - Adds support for writing to the metadata field for a flow.
-      - It is possible to request the OpenFlow port number with the
-        "ofport_request" column in the Interface table.
+    - Tunneling:
+      - The tunneling code no longer assumes input and output keys are
+        symmetric.  If they are not, PMTUD needs to be disabled for
+        tunneling to work. Note this only applies to flow-based keys.
+      - New support for a nonstandard form of GRE that supports a 64-bit key.
+      - Tunnel Path MTU Discovery default value was set to 'disabled'.
+        This feature is deprecated and will be removed soon.
+      - Tunnel header caching removed.
     - ovs-ofctl:
       - Commands and actions that accept port numbers now also accept keywords
         that represent those ports (such as LOCAL, NONE, and ALL).  This is
@@ -60,31 +95,14 @@ v1.9.0 - xx xxx xxxx
     - ovs-dpctl:
       - Support requesting the port number with the "port_no" option in
         the "add-if" command.
-      - The "dump-flows" and "del-flows" no longer require an argument
-        if only one datapath exists.
-    - ovs-appctl:
-      - New "dpif/dump-dps", "dpif/show", and "dpif/dump-flows" command
-        that mimic the equivalent ovs-dpctl commands.
     - ovs-pki: The "online PKI" features have been removed, along with
       the ovs-pki-cgi program that facilitated it, because of some
       alarmist insecurity claims.  We do not believe that these claims
       are true, but because we do not know of any users for this
       feature it seems better on balance to remove it.  (The ovs-pki-cgi
       program was not included in distribution packaging.)
-    - Tunnel Path MTU Discovery default value was set to 'disabled'.  This
-      feature is deprecated and will be removed soon.
     - ovsdb-server now enforces the immutability of immutable columns.  This
       was not enforced in earlier versions due to an oversight.
-    - New support for a nonstandard form of GRE that supports a 64-bit key.
-    - The ofproto library is now responsible for assigning OpenFlow port
-      numbers.  An ofproto implementation should assign them when
-      port_construct() is called.
-    - All dpif-based bridges of a particular type share a common
-      datapath called "ovs-<type>", e.g. "ovs-system".  The ovs-dpctl
-      commands will now return information on that shared datapath.  To
-      get the equivalent bridge-specific information, use the new
-      "ovs-appctl dpif/*" commands.
-    - Tunnel header caching removed.
     - The following features are now deprecated.  They will be removed no
       earlier than February 2013.  Please email dev@openvswitch.org with
       concerns.
index 2c55cfe..b6a4222 100644 (file)
@@ -66,12 +66,6 @@ probably incomplete.
       specified.  Check that OVS implements the new behavior, fix it
       if not.
 
-    * On OF1.1+ flow_mods, DELETE now ignores buffer_id.
-
-    * OFPST_PORT and OFPST_QUEUE stats.  These differ little from
-      OF1.0 to OF1.1 (just the size of the port number field) but do
-      require abstraction (Done?).
-
     * OFPT_TABLE_MOD stats.  This is new in OF1.1, so we need to
       implement it.  It should be implemented so that the default OVS
       behavior does not change.
@@ -79,8 +73,7 @@ probably incomplete.
     * Document how OVS does packet buffering.
 
     * MPLS.  Simon Horman maintains a patch series that adds this
-      feature.  It needs review and possible revision before it is
-      merged.
+      feature.  This is partially merged.
 
     * SCTP.  Joe Stringer maintains a patch series that adds this
       feature.  It has received review comments that need to be
@@ -99,7 +92,7 @@ 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 didnt compare the specs carefully yet.)
+end of the OF1.2 spec.  I didn't compare the specs carefully yet.)
 
     * Use new OpenFlow extensible error infrastructure, on OF1.2+
       only, instead of the OVS-specific extension used until now.
@@ -120,9 +113,6 @@ end of the OF1.2 spec.  I didn’t compare the specs carefully yet.)
 
         * Update DESIGN to describe OF1.2 behavior also.
 
-    * Implement OFPT_ROLE_REQUEST.  Patch submitted by Jarno
-      Rajahalme, currently under revision.
-
     * Add ability to turn off packet buffering with OFPCML_NO_BUFFER.
 
 OpenFlow 1.3
@@ -131,7 +121,7 @@ OpenFlow 1.3
 OpenFlow 1.3 support requires OpenFlow 1.2 as a prerequisite, plus the
 following additional work.  (This is based on the change log at the
 end of the OF1.3 spec, reusing most of the section titles directly.  I
-didnt compare the specs carefully yet.)
+didn't compare the specs carefully yet.)
 
     * Add support for multipart requests.
 
@@ -148,28 +138,28 @@ didn’t compare the specs carefully yet.)
       and design requirements.  Might be politically difficult to add
       directly to the kernel module, since its functionality overlaps
       with tc.  Ideally, therefore, we could implement these somehow
-      with tc, but I havent investigated whether that makes sense.
+      with tc, but I haven't investigated whether that makes sense.
 
-    * Per-connection event filtering.  OF1.3 adopted Open vSwitchs
+    * Per-connection event filtering.  OF1.3 adopted Open vSwitch's
       existing design for this feature so implementation should be
       easy.
 
     * Auxiliary connections.  These are optional, so a minimal
       implementation would not need them.  An implementation in
-      generic code might be a weeks worth of work.  The value of an
+      generic code might be a week's worth of work.  The value of an
       implementation in generic code is questionable, though, since
       much of the benefit of axuiliary connections is supposed to be
       to take advantage of hardware support.  (We could make the
       kernel module somehow send packets across the auxiliary
-      connections directly, for some kind of “hardware” support, if we
+      connections directly, for some kind of "hardware" support, if we
       judged it useful enough.)
 
     * MPLS BoS matching.  (Included in Simon's MPLS series?)
 
-    * Provider Backbone Bridge tagging.  I dont plan to implement
-      this (but wed accept an implementation).
+    * Provider Backbone Bridge tagging.  I don't plan to implement
+      this (but we'd accept an implementation).
 
-    * Rework tag order.  Im not sure whether we need to do anything
+    * Rework tag order.  I'm not sure whether we need to do anything
       for this.
 
     * Duration for stats.
@@ -202,7 +192,7 @@ Please consider the following:
       tree).
 
     * The patch submission guidelines (see SubmittingPatches).  I
-      recommend using “git send-email”, which automatically follows a
+      recommend using "git send-email", which automatically follows a
       lot of those guidelines.
 
 Bug Reporting
diff --git a/README b/README
index dc5f05e..f6ffa84 100644 (file)
--- a/README
+++ b/README
@@ -24,7 +24,7 @@ vSwitch supports the following features:
     * NIC bonding with or without LACP on upstream switch
     * NetFlow, sFlow(R), and mirroring for increased visibility
     * QoS (Quality of Service) configuration, plus policing
-    * GRE, GRE over IPSEC, CAPWAP, and VXLAN tunneling
+    * GRE, GRE over IPSEC, VXLAN, and LISP tunneling
     * 802.1ag connectivity fault management
     * OpenFlow 1.0 plus numerous extensions
     * Transactional configuration database with C and Python bindings
diff --git a/README-lisp b/README-lisp
new file mode 100644 (file)
index 0000000..7c9071a
--- /dev/null
@@ -0,0 +1,68 @@
+Using LISP tunneling
+====================
+
+LISP is a layer 3 tunneling mechanism, meaning that encapsulated packets do
+not carry Ethernet headers, and ARP requests shouldn't be sent over the
+tunnel.  Because of this, there are some additional steps required for setting
+up LISP tunnels in Open vSwitch, until support for L3 tunnels will improve.
+
+This guide assumes a point-to-point tunnel between two VMs connected to OVS
+bridges on different hypervisors connected via IPv4.  Of course, more than one
+VM may be connected to any of the hypervisors, using the same LISP tunnel, and
+a hypervisor may be connected to several hypervisors over different LISP
+tunnels.
+
+There are several scenarios:
+
+  1) the VMs have IP addresses in the same subnet and the hypervisors are also
+     in a single subnet (although one different from the VM's);
+  2) the VMs have IP addresses in the same subnet but the hypervisors are
+     separated by a router;
+  3) the VMs are in different subnets.
+
+In cases 1) and 3) ARP resolution can work as normal: ARP traffic is
+configured not to go through the LISP tunnel.  For case 1) ARP is able to
+reach the other VM, if both OVS instances default to MAC address learning.
+Case 3) requires the hypervisor be configured as the default router for the
+VMs.
+
+In case 2) the VMs expect ARP replies from each other, but this is not
+possible over a layer 3 tunnel.  One solution is to have static MAC address
+entries preconfigured on the VMs (e.g., `arp -f /etc/ethers` on startup on
+Unix based VMs), or have the hypervisor do proxy ARP.
+
+On the receiving side, the packet arrives without the original MAC header.
+The LISP tunneling code attaches a header with harcoded source and destination
+MAC addres 02:00:00:00:00:00.  This address has all bits set to 0, except the
+locally administered bit, in order to avoid potential collisions with existing
+allocations.  In order for packets to reach their intended destination, the
+destination MAC address needs to be rewritten.  This can be done using the
+flow table.
+
+See below for an example setup, and the associated flow rules to enable LISP
+tunneling.
+
+               +---+                               +---+
+               |VM1|                               |VM2|
+               +---+                               +---+
+                 |                                   |
+            +--[tap0]--+                       +--[tap0]---+
+            |          |                       |           |
+        [lisp0] OVS1 [eth0]-----------------[eth0] OVS2 [lisp0]
+            |          |                       |           |
+            +----------+                       +-----------+
+
+On each hypervisor, interfaces tap0, eth0, and lisp0 are added to a single
+bridge instance, and become numbered 1, 2, and 3 respectively:
+
+    ovs-vsctl add-br br0
+    ovs-vsctl add-port br0 tap0
+    ovs-vsctl add-port br0 eth0
+    ovs-vsctl add-port br0 lisp0 -- set Interface lisp0 type=lisp options:remote_ip=<OVSx_IP>
+
+Flows on br0 are configured as follows:
+
+    priority=3,dl_dst=02:00:00:00:00:00,action=mod_dl_dst:<VMx_MAC>,output:1
+    priority=2,in_port=1,dl_type=0x0806,action=NORMAL
+    priority=1,in_port=1,dl_type=0x0800,vlan_tci=0,nw_src=<EID_prefix>,action=output:3
+    priority=0,action=NORMAL
index bcfb227..1cacd29 100644 (file)
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 AC_PREREQ(2.64)
-AC_INIT(openvswitch, 1.9.90, ovs-bugs@openvswitch.org)
+AC_INIT(openvswitch, 1.10.90, ovs-bugs@openvswitch.org)
 AC_CONFIG_SRCDIR([datapath/datapath.c])
 AC_CONFIG_MACRO_DIR([m4])
 AC_CONFIG_AUX_DIR([build-aux])
diff --git a/datapath/CAPWAP.txt b/datapath/CAPWAP.txt
deleted file mode 100644 (file)
index 5ab6d53..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-
-References:
-* http://www.rfc-editor.org/rfc/rfc5415.txt
-
-
-The CAPWAP header layout is summarized as follows:
-
-
-        0                   1                   2                   3
-        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-       |CAPWAP Preamble|  HLEN   |   RID   | WBID    |T|F|L|W|M|K|Flags|
-       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-       |          Fragment ID          |     Frag Offset         |Rsvd |
-       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-       |                 (optional) Radio MAC Address                  |
-       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-       |            (optional) Wireless Specific Information           |
-       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-       |                        Payload ....                           |
-       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
-The spec defines an optional Wireless Specific Information field which can be
-used to pass arbitrary data in the encapsulation layer:
-
-   Wireless Specific Information:  This optional field may be used to carry
-      per-packet information.  This field is only present if the
-      'W' bit is set.  The WBID field in the CAPWAP Header is used to
-      identify the format of the WSI optional field. The HLEN field assumes
-      4-byte alignment, and this field MUST be padded with zeroes (0x00) if it
-      is not 4-byte aligned.
-
-      The Wireless-Specific Information field uses the following format:
-
-        0                   1                   2                   3
-        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-       |    Length     |                Data...
-       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
-      Length:  The 8-bit field contains the length of the data field,
-         with a maximum size of 255.
-
-      Data:  Wireless-specific information, defined by the wireless-
-         specific binding specified in the CAPWAP Header's WBID field.
-
-
-   WBID:  A 5-bit field that is the wireless binding identifier.  The
-      identifier will indicate the type of wireless packet associated
-      with the radio.  The following values are defined:
-
-      0 -  Reserved
-      1 -  IEEE 802.11
-      2 -  Reserved
-      3 -  EPCGlobal [EPCGlobal]
-
-      When Open vSwitch uses this field, it writes the value:
-      30 - Open vSwitch data
-
-
-Open vSwitch can make use of this field to pass additional packet routing
-information. When needed, it sets the 'W' bit to indicates the WSI field is
-added, and fills the field as follows:
-
-        0                   1                   2                   3
-        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-       |  WSI_LEN      |K|      Flags  |             Reserved          |
-       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-       |   (optional) 64bit Tunnel Key                                 |
-       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
-       K - flag bit to identify presence of a 64bit tunnel key.
-
-
-Adding WSI fields:  Fields must be written and read in consitent order.  New
-fields may be added, but the existing fields always come first.
index 54c6f13..9941123 100644 (file)
@@ -16,9 +16,9 @@ openvswitch_sources = \
        tunnel.c \
        vlan.c \
        vport.c \
-       vport-capwap.c \
        vport-gre.c \
        vport-internal_dev.c \
+       vport-lisp.c \
        vport-netdev.c \
        vport-vxlan.c
 
@@ -31,13 +31,11 @@ openvswitch_headers = \
        tunnel.h \
        vlan.h \
        vport.h \
-       vport-capwap.h \
        vport-internal_dev.h \
        vport-netdev.h
 
 openvswitch_extras = \
-       README \
-       CAPWAP.txt
+       README
 
 dist_sources = $(foreach module,$(dist_modules),$($(module)_sources))
 dist_headers = $(foreach module,$(dist_modules),$($(module)_headers))
index f638ffc..9202335 100644 (file)
@@ -61,7 +61,7 @@ static int __pop_vlan_tci(struct sk_buff *skb, __be16 *current_tci)
 
        if (get_ip_summed(skb) == OVS_CSUM_COMPLETE)
                skb->csum = csum_sub(skb->csum, csum_partial(skb->data
-                                       + ETH_HLEN, VLAN_HLEN, 0));
+                                       + (2 * ETH_ALEN), VLAN_HLEN, 0));
 
        vhdr = (struct vlan_hdr *)(skb->data + ETH_HLEN);
        *current_tci = vhdr->h_vlan_TCI;
@@ -118,7 +118,7 @@ static int push_vlan(struct sk_buff *skb, const struct ovs_action_push_vlan *vla
 
                if (get_ip_summed(skb) == OVS_CSUM_COMPLETE)
                        skb->csum = csum_add(skb->csum, csum_partial(skb->data
-                                       + ETH_HLEN, VLAN_HLEN, 0));
+                                       + (2 * ETH_ALEN), VLAN_HLEN, 0));
 
        }
        __vlan_hwaccel_put_tag(skb, ntohs(vlan->vlan_tci) & ~VLAN_TAG_PRESENT);
index 04a5e7f..bd2d57b 100644 (file)
@@ -306,7 +306,7 @@ static int queue_gso_packets(struct net *net, int dp_ifindex,
        struct sk_buff *segs, *nskb;
        int err;
 
-       segs = skb_gso_segment(skb, NETIF_F_SG | NETIF_F_HW_CSUM);
+       segs = __skb_gso_segment(skb, NETIF_F_SG | NETIF_F_HW_CSUM, false);
        if (IS_ERR(segs))
                return PTR_ERR(segs);
 
@@ -374,8 +374,8 @@ static int queue_userspace_packet(struct net *net, int dp_ifindex,
        len = sizeof(struct ovs_header);
        len += nla_total_size(skb->len);
        len += nla_total_size(FLOW_BUFSIZE);
-       if (upcall_info->cmd == OVS_PACKET_CMD_ACTION)
-               len += nla_total_size(8);
+       if (upcall_info->userdata)
+               len += NLA_ALIGN(upcall_info->userdata->nla_len);
 
        user_skb = genlmsg_new(len, GFP_ATOMIC);
        if (!user_skb) {
@@ -392,13 +392,15 @@ static int queue_userspace_packet(struct net *net, int dp_ifindex,
        nla_nest_end(user_skb, nla);
 
        if (upcall_info->userdata)
-               nla_put_u64(user_skb, OVS_PACKET_ATTR_USERDATA,
-                           nla_get_u64(upcall_info->userdata));
+               __nla_put(user_skb, OVS_PACKET_ATTR_USERDATA,
+                         nla_len(upcall_info->userdata),
+                         nla_data(upcall_info->userdata));
 
        nla = __nla_reserve(user_skb, OVS_PACKET_ATTR_PACKET, skb->len);
 
        skb_copy_and_csum_dev(skb, nla_data(nla));
 
+       genlmsg_end(user_skb, upcall);
        err = genlmsg_unicast(net, user_skb, upcall_info->portid);
 
 out:
@@ -432,10 +434,10 @@ static struct nlattr *reserve_sfa_size(struct sw_flow_actions **sfa, int attr_le
        int next_offset = offsetof(struct sw_flow_actions, actions) +
                                        (*sfa)->actions_len;
 
-       if (req_size <= (ksize(*sfa) - next_offset))
+       if (req_size <= ((*sfa)->buf_size - next_offset))
                goto out;
 
-       new_acts_size = ksize(*sfa) * 2;
+       new_acts_size = (*sfa)->buf_size * 2;
 
        if (new_acts_size > MAX_ACTIONS_BUFSIZE) {
                if ((MAX_ACTIONS_BUFSIZE - next_offset) < req_size)
@@ -449,7 +451,7 @@ static struct nlattr *reserve_sfa_size(struct sw_flow_actions **sfa, int attr_le
 
        memcpy(acts->actions, (*sfa)->actions, (*sfa)->actions_len);
        acts->actions_len = (*sfa)->actions_len;
-       kfree(*sfa);
+       ovs_flow_actions_free(*sfa);
        *sfa = acts;
 
 out:
@@ -678,7 +680,7 @@ static int validate_userspace(const struct nlattr *attr)
 {
        static const struct nla_policy userspace_policy[OVS_USERSPACE_ATTR_MAX + 1] =   {
                [OVS_USERSPACE_ATTR_PID] = {.type = NLA_U32 },
-               [OVS_USERSPACE_ATTR_USERDATA] = {.type = NLA_U64 },
+               [OVS_USERSPACE_ATTR_USERDATA] = {.type = NLA_UNSPEC },
        };
        struct nlattr *a[OVS_USERSPACE_ATTR_MAX + 1];
        int error;
@@ -1290,7 +1292,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
        return 0;
 
 err_kfree:
-       kfree(acts);
+       ovs_flow_actions_free(acts);
 error:
        return error;
 }
@@ -1967,6 +1969,7 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
        if (IS_ERR(vport))
                goto exit_unlock;
 
+       err = 0;
        if (a[OVS_VPORT_ATTR_STATS])
                ovs_vport_set_stats(vport, nla_data(a[OVS_VPORT_ATTR_STATS]));
 
@@ -2064,6 +2067,7 @@ static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
        if (IS_ERR(reply))
                goto exit_unlock;
 
+       err = 0;
        ovs_dp_detach_port(vport);
 
        genl_notify(reply, genl_info_net(info), info->snd_portid,
index 2b93348..01e7296 100644 (file)
@@ -120,7 +120,7 @@ struct ovs_skb_cb {
  * struct dp_upcall - metadata to include with a packet to send to userspace
  * @cmd: One of %OVS_PACKET_CMD_*.
  * @key: Becomes %OVS_PACKET_ATTR_KEY.  Must be nonnull.
- * @userdata: If nonnull, its u64 value is extracted and passed to userspace as
+ * @userdata: If nonnull, its variable-length value is passed to userspace as
  * %OVS_PACKET_ATTR_USERDATA.
  * @portid: Netlink PID to which packet should be sent.  If @portid is 0 then no
  * packet is sent and the packet is accounted in the datapath's @n_lost
@@ -141,7 +141,6 @@ struct dp_upcall_info {
  */
 struct ovs_net {
        struct list_head dps;
-       struct vport_net vport_net;
 };
 
 extern int ovs_net_id;
index fad9e19..b6bb7a7 100644 (file)
@@ -207,14 +207,29 @@ struct sw_flow_actions *ovs_flow_actions_alloc(int size)
        if (size > MAX_ACTIONS_BUFSIZE)
                return ERR_PTR(-EINVAL);
 
-       sfa = kmalloc(sizeof(*sfa) + size, GFP_KERNEL);
+       size += sizeof(*sfa);
+       if (size <= MAX_ACTIONS_BUFSIZE_KMALLOC)
+               sfa = kmalloc(size, GFP_KERNEL);
+       else
+               sfa = vmalloc(size);
+
        if (!sfa)
                return ERR_PTR(-ENOMEM);
 
        sfa->actions_len = 0;
+       sfa->buf_size = size;
+
        return sfa;
 }
 
+void ovs_flow_actions_free(struct sw_flow_actions *sfa)
+{
+       if (sfa->buf_size <= MAX_ACTIONS_BUFSIZE_KMALLOC)
+               kfree(sfa);
+       else
+               vfree(sfa);
+}
+
 struct sw_flow *ovs_flow_alloc(void)
 {
        struct sw_flow *flow;
@@ -437,7 +452,7 @@ static void rcu_free_acts_callback(struct rcu_head *rcu)
 {
        struct sw_flow_actions *sf_acts = container_of(rcu,
                        struct sw_flow_actions, rcu);
-       kfree(sf_acts);
+       ovs_flow_actions_free(sf_acts);
 }
 
 /* Schedules 'sf_acts' to be freed after the next RCU grace period.
@@ -500,7 +515,11 @@ static __be16 parse_ethertype(struct sk_buff *skb)
                return htons(ETH_P_802_2);
 
        __skb_pull(skb, sizeof(struct llc_snap_hdr));
-       return llc->ethertype;
+
+       if (ntohs(llc->ethertype) >= 1536)
+               return llc->ethertype;
+
+       return htons(ETH_P_802_2);
 }
 
 static int parse_icmpv6(struct sk_buff *skb, struct sw_flow_key *key,
index 6949640..3b08ea6 100644 (file)
@@ -37,6 +37,7 @@ struct sk_buff;
 struct sw_flow_actions {
        struct rcu_head rcu;
        u32 actions_len;
+       int buf_size;
        struct nlattr actions[];
 };
 
@@ -151,6 +152,7 @@ void ovs_flow_deferred_free(struct sw_flow *);
 void ovs_flow_free(struct sw_flow *);
 
 struct sw_flow_actions *ovs_flow_actions_alloc(int actions_len);
+void ovs_flow_actions_free(struct sw_flow_actions *sfa);
 void ovs_flow_deferred_free_acts(struct sw_flow_actions *);
 
 int ovs_flow_extract(struct sk_buff *, u16 in_port, struct sw_flow_key *,
@@ -194,7 +196,8 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
 int ovs_flow_metadata_from_nlattrs(struct sw_flow *flow, int key_len,
                                   const struct nlattr *attr);
 
-#define MAX_ACTIONS_BUFSIZE    (16 * 1024)
+#define MAX_ACTIONS_BUFSIZE            (32 * 1024)
+#define MAX_ACTIONS_BUFSIZE_KMALLOC    PAGE_SIZE
 #define TBL_MIN_BUCKETS                1024
 
 struct flow_table {
index 901b2a8..16fbc8a 100644 (file)
 /tmp
 /tunnel.c
 /vlan.c
-/vport-capwap.c
 /vport-generic.c
 /vport-gre.c
 /vport-internal_dev.c
+/vport-lisp.c
 /vport-netdev.c
 /vport-patch.c
 /vport-vxlan.c
index 0c2f2f4..71aad87 100644 (file)
@@ -154,4 +154,17 @@ static inline int rpl_netif_needs_gso(struct sk_buff *skb, int features)
 }
 #endif
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0)
+typedef u32 netdev_features_t;
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0)
+static inline struct sk_buff *__skb_gso_segment(struct sk_buff *skb,
+                                               netdev_features_t features,
+                                               bool tx_path)
+{
+       return skb_gso_segment(skb, features);
+}
+#endif
+
 #endif
index 6193891..a05cf54 100644 (file)
@@ -45,6 +45,7 @@
 #include <net/xfrm.h>
 
 #include "checksum.h"
+#include "compat.h"
 #include "datapath.h"
 #include "tunnel.h"
 #include "vlan.h"
@@ -360,7 +361,7 @@ void ovs_tnl_rcv(struct vport *vport, struct sk_buff *skb)
 
 static struct rtable *find_route(struct net *net,
                __be32 *saddr, __be32 daddr, u8 ipproto,
-               u8 tos)
+               u8 tos, u32 skb_mark)
 {
        struct rtable *rt;
        /* Tunnel configuration keeps DSCP part of TOS bits, But Linux
@@ -370,7 +371,13 @@ static 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)))
@@ -381,6 +388,7 @@ static struct rtable *find_route(struct net *net,
        struct flowi4 fl = { .daddr = daddr,
                             .saddr = *saddr,
                             .flowi4_tos = RT_TOS(tos),
+                            .flowi4_mark = skb_mark,
                             .flowi4_proto = ipproto };
 
        rt = ip_route_output_key(net, &fl);
@@ -435,7 +443,7 @@ static struct sk_buff *handle_offloads(struct sk_buff *skb,
        if (skb_is_gso(skb)) {
                struct sk_buff *nskb;
 
-               nskb = skb_gso_segment(skb, 0);
+               nskb = __skb_gso_segment(skb, 0, false);
                if (IS_ERR(nskb)) {
                        kfree_skb(skb);
                        err = PTR_ERR(nskb);
@@ -504,6 +512,21 @@ free_frags:
        return sent_len;
 }
 
+/* Compute source UDP port for outgoing packet.
+ * Currently we use the flow hash.
+ */
+u16 ovs_tnl_get_src_port(struct sk_buff *skb)
+{
+       int low;
+       int high;
+       unsigned int range;
+       u32 hash = OVS_CB(skb)->flow->hash;
+
+       inet_get_local_port_range(&low, &high);
+       range = (high - low) + 1;
+       return (((u64) hash * range) >> 32) + low;
+}
+
 int ovs_tnl_send(struct vport *vport, struct sk_buff *skb)
 {
        struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
@@ -516,6 +539,7 @@ int ovs_tnl_send(struct vport *vport, struct sk_buff *skb)
        __be16 frag_off;
        __be32 daddr;
        __be32 saddr;
+       u32 skb_mark;
        u8 ttl;
        u8 tos;
 
@@ -608,8 +632,9 @@ int ovs_tnl_send(struct vport *vport, struct sk_buff *skb)
        }
 
        /* Route lookup */
+       skb_mark = skb_get_mark(skb);
        rt = find_route(port_key_get_net(&mutable->key), &saddr, daddr,
-                         tnl_vport->tnl_ops->ipproto, tos);
+                         tnl_vport->tnl_ops->ipproto, tos, skb_mark);
        if (IS_ERR(rt))
                goto error_free;
 
@@ -773,7 +798,7 @@ static int tnl_set_config(struct net *net, struct nlattr *options,
 
                rt = find_route(port_key_get_net(&mutable->key),
                             &saddr, mutable->key.daddr,
-                            tnl_ops->ipproto, mutable->tos);
+                            tnl_ops->ipproto, mutable->tos, 0);
                if (IS_ERR(rt))
                        return -EADDRNOTAVAIL;
                dev = rt_dst(rt).dev;
@@ -799,7 +824,6 @@ struct vport *ovs_tnl_create(const struct vport_parms *parms,
        struct vport *vport;
        struct tnl_vport *tnl_vport;
        struct tnl_mutable_config *mutable;
-       int initial_frag_id;
        int err;
 
        vport = ovs_vport_alloc(sizeof(struct tnl_vport), vport_ops, parms);
@@ -819,9 +843,6 @@ struct vport *ovs_tnl_create(const struct vport_parms *parms,
                goto error_free_vport;
        }
 
-       get_random_bytes(&initial_frag_id, sizeof(int));
-       atomic_set(&tnl_vport->frag_id, initial_frag_id);
-
        err = tnl_set_config(ovs_dp_get_net(parms->dp), parms->options, tnl_ops,
                             NULL, mutable);
        if (err)
index 7e4d1a6..2bdfe91 100644 (file)
@@ -41,8 +41,8 @@
  */
 #define TNL_T_PROTO_GRE                0
 #define TNL_T_PROTO_GRE64      1
-#define TNL_T_PROTO_CAPWAP     2
 #define TNL_T_PROTO_VXLAN      3
+#define TNL_T_PROTO_LISP       4
 
 /* These flags are only needed when calling tnl_find_port(). */
 #define TNL_T_KEY_EXACT                (1 << 10)
@@ -56,7 +56,7 @@
 
 /* All public tunnel flags. */
 #define TNL_F_PUBLIC (TNL_F_CSUM | TNL_F_TOS_INHERIT | TNL_F_TTL_INHERIT | \
-                     TNL_F_DF_DEFAULT | TNL_F_IPSEC)
+                     TNL_F_DF_DEFAULT)
 
 /**
  * struct port_lookup_key - Tunnel port key, used as hash table key.
@@ -147,13 +147,6 @@ struct tnl_vport {
        const struct tnl_ops *tnl_ops;
 
        struct tnl_mutable_config __rcu *mutable;
-
-       /*
-        * ID of last fragment sent (for tunnel protocols with direct support
-        * fragmentation).  If the protocol relies on IP fragmentation then
-        * this is not needed.
-        */
-       atomic_t frag_id;
 };
 
 struct vport *ovs_tnl_create(const struct vport_parms *, const struct vport_ops *,
@@ -166,6 +159,7 @@ int ovs_tnl_get_options(const struct vport *, struct sk_buff *);
 const char *ovs_tnl_get_name(const struct vport *vport);
 int ovs_tnl_send(struct vport *vport, struct sk_buff *skb);
 void ovs_tnl_rcv(struct vport *vport, struct sk_buff *skb);
+u16 ovs_tnl_get_src_port(struct sk_buff *skb);
 
 struct vport *ovs_tnl_find_port(struct net *net, __be32 saddr, __be32 daddr,
                                __be64 key, int tunnel_type,
diff --git a/datapath/vport-capwap.c b/datapath/vport-capwap.c
deleted file mode 100644 (file)
index 56e6394..0000000
+++ /dev/null
@@ -1,851 +0,0 @@
-/*
- * Copyright (c) 2007-2012 Nicira, Inc.
- * Distributed under the terms of the GNU GPL version 2.
- *
- * Significant portions of this file may be copied from parts of the Linux
- * kernel, by Linus Torvalds and others.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/version.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
-
-#include <linux/if.h>
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/list.h>
-#include <linux/net.h>
-#include <net/net_namespace.h>
-
-#include <net/icmp.h>
-#include <net/inet_frag.h>
-#include <net/ip.h>
-#include <net/protocol.h>
-#include <net/udp.h>
-
-#include "datapath.h"
-#include "tunnel.h"
-#include "vport.h"
-
-#define CAPWAP_SRC_PORT 58881
-#define CAPWAP_DST_PORT 58882
-
-#define CAPWAP_FRAG_TIMEOUT (30 * HZ)
-#define CAPWAP_FRAG_MAX_MEM (256 * 1024)
-#define CAPWAP_FRAG_PRUNE_MEM (192 * 1024)
-#define CAPWAP_FRAG_SECRET_INTERVAL (10 * 60 * HZ)
-
-/*
- * The CAPWAP header is a mess, with all kinds of odd size bit fields that
- * cross byte boundaries, which are difficult to represent correctly in
- * various byte orderings.  Luckily we only care about a few permutations, so
- * statically create them and we can do very fast parsing by checking all 12
- * fields in one go.
- */
-#define CAPWAP_PREAMBLE_MASK __cpu_to_be32(0xFF000000)
-#define CAPWAP_HLEN_SHIFT    17
-#define CAPWAP_HLEN_MASK     __cpu_to_be32(0x00F80000)
-#define CAPWAP_RID_MASK      __cpu_to_be32(0x0007C000)
-#define CAPWAP_WBID_MASK     __cpu_to_be32(0x00003E00)
-#define CAPWAP_F_MASK        __cpu_to_be32(0x000001FF)
-
-#define CAPWAP_F_FRAG        __cpu_to_be32(0x00000080)
-#define CAPWAP_F_LASTFRAG    __cpu_to_be32(0x00000040)
-#define CAPWAP_F_WSI         __cpu_to_be32(0x00000020)
-#define CAPWAP_F_RMAC        __cpu_to_be32(0x00000010)
-
-#define CAPWAP_RMAC_LEN      4
-
-/*  Standard CAPWAP looks for a WBID value of 2.
- *  When we insert WSI field, use WBID value of 30, which has been
- *  proposed for all "experimental" usage - users with no reserved WBID value
- *  of their own.
-*/
-#define CAPWAP_WBID_30   __cpu_to_be32(0x00003C00)
-#define CAPWAP_WBID_2    __cpu_to_be32(0x00000200)
-
-#define FRAG_HDR (CAPWAP_F_FRAG)
-#define FRAG_LAST_HDR (FRAG_HDR | CAPWAP_F_LASTFRAG)
-
-/* Keyed packet, WBID 30, and length long enough to include WSI key */
-#define CAPWAP_KEYED (CAPWAP_WBID_30 | CAPWAP_F_WSI | htonl(20 << CAPWAP_HLEN_SHIFT))
-/* A backward-compatible packet, WBID 2 and length of 2 words (no WSI fields) */
-#define CAPWAP_NO_WSI (CAPWAP_WBID_2 | htonl(8 << CAPWAP_HLEN_SHIFT))
-
-/* Mask for all parts of header that must be 0. */
-#define CAPWAP_ZERO_MASK (CAPWAP_PREAMBLE_MASK | \
-               (CAPWAP_F_MASK ^ (CAPWAP_F_WSI | CAPWAP_F_FRAG | CAPWAP_F_LASTFRAG | CAPWAP_F_RMAC)))
-
-struct capwaphdr {
-       __be32 begin;
-       __be16 frag_id;
-       /* low 3 bits of frag_off are reserved */
-       __be16 frag_off;
-};
-
-/*
- * We use the WSI field to hold additional tunnel data.
- * The first eight bits store the size of the wsi data in bytes.
- */
-struct capwaphdr_wsi {
-       u8 wsi_len;
-       u8 flags;
-       __be16 reserved_padding;
-};
-
-struct capwaphdr_wsi_key {
-       __be64 key;
-};
-
-/* Flag indicating a 64bit key is stored in WSI data field */
-#define CAPWAP_WSI_F_KEY64 0x80
-
-static struct capwaphdr *capwap_hdr(const struct sk_buff *skb)
-{
-       return (struct capwaphdr *)(udp_hdr(skb) + 1);
-}
-
-/*
- * The fragment offset is actually the high 13 bits of the last 16 bit field,
- * so we would normally need to right shift 3 places.  However, it stores the
- * offset in 8 byte chunks, which would involve a 3 place left shift.  So we
- * just mask off the last 3 bits and be done with it.
- */
-#define FRAG_OFF_MASK (~0x7U)
-
-/*
- * The minimum header length.  The header may be longer if the optional
- * WSI field is used.
- */
-#define CAPWAP_MIN_HLEN (sizeof(struct udphdr) + sizeof(struct capwaphdr))
-
-struct frag_match {
-       __be32 saddr;
-       __be32 daddr;
-       __be16 id;
-};
-
-struct frag_queue {
-       struct inet_frag_queue ifq;
-       struct frag_match match;
-};
-
-struct frag_skb_cb {
-       u16 offset;
-};
-#define FRAG_CB(skb) ((struct frag_skb_cb *)(skb)->cb)
-
-static struct sk_buff *fragment(struct sk_buff *, const struct vport *,
-                               struct dst_entry *dst, unsigned int hlen);
-static struct sk_buff *defrag(struct sk_buff *, bool frag_last);
-
-static void capwap_frag_init(struct inet_frag_queue *, void *match);
-static unsigned int capwap_frag_hash(struct inet_frag_queue *);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)
-static int capwap_frag_match(struct inet_frag_queue *, void *match);
-#else
-static bool capwap_frag_match(struct inet_frag_queue *, void *match);
-#endif
-static void capwap_frag_expire(unsigned long ifq);
-
-static struct inet_frags frag_state = {
-       .constructor    = capwap_frag_init,
-       .qsize          = sizeof(struct frag_queue),
-       .hashfn         = capwap_frag_hash,
-       .match          = capwap_frag_match,
-       .frag_expire    = capwap_frag_expire,
-       .secret_interval = CAPWAP_FRAG_SECRET_INTERVAL,
-};
-
-static int capwap_hdr_len(const struct tnl_mutable_config *mutable,
-                         const struct ovs_key_ipv4_tunnel *tun_key)
-{
-       int size = CAPWAP_MIN_HLEN;
-       u32 flags;
-       __be64 out_key;
-
-       tnl_get_param(mutable, tun_key, &flags, &out_key);
-
-       /* CAPWAP has no checksums. */
-       if (flags & TNL_F_CSUM)
-               return -EINVAL;
-
-       /* if keys are specified, then add WSI field */
-       if (out_key || (flags & TNL_F_OUT_KEY_ACTION)) {
-               size += sizeof(struct capwaphdr_wsi) +
-                       sizeof(struct capwaphdr_wsi_key);
-       }
-
-       return size;
-}
-
-static struct sk_buff *capwap_build_header(const struct vport *vport,
-                                           const struct tnl_mutable_config *mutable,
-                                           struct dst_entry *dst,
-                                           struct sk_buff *skb,
-                                           int tunnel_hlen)
-{
-       struct ovs_key_ipv4_tunnel *tun_key = OVS_CB(skb)->tun_key;
-       struct udphdr *udph = udp_hdr(skb);
-       struct capwaphdr *cwh = (struct capwaphdr *)(udph + 1);
-       u32 flags;
-       __be64 out_key;
-
-       tnl_get_param(mutable, tun_key, &flags, &out_key);
-
-       udph->source = htons(CAPWAP_SRC_PORT);
-       udph->dest = htons(CAPWAP_DST_PORT);
-       udph->check = 0;
-
-       cwh->frag_id = 0;
-       cwh->frag_off = 0;
-
-       if (out_key || flags & TNL_F_OUT_KEY_ACTION) {
-               /* first field in WSI is key */
-               struct capwaphdr_wsi *wsi = (struct capwaphdr_wsi *)(cwh + 1);
-
-               cwh->begin = CAPWAP_KEYED;
-
-               /* -1 for wsi_len byte, not included in length as per spec */
-               wsi->wsi_len = sizeof(struct capwaphdr_wsi) - 1
-                       + sizeof(struct capwaphdr_wsi_key);
-               wsi->flags = CAPWAP_WSI_F_KEY64;
-               wsi->reserved_padding = 0;
-
-               if (out_key) {
-                       struct capwaphdr_wsi_key *opt = (struct capwaphdr_wsi_key *)(wsi + 1);
-                       opt->key = out_key;
-               }
-       } else {
-               /* make packet readable by old capwap code */
-               cwh->begin = CAPWAP_NO_WSI;
-       }
-       udph->len = htons(skb->len - skb_transport_offset(skb));
-
-       if (unlikely(skb->len - skb_network_offset(skb) > dst_mtu(dst))) {
-               unsigned int hlen = skb_transport_offset(skb) + capwap_hdr_len(mutable, tun_key);
-               skb = fragment(skb, vport, dst, hlen);
-       }
-
-       return skb;
-}
-
-static int process_capwap_wsi(struct sk_buff *skb, __be64 *key, bool *key_present)
-{
-       struct capwaphdr *cwh = capwap_hdr(skb);
-       struct capwaphdr_wsi *wsi;
-       int hdr_len;
-       int rmac_len = 0;
-       int wsi_len;
-
-       if (((cwh->begin & CAPWAP_WBID_MASK) != CAPWAP_WBID_30))
-               return 0;
-
-       if (cwh->begin & CAPWAP_F_RMAC)
-               rmac_len = CAPWAP_RMAC_LEN;
-
-       hdr_len = ntohl(cwh->begin & CAPWAP_HLEN_MASK) >> CAPWAP_HLEN_SHIFT;
-
-       if (unlikely(sizeof(struct capwaphdr) + rmac_len + sizeof(struct capwaphdr_wsi) > hdr_len))
-               return -EINVAL;
-
-       /* read wsi header to find out how big it really is */
-       wsi = (struct capwaphdr_wsi *)((u8 *)(cwh + 1) + rmac_len);
-       /* +1 for length byte not included in wsi_len */
-       wsi_len = 1 + wsi->wsi_len;
-
-       if (unlikely(sizeof(struct capwaphdr) + rmac_len + wsi_len != hdr_len))
-               return -EINVAL;
-
-       wsi_len -= sizeof(struct capwaphdr_wsi);
-
-       if (wsi->flags & CAPWAP_WSI_F_KEY64) {
-               struct capwaphdr_wsi_key *opt;
-
-               if (unlikely(wsi_len < sizeof(struct capwaphdr_wsi_key)))
-                       return -EINVAL;
-
-               opt = (struct capwaphdr_wsi_key *)(wsi + 1);
-               *key = opt->key;
-               *key_present = true;
-       } else {
-               *key_present = false;
-       }
-
-       return 0;
-}
-
-static struct sk_buff *process_capwap_proto(struct sk_buff *skb, __be64 *key, bool *key_present)
-{
-       struct capwaphdr *cwh = capwap_hdr(skb);
-       int hdr_len = sizeof(struct udphdr);
-
-       if (unlikely((cwh->begin & CAPWAP_ZERO_MASK) != 0))
-               goto error;
-
-       hdr_len += ntohl(cwh->begin & CAPWAP_HLEN_MASK) >> CAPWAP_HLEN_SHIFT;
-       if (unlikely(hdr_len < CAPWAP_MIN_HLEN))
-               goto error;
-
-       if (unlikely(!pskb_may_pull(skb, hdr_len + ETH_HLEN)))
-               goto error;
-
-       cwh = capwap_hdr(skb);
-       __skb_pull(skb, hdr_len);
-       skb_postpull_rcsum(skb, skb_transport_header(skb), hdr_len + ETH_HLEN);
-
-       if (cwh->begin & CAPWAP_F_FRAG) {
-               skb = defrag(skb, (__force bool)(cwh->begin & CAPWAP_F_LASTFRAG));
-               if (!skb)
-                       return NULL;
-               cwh = capwap_hdr(skb);
-       }
-
-       if ((cwh->begin & CAPWAP_F_WSI) && process_capwap_wsi(skb, key, key_present))
-               goto error;
-
-       return skb;
-error:
-       kfree_skb(skb);
-       return NULL;
-}
-
-/* Called with rcu_read_lock and BH disabled. */
-static int capwap_rcv(struct sock *sk, struct sk_buff *skb)
-{
-       struct vport *vport;
-       const struct tnl_mutable_config *mutable;
-       struct iphdr *iph;
-       struct ovs_key_ipv4_tunnel tun_key;
-       __be64 key = 0;
-       bool key_present = false;
-
-       if (unlikely(!pskb_may_pull(skb, CAPWAP_MIN_HLEN + ETH_HLEN)))
-               goto error;
-
-       skb = process_capwap_proto(skb, &key, &key_present);
-       if (unlikely(!skb))
-               goto out;
-
-       iph = ip_hdr(skb);
-       vport = ovs_tnl_find_port(sock_net(sk), iph->daddr, iph->saddr, key,
-                                 TNL_T_PROTO_CAPWAP, &mutable);
-       if (unlikely(!vport)) {
-               icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
-               goto error;
-       }
-
-       if (key_present && mutable->key.daddr &&
-                        !(mutable->flags & TNL_F_IN_KEY_MATCH)) {
-               key_present = false;
-               key = 0;
-       }
-
-       tnl_tun_key_init(&tun_key, iph, key, key_present ? OVS_TNL_F_KEY : 0);
-       OVS_CB(skb)->tun_key = &tun_key;
-
-       ovs_tnl_rcv(vport, skb);
-       goto out;
-
-error:
-       kfree_skb(skb);
-out:
-       return 0;
-}
-
-static const struct tnl_ops capwap_tnl_ops = {
-       .tunnel_type    = TNL_T_PROTO_CAPWAP,
-       .ipproto        = IPPROTO_UDP,
-       .hdr_len        = capwap_hdr_len,
-       .build_header   = capwap_build_header,
-};
-
-static inline struct capwap_net *ovs_get_capwap_net(struct net *net)
-{
-       struct ovs_net *ovs_net = net_generic(net, ovs_net_id);
-       return &ovs_net->vport_net.capwap;
-}
-
-/* Arbitrary value.  Irrelevant as long as it's not 0 since we set the handler. */
-#define UDP_ENCAP_CAPWAP 10
-static int init_socket(struct net *net)
-{
-       int err;
-       struct capwap_net *capwap_net = ovs_get_capwap_net(net);
-       struct sockaddr_in sin;
-
-       if (capwap_net->n_tunnels) {
-               capwap_net->n_tunnels++;
-               return 0;
-       }
-
-       err = sock_create_kern(AF_INET, SOCK_DGRAM, 0,
-                              &capwap_net->capwap_rcv_socket);
-       if (err)
-               goto error;
-
-       /* release net ref. */
-       sk_change_net(capwap_net->capwap_rcv_socket->sk, net);
-
-       sin.sin_family = AF_INET;
-       sin.sin_addr.s_addr = htonl(INADDR_ANY);
-       sin.sin_port = htons(CAPWAP_DST_PORT);
-
-       err = kernel_bind(capwap_net->capwap_rcv_socket,
-                         (struct sockaddr *)&sin,
-                         sizeof(struct sockaddr_in));
-       if (err)
-               goto error_sock;
-
-       udp_sk(capwap_net->capwap_rcv_socket->sk)->encap_type = UDP_ENCAP_CAPWAP;
-       udp_sk(capwap_net->capwap_rcv_socket->sk)->encap_rcv = capwap_rcv;
-
-       capwap_net->frag_state.timeout          = CAPWAP_FRAG_TIMEOUT;
-       capwap_net->frag_state.high_thresh      = CAPWAP_FRAG_MAX_MEM;
-       capwap_net->frag_state.low_thresh       = CAPWAP_FRAG_PRUNE_MEM;
-
-       inet_frags_init_net(&capwap_net->frag_state);
-       udp_encap_enable();
-       capwap_net->n_tunnels++;
-       return 0;
-
-error_sock:
-       sk_release_kernel(capwap_net->capwap_rcv_socket->sk);
-error:
-       pr_warn("cannot register capwap protocol handler : %d\n", err);
-       return err;
-}
-
-static void release_socket(struct net *net)
-{
-       struct capwap_net *capwap_net = ovs_get_capwap_net(net);
-
-       capwap_net->n_tunnels--;
-       if (capwap_net->n_tunnels)
-               return;
-
-       inet_frags_exit_net(&capwap_net->frag_state, &frag_state);
-       sk_release_kernel(capwap_net->capwap_rcv_socket->sk);
-}
-
-static struct vport *capwap_create(const struct vport_parms *parms)
-{
-       struct vport *vport;
-       int err;
-
-       err = init_socket(ovs_dp_get_net(parms->dp));
-       if (err)
-               return ERR_PTR(err);
-
-       vport = ovs_tnl_create(parms, &ovs_capwap_vport_ops, &capwap_tnl_ops);
-       if (IS_ERR(vport))
-               release_socket(ovs_dp_get_net(parms->dp));
-
-       return vport;
-}
-
-static void capwap_destroy(struct vport *vport)
-{
-       ovs_tnl_destroy(vport);
-       release_socket(ovs_dp_get_net(vport->dp));
-}
-
-static int capwap_init(void)
-{
-       inet_frags_init(&frag_state);
-       return 0;
-}
-
-static void capwap_exit(void)
-{
-       inet_frags_fini(&frag_state);
-}
-
-static void copy_skb_metadata(struct sk_buff *from, struct sk_buff *to)
-{
-       to->pkt_type = from->pkt_type;
-       to->priority = from->priority;
-       to->protocol = from->protocol;
-       skb_dst_set(to, dst_clone(skb_dst(from)));
-       to->dev = from->dev;
-       to->mark = from->mark;
-
-       if (from->sk)
-               skb_set_owner_w(to, from->sk);
-
-#ifdef CONFIG_NET_SCHED
-       to->tc_index = from->tc_index;
-#endif
-#if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE)
-       to->ipvs_property = from->ipvs_property;
-#endif
-       skb_copy_secmark(to, from);
-}
-
-static struct sk_buff *fragment(struct sk_buff *skb, const struct vport *vport,
-                               struct dst_entry *dst, unsigned int hlen)
-{
-       struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
-       unsigned int headroom;
-       unsigned int max_frame_len = dst_mtu(dst) + skb_network_offset(skb);
-       struct sk_buff *result = NULL, *list_cur = NULL;
-       unsigned int remaining;
-       unsigned int offset;
-       __be16 frag_id;
-
-       if (hlen + ~FRAG_OFF_MASK + 1 > max_frame_len) {
-               if (net_ratelimit())
-                       pr_warn("capwap link mtu (%d) is less than minimum packet (%d)\n",
-                               dst_mtu(dst),
-                               hlen - skb_network_offset(skb) + ~FRAG_OFF_MASK + 1);
-               goto error;
-       }
-
-       remaining = skb->len - hlen;
-       offset = 0;
-       frag_id = htons(atomic_inc_return(&tnl_vport->frag_id));
-
-       headroom = dst->header_len + 16;
-       if (!skb_network_offset(skb))
-               headroom += LL_RESERVED_SPACE(dst->dev);
-
-       while (remaining) {
-               struct sk_buff *skb2;
-               int frag_size;
-               struct udphdr *udph;
-               struct capwaphdr *cwh;
-
-               frag_size = min(remaining, max_frame_len - hlen);
-               if (remaining > frag_size)
-                       frag_size &= FRAG_OFF_MASK;
-
-               skb2 = alloc_skb(headroom + hlen + frag_size, GFP_ATOMIC);
-               if (!skb2)
-                       goto error;
-
-               skb_reserve(skb2, headroom);
-               __skb_put(skb2, hlen + frag_size);
-
-               if (skb_network_offset(skb))
-                       skb_reset_mac_header(skb2);
-               skb_set_network_header(skb2, skb_network_offset(skb));
-               skb_set_transport_header(skb2, skb_transport_offset(skb));
-
-               /* Copy (Ethernet)/IP/UDP/CAPWAP header. */
-               copy_skb_metadata(skb, skb2);
-               skb_copy_from_linear_data(skb, skb2->data, hlen);
-
-               /* Copy this data chunk. */
-               if (skb_copy_bits(skb, hlen + offset, skb2->data + hlen, frag_size))
-                       BUG();
-
-               udph = udp_hdr(skb2);
-               udph->len = htons(skb2->len - skb_transport_offset(skb2));
-
-               cwh = capwap_hdr(skb2);
-               if (remaining > frag_size)
-                       cwh->begin |= FRAG_HDR;
-               else
-                       cwh->begin |= FRAG_LAST_HDR;
-               cwh->frag_id = frag_id;
-               cwh->frag_off = htons(offset);
-
-               if (result) {
-                       list_cur->next = skb2;
-                       list_cur = skb2;
-               } else
-                       result = list_cur = skb2;
-
-               offset += frag_size;
-               remaining -= frag_size;
-       }
-
-       consume_skb(skb);
-       return result;
-
-error:
-       ovs_tnl_free_linked_skbs(result);
-       kfree_skb(skb);
-       return NULL;
-}
-
-/* All of the following functions relate to fragmentation reassembly. */
-
-static struct frag_queue *ifq_cast(struct inet_frag_queue *ifq)
-{
-       return container_of(ifq, struct frag_queue, ifq);
-}
-
-static u32 frag_hash(struct frag_match *match)
-{
-       return jhash_3words((__force u16)match->id, (__force u32)match->saddr,
-                           (__force u32)match->daddr,
-                           frag_state.rnd) & (INETFRAGS_HASHSZ - 1);
-}
-
-static struct frag_queue *queue_find(struct netns_frags *ns_frag_state,
-                                    struct frag_match *match)
-{
-       struct inet_frag_queue *ifq;
-
-       read_lock(&frag_state.lock);
-
-       ifq = inet_frag_find(ns_frag_state, &frag_state, match, frag_hash(match));
-       if (!ifq)
-               return NULL;
-
-       /* Unlock happens inside inet_frag_find(). */
-
-       return ifq_cast(ifq);
-}
-
-static struct sk_buff *frag_reasm(struct frag_queue *fq, struct net_device *dev)
-{
-       struct sk_buff *head = fq->ifq.fragments;
-       struct sk_buff *frag;
-
-       /* Succeed or fail, we're done with this queue. */
-       inet_frag_kill(&fq->ifq, &frag_state);
-
-       if (fq->ifq.len > 65535)
-               return NULL;
-
-       /* Can't have the head be a clone. */
-       if (skb_cloned(head) && pskb_expand_head(head, 0, 0, GFP_ATOMIC))
-               return NULL;
-
-       /*
-        * We're about to build frag list for this SKB.  If it already has a
-        * frag list, alloc a new SKB and put the existing frag list there.
-        */
-       if (skb_shinfo(head)->frag_list) {
-               int i;
-               int paged_len = 0;
-
-               frag = alloc_skb(0, GFP_ATOMIC);
-               if (!frag)
-                       return NULL;
-
-               frag->next = head->next;
-               head->next = frag;
-               skb_shinfo(frag)->frag_list = skb_shinfo(head)->frag_list;
-               skb_shinfo(head)->frag_list = NULL;
-
-               for (i = 0; i < skb_shinfo(head)->nr_frags; i++)
-                       paged_len += skb_shinfo(head)->frags[i].size;
-               frag->len = frag->data_len = head->data_len - paged_len;
-               head->data_len -= frag->len;
-               head->len -= frag->len;
-
-               frag->ip_summed = head->ip_summed;
-               atomic_add(frag->truesize, &fq->ifq.net->mem);
-       }
-
-       skb_shinfo(head)->frag_list = head->next;
-       atomic_sub(head->truesize, &fq->ifq.net->mem);
-
-       /* Properly account for data in various packets. */
-       for (frag = head->next; frag; frag = frag->next) {
-               head->data_len += frag->len;
-               head->len += frag->len;
-
-               if (head->ip_summed != frag->ip_summed)
-                       head->ip_summed = CHECKSUM_NONE;
-               else if (head->ip_summed == CHECKSUM_COMPLETE)
-                       head->csum = csum_add(head->csum, frag->csum);
-
-               head->truesize += frag->truesize;
-               atomic_sub(frag->truesize, &fq->ifq.net->mem);
-       }
-
-       head->next = NULL;
-       head->dev = dev;
-       head->tstamp = fq->ifq.stamp;
-       fq->ifq.fragments = NULL;
-
-       return head;
-}
-
-static struct sk_buff *frag_queue(struct frag_queue *fq, struct sk_buff *skb,
-                                 u16 offset, bool frag_last)
-{
-       struct sk_buff *prev, *next;
-       struct net_device *dev;
-       int end;
-
-       if (fq->ifq.last_in & INET_FRAG_COMPLETE)
-               goto error;
-
-       if (!skb->len)
-               goto error;
-
-       end = offset + skb->len;
-
-       if (frag_last) {
-               /*
-                * Last fragment, shouldn't already have data past our end or
-                * have another last fragment.
-                */
-               if (end < fq->ifq.len || fq->ifq.last_in & INET_FRAG_LAST_IN)
-                       goto error;
-
-               fq->ifq.last_in |= INET_FRAG_LAST_IN;
-               fq->ifq.len = end;
-       } else {
-               /* Fragments should align to 8 byte chunks. */
-               if (end & ~FRAG_OFF_MASK)
-                       goto error;
-
-               if (end > fq->ifq.len) {
-                       /*
-                        * Shouldn't have data past the end, if we already
-                        * have one.
-                        */
-                       if (fq->ifq.last_in & INET_FRAG_LAST_IN)
-                               goto error;
-
-                       fq->ifq.len = end;
-               }
-       }
-
-       /* Find where we fit in. */
-       prev = NULL;
-       for (next = fq->ifq.fragments; next != NULL; next = next->next) {
-               if (FRAG_CB(next)->offset >= offset)
-                       break;
-               prev = next;
-       }
-
-       /*
-        * Overlapping fragments aren't allowed.  We shouldn't start before
-        * the end of the previous fragment.
-        */
-       if (prev && FRAG_CB(prev)->offset + prev->len > offset)
-               goto error;
-
-       /* We also shouldn't end after the beginning of the next fragment. */
-       if (next && end > FRAG_CB(next)->offset)
-               goto error;
-
-       FRAG_CB(skb)->offset = offset;
-
-       /* Link into list. */
-       skb->next = next;
-       if (prev)
-               prev->next = skb;
-       else
-               fq->ifq.fragments = skb;
-
-       dev = skb->dev;
-       skb->dev = NULL;
-
-       fq->ifq.stamp = skb->tstamp;
-       fq->ifq.meat += skb->len;
-       atomic_add(skb->truesize, &fq->ifq.net->mem);
-       if (offset == 0)
-               fq->ifq.last_in |= INET_FRAG_FIRST_IN;
-
-       /* If we have all fragments do reassembly. */
-       if (fq->ifq.last_in == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) &&
-           fq->ifq.meat == fq->ifq.len)
-               return frag_reasm(fq, dev);
-
-       write_lock(&frag_state.lock);
-       list_move_tail(&fq->ifq.lru_list, &fq->ifq.net->lru_list);
-       write_unlock(&frag_state.lock);
-
-       return NULL;
-
-error:
-       kfree_skb(skb);
-       return NULL;
-}
-
-static struct sk_buff *defrag(struct sk_buff *skb, bool frag_last)
-{
-       struct iphdr *iph = ip_hdr(skb);
-       struct capwaphdr *cwh = capwap_hdr(skb);
-       struct capwap_net *capwap_net = ovs_get_capwap_net(dev_net(skb->dev));
-       struct netns_frags *ns_frag_state = &capwap_net->frag_state;
-       struct frag_match match;
-       u16 frag_off;
-       struct frag_queue *fq;
-
-       inet_frag_evictor(ns_frag_state, &frag_state, false);
-
-       match.daddr = iph->daddr;
-       match.saddr = iph->saddr;
-       match.id = cwh->frag_id;
-       frag_off = ntohs(cwh->frag_off) & FRAG_OFF_MASK;
-
-       fq = queue_find(ns_frag_state, &match);
-       if (fq) {
-               spin_lock(&fq->ifq.lock);
-               skb = frag_queue(fq, skb, frag_off, frag_last);
-               spin_unlock(&fq->ifq.lock);
-
-               inet_frag_put(&fq->ifq, &frag_state);
-
-               return skb;
-       }
-
-       kfree_skb(skb);
-       return NULL;
-}
-
-static void capwap_frag_init(struct inet_frag_queue *ifq, void *match_)
-{
-       struct frag_match *match = match_;
-
-       ifq_cast(ifq)->match = *match;
-}
-
-static unsigned int capwap_frag_hash(struct inet_frag_queue *ifq)
-{
-       return frag_hash(&ifq_cast(ifq)->match);
-}
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)
-static int capwap_frag_match(struct inet_frag_queue *ifq, void *a_)
-#else
-static bool capwap_frag_match(struct inet_frag_queue *ifq, void *a_)
-#endif
-{
-       struct frag_match *a = a_;
-       struct frag_match *b = &ifq_cast(ifq)->match;
-
-       return a->id == b->id && a->saddr == b->saddr && a->daddr == b->daddr;
-}
-
-/* Run when the timeout for a given queue expires. */
-static void capwap_frag_expire(unsigned long ifq)
-{
-       struct frag_queue *fq;
-
-       fq = ifq_cast((struct inet_frag_queue *)ifq);
-
-       spin_lock(&fq->ifq.lock);
-
-       if (!(fq->ifq.last_in & INET_FRAG_COMPLETE))
-               inet_frag_kill(&fq->ifq, &frag_state);
-
-       spin_unlock(&fq->ifq.lock);
-       inet_frag_put(&fq->ifq, &frag_state);
-}
-
-const struct vport_ops ovs_capwap_vport_ops = {
-       .type           = OVS_VPORT_TYPE_CAPWAP,
-       .flags          = VPORT_F_TUN_ID,
-       .init           = capwap_init,
-       .exit           = capwap_exit,
-       .create         = capwap_create,
-       .destroy        = capwap_destroy,
-       .get_name       = ovs_tnl_get_name,
-       .get_options    = ovs_tnl_get_options,
-       .set_options    = ovs_tnl_set_options,
-       .send           = ovs_tnl_send,
-};
-#else
-#warning CAPWAP tunneling will not be available on kernels before 2.6.26
-#endif /* Linux kernel < 2.6.26 */
diff --git a/datapath/vport-capwap.h b/datapath/vport-capwap.h
deleted file mode 100644 (file)
index 5c0a6f8..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (c) 2012 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 VPORT_CAPWAP_H
-#define VPORT_CAPWAP_H 1
-
-#include <linux/net.h>
-
-struct capwap_net {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
-       struct socket *capwap_rcv_socket;
-       struct netns_frags frag_state;
-       int n_tunnels;
-#endif
-};
-
-#endif /* vport-capwap.h */
index 14c5ba3..680e7b3 100644 (file)
@@ -274,10 +274,8 @@ static int gre_rcv(struct sk_buff *skb)
        iph = ip_hdr(skb);
        vport = ovs_tnl_find_port(dev_net(skb->dev), iph->daddr, iph->saddr, key,
                                  tunnel_type, &mutable);
-       if (unlikely(!vport)) {
-               icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
+       if (unlikely(!vport))
                goto error;
-       }
 
        tnl_flags = gre_flags_to_tunnel_flags(mutable, gre_flags, &key);
        tnl_tun_key_init(&tun_key, iph, key, tnl_flags);
diff --git a/datapath/vport-lisp.c b/datapath/vport-lisp.c
new file mode 100644 (file)
index 0000000..0f01395
--- /dev/null
@@ -0,0 +1,488 @@
+/*
+ * Copyright (c) 2011 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
+ * 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/version.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
+
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/list.h>
+#include <linux/net.h>
+#include <linux/udp.h>
+
+#include <net/icmp.h>
+#include <net/ip.h>
+#include <net/udp.h>
+
+#include "datapath.h"
+#include "tunnel.h"
+#include "vport.h"
+
+
+/*
+ *  LISP encapsulation header:
+ *
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |N|L|E|V|I|flags|            Nonce/Map-Version                  |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |                 Instance ID/Locator Status Bits               |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ */
+
+/**
+ * struct lisphdr - LISP header
+ * @nonce_present: Flag indicating the presence of a 24 bit nonce value.
+ * @locator_status_bits_present: Flag indicating the presence of Locator Status
+ *                               Bits (LSB).
+ * @solicit_echo_nonce: Flag indicating the use of the echo noncing mechanism.
+ * @map_version_present: Flag indicating the use of mapping versioning.
+ * @instance_id_present: Flag indicating the presence of a 24 bit Instance ID.
+ * @reserved_flags: 3 bits reserved for future flags.
+ * @nonce: 24 bit nonce value.
+ * @map_version: 24 bit mapping version.
+ * @locator_status_bits: Locator Status Bits: 32 bits when instance_id_present
+ *                       is not set, 8 bits when it is.
+ * @instance_id: 24 bit Instance ID
+ */
+struct lisphdr {
+#ifdef __LITTLE_ENDIAN_BITFIELD
+       __u8 reserved_flags:3;
+       __u8 instance_id_present:1;
+       __u8 map_version_present:1;
+       __u8 solicit_echo_nonce:1;
+       __u8 locator_status_bits_present:1;
+       __u8 nonce_present:1;
+#else
+       __u8 nonce_present:1;
+       __u8 locator_status_bits_present:1;
+       __u8 solicit_echo_nonce:1;
+       __u8 map_version_present:1;
+       __u8 instance_id_present:1;
+       __u8 reserved_flags:3;
+#endif
+       union {
+               __u8 nonce[3];
+               __u8 map_version[3];
+       } u1;
+       union {
+               __be32 locator_status_bits;
+               struct {
+                       __u8 instance_id[3];
+                       __u8 locator_status_bits;
+               } word2;
+       } u2;
+};
+
+#define LISP_HLEN (sizeof(struct udphdr) + sizeof(struct lisphdr))
+
+static inline int lisp_hdr_len(const struct tnl_mutable_config *mutable,
+                              const struct ovs_key_ipv4_tunnel *tun_key)
+{
+       return LISP_HLEN;
+}
+
+/**
+ * struct lisp_port - Keeps track of open UDP ports
+ * @list: list element.
+ * @port: The UDP port number in network byte order.
+ * @socket: The socket created for this port number.
+ * @count: How many ports are using this socket/port.
+ */
+struct lisp_port {
+       struct list_head list;
+       __be16 port;
+       struct socket *lisp_rcv_socket;
+       int count;
+};
+
+static LIST_HEAD(lisp_ports);
+
+static struct lisp_port *lisp_port_exists(struct net *net, __be16 port)
+{
+       struct lisp_port *lisp_port;
+
+       list_for_each_entry(lisp_port, &lisp_ports, list) {
+               if (lisp_port->port == port &&
+                       net_eq(sock_net(lisp_port->lisp_rcv_socket->sk), net))
+                       return lisp_port;
+       }
+
+       return NULL;
+}
+
+static inline struct lisphdr *lisp_hdr(const struct sk_buff *skb)
+{
+       return (struct lisphdr *)(udp_hdr(skb) + 1);
+}
+
+static int lisp_tnl_send(struct vport *vport, struct sk_buff *skb)
+{
+       int tnl_len;
+       int network_offset = skb_network_offset(skb);
+
+       /* We only encapsulate IPv4 and IPv6 packets */
+       switch (skb->protocol) {
+       case htons(ETH_P_IP):
+       case htons(ETH_P_IPV6):
+               /* Pop off "inner" Ethernet header */
+               skb_pull(skb, network_offset);
+               tnl_len = ovs_tnl_send(vport, skb);
+               return tnl_len > 0 ? tnl_len + network_offset : tnl_len;
+       default:
+               kfree_skb(skb);
+               return 0;
+       }
+}
+
+/* Convert 64 bit tunnel ID to 24 bit Instance ID. */
+static void tunnel_id_to_instance_id(__be64 tun_id, __u8 *iid)
+{
+
+#ifdef __BIG_ENDIAN
+       iid[0] = (__force __u8)(tun_id >> 16);
+       iid[1] = (__force __u8)(tun_id >> 8);
+       iid[2] = (__force __u8)tun_id;
+#else
+       iid[0] = (__force __u8)((__force u64)tun_id >> 40);
+       iid[1] = (__force __u8)((__force u64)tun_id >> 48);
+       iid[2] = (__force __u8)((__force u64)tun_id >> 56);
+#endif
+}
+
+/* Convert 24 bit Instance ID to 64 bit tunnel ID. */
+static __be64 instance_id_to_tunnel_id(__u8 *iid)
+{
+#ifdef __BIG_ENDIAN
+       return (iid[0] << 16) | (iid[1] << 8) | iid[2];
+#else
+       return (__force __be64)(((__force u64)iid[0] << 40) |
+                               ((__force u64)iid[1] << 48) |
+                               ((__force u64)iid[2] << 56));
+#endif
+}
+
+static struct sk_buff *lisp_build_header(const struct vport *vport,
+                                        const struct tnl_mutable_config *mutable,
+                                        struct dst_entry *dst,
+                                        struct sk_buff *skb,
+                                        int tunnel_hlen)
+{
+       struct udphdr *udph = udp_hdr(skb);
+       struct lisphdr *lisph = (struct lisphdr *)(udph + 1);
+       const struct ovs_key_ipv4_tunnel *tun_key = OVS_CB(skb)->tun_key;
+       __be64 out_key;
+       u32 flags;
+
+       tnl_get_param(mutable, tun_key, &flags, &out_key);
+
+       udph->dest = mutable->dst_port;
+       udph->source = htons(ovs_tnl_get_src_port(skb));
+       udph->check = 0;
+       udph->len = htons(skb->len - skb_transport_offset(skb));
+
+       lisph->nonce_present = 0;       /* We don't support echo nonce algorithm */
+       lisph->locator_status_bits_present = 1; /* Set LSB */
+       lisph->solicit_echo_nonce = 0;  /* No echo noncing */
+       lisph->map_version_present = 0; /* No mapping versioning, nonce instead */
+       lisph->instance_id_present = 1; /* Store the tun_id as Instance ID  */
+       lisph->reserved_flags = 0;      /* Reserved flags, set to 0  */
+
+       lisph->u1.nonce[0] = 0;
+       lisph->u1.nonce[1] = 0;
+       lisph->u1.nonce[2] = 0;
+
+       tunnel_id_to_instance_id(out_key, &lisph->u2.word2.instance_id[0]);
+       lisph->u2.word2.locator_status_bits = 1;
+
+       /*
+        * Allow our local IP stack to fragment the outer packet even if the
+        * DF bit is set as a last resort.  We also need to force selection of
+        * an IP ID here because Linux will otherwise leave it at 0 if the
+        * packet originally had DF set.
+        */
+       skb->local_df = 1;
+       __ip_select_ident(ip_hdr(skb), dst, 0);
+
+       return skb;
+}
+
+/* Called with rcu_read_lock and BH disabled. */
+static int lisp_rcv(struct sock *sk, struct sk_buff *skb)
+{
+       struct vport *vport;
+       struct lisphdr *lisph;
+       const struct tnl_mutable_config *mutable;
+       struct iphdr *iph, *inner_iph;
+       struct ovs_key_ipv4_tunnel tun_key;
+       __be64 key;
+       u32 tunnel_flags = 0;
+       struct ethhdr *ethh;
+       __be16 protocol;
+
+       if (unlikely(!pskb_may_pull(skb, LISP_HLEN)))
+               goto error;
+
+       lisph = lisp_hdr(skb);
+
+       skb_pull_rcsum(skb, LISP_HLEN);
+
+       if (lisph->instance_id_present != 1)
+               key = 0;
+       else
+               key = instance_id_to_tunnel_id(&lisph->u2.word2.instance_id[0]);
+
+       iph = ip_hdr(skb);
+       vport = ovs_tnl_find_port(dev_net(skb->dev), iph->daddr, iph->saddr,
+               key, TNL_T_PROTO_LISP, &mutable);
+       if (unlikely(!vport))
+               goto error;
+
+       if (mutable->flags & TNL_F_IN_KEY_MATCH || !mutable->key.daddr)
+               tunnel_flags = OVS_TNL_F_KEY;
+       else
+               key = 0;
+
+       /* Save outer tunnel values */
+       tnl_tun_key_init(&tun_key, iph, key, tunnel_flags);
+       OVS_CB(skb)->tun_key = &tun_key;
+
+       /* Drop non-IP inner packets */
+       inner_iph = (struct iphdr *)(lisph + 1);
+       switch (inner_iph->version) {
+       case 4:
+               protocol = htons(ETH_P_IP);
+               break;
+       case 6:
+               protocol = htons(ETH_P_IPV6);
+               break;
+       default:
+               goto error;
+       }
+
+       /* Add Ethernet header */
+       ethh = (struct ethhdr *)skb_push(skb, ETH_HLEN);
+       memset(ethh, 0, ETH_HLEN);
+       ethh->h_dest[0] = 0x02;
+       ethh->h_source[0] = 0x02;
+       ethh->h_proto = protocol;
+
+       ovs_tnl_rcv(vport, skb);
+       goto out;
+
+error:
+       kfree_skb(skb);
+out:
+       return 0;
+}
+
+/* Arbitrary value.  Irrelevant as long as it's not 0 since we set the handler. */
+#define UDP_ENCAP_LISP 1
+static int lisp_socket_init(struct lisp_port *lisp_port, struct net *net)
+{
+       int err;
+       struct sockaddr_in sin;
+
+       err = sock_create_kern(AF_INET, SOCK_DGRAM, 0,
+                              &lisp_port->lisp_rcv_socket);
+       if (err)
+               goto error;
+
+       /* release net ref. */
+       sk_change_net(lisp_port->lisp_rcv_socket->sk, net);
+
+       sin.sin_family = AF_INET;
+       sin.sin_addr.s_addr = htonl(INADDR_ANY);
+       sin.sin_port = lisp_port->port;
+
+       err = kernel_bind(lisp_port->lisp_rcv_socket, (struct sockaddr *)&sin,
+                         sizeof(struct sockaddr_in));
+       if (err)
+               goto error_sock;
+
+       udp_sk(lisp_port->lisp_rcv_socket->sk)->encap_type = UDP_ENCAP_LISP;
+       udp_sk(lisp_port->lisp_rcv_socket->sk)->encap_rcv = lisp_rcv;
+
+       udp_encap_enable();
+
+       return 0;
+
+error_sock:
+       sk_release_kernel(lisp_port->lisp_rcv_socket->sk);
+error:
+       pr_warn("cannot register lisp protocol handler: %d\n", err);
+       return err;
+}
+
+static void lisp_tunnel_release(struct lisp_port *lisp_port)
+{
+       lisp_port->count--;
+
+       if (lisp_port->count == 0) {
+               /* Release old socket */
+               sk_release_kernel(lisp_port->lisp_rcv_socket->sk);
+               list_del(&lisp_port->list);
+               kfree(lisp_port);
+       }
+}
+
+static int lisp_tunnel_setup(struct net *net, struct nlattr *options,
+                            struct lisp_port **lport)
+{
+       struct nlattr *a;
+       int err;
+       u16 dst_port;
+       struct lisp_port *lisp_port = NULL;
+
+       *lport = NULL;
+
+       if (!options) {
+               err = -EINVAL;
+               goto out;
+       }
+
+       a = nla_find_nested(options, OVS_TUNNEL_ATTR_DST_PORT);
+       if (a && nla_len(a) == sizeof(u16)) {
+               dst_port = nla_get_u16(a);
+       } else {
+               /* Require destination port from userspace. */
+               err = -EINVAL;
+               goto out;
+       }
+
+       /* Verify if we already have a socket created for this port */
+       lisp_port = lisp_port_exists(net, htons(dst_port));
+       if (lisp_port) {
+               lisp_port->count++;
+               err = 0;
+               *lport = lisp_port;
+               goto out;
+       }
+
+       /* Add a new socket for this port */
+       lisp_port = kzalloc(sizeof(struct lisp_port), GFP_KERNEL);
+       if (!lisp_port) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       lisp_port->port = htons(dst_port);
+       lisp_port->count = 1;
+       list_add_tail(&lisp_port->list, &lisp_ports);
+
+       err = lisp_socket_init(lisp_port, net);
+       if (err)
+               goto error;
+
+       *lport = lisp_port;
+       goto out;
+
+error:
+       list_del(&lisp_port->list);
+       kfree(lisp_port);
+out:
+       return err;
+}
+
+static int lisp_tnl_set_options(struct vport *vport, struct nlattr *options)
+{
+       int err;
+       struct net *net = ovs_dp_get_net(vport->dp);
+       struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
+       struct tnl_mutable_config *config;
+       struct lisp_port *old_port = NULL;
+       struct lisp_port *lisp_port = NULL;
+
+       config = rtnl_dereference(tnl_vport->mutable);
+
+       old_port = lisp_port_exists(net, config->dst_port);
+
+       err = lisp_tunnel_setup(net, options, &lisp_port);
+       if (err)
+               goto out;
+
+       err = ovs_tnl_set_options(vport, options);
+
+       if (err)
+               lisp_tunnel_release(lisp_port);
+       else {
+               /* Release old socket */
+               lisp_tunnel_release(old_port);
+       }
+out:
+       return err;
+}
+
+static const struct tnl_ops ovs_lisp_tnl_ops = {
+       .tunnel_type    = TNL_T_PROTO_LISP,
+       .ipproto        = IPPROTO_UDP,
+       .hdr_len        = lisp_hdr_len,
+       .build_header   = lisp_build_header,
+};
+
+static void lisp_tnl_destroy(struct vport *vport)
+{
+       struct lisp_port *lisp_port;
+       struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
+       struct tnl_mutable_config *config;
+
+       config = rtnl_dereference(tnl_vport->mutable);
+
+       lisp_port = lisp_port_exists(ovs_dp_get_net(vport->dp),
+                                    config->dst_port);
+
+       lisp_tunnel_release(lisp_port);
+
+       ovs_tnl_destroy(vport);
+}
+
+static struct vport *lisp_tnl_create(const struct vport_parms *parms)
+{
+       int err;
+       struct vport *vport;
+       struct lisp_port *lisp_port = NULL;
+
+       err = lisp_tunnel_setup(ovs_dp_get_net(parms->dp), parms->options,
+                               &lisp_port);
+       if (err)
+               return ERR_PTR(err);
+
+       vport = ovs_tnl_create(parms, &ovs_lisp_vport_ops, &ovs_lisp_tnl_ops);
+
+       if (IS_ERR(vport))
+               lisp_tunnel_release(lisp_port);
+
+       return vport;
+}
+
+const struct vport_ops ovs_lisp_vport_ops = {
+       .type           = OVS_VPORT_TYPE_LISP,
+       .flags          = VPORT_F_TUN_ID,
+       .create         = lisp_tnl_create,
+       .destroy        = lisp_tnl_destroy,
+       .get_name       = ovs_tnl_get_name,
+       .get_options    = ovs_tnl_get_options,
+       .set_options    = lisp_tnl_set_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 4f9f339..388d9fb 100644 (file)
@@ -90,21 +90,6 @@ static inline struct vxlanhdr *vxlan_hdr(const struct sk_buff *skb)
        return (struct vxlanhdr *)(udp_hdr(skb) + 1);
 }
 
-/* Compute source port for outgoing packet.
- * Currently we use the flow hash.
- */
-static u16 get_src_port(struct sk_buff *skb)
-{
-       int low;
-       int high;
-       unsigned int range;
-       u32 hash = OVS_CB(skb)->flow->hash;
-
-        inet_get_local_port_range(&low, &high);
-        range = (high - low) + 1;
-       return (((u64) hash * range) >> 32) + low;
-}
-
 static struct sk_buff *vxlan_build_header(const struct vport *vport,
                                          const struct tnl_mutable_config *mutable,
                                          struct dst_entry *dst,
@@ -120,7 +105,7 @@ static struct sk_buff *vxlan_build_header(const struct vport *vport,
        tnl_get_param(mutable, tun_key, &flags, &out_key);
 
        udph->dest = mutable->dst_port;
-       udph->source = htons(get_src_port(skb));
+       udph->source = htons(ovs_tnl_get_src_port(skb));
        udph->check = 0;
        udph->len = htons(skb->len - skb_transport_offset(skb));
 
@@ -166,10 +151,8 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
        iph = ip_hdr(skb);
        vport = ovs_tnl_find_port(dev_net(skb->dev), iph->daddr, iph->saddr,
                key, TNL_T_PROTO_VXLAN, &mutable);
-       if (unlikely(!vport)) {
-               icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
+       if (unlikely(!vport))
                goto error;
-       }
 
        if (mutable->flags & TNL_F_IN_KEY_MATCH || !mutable->key.daddr)
                tunnel_flags = OVS_TNL_F_KEY;
index 9c0942b..0a0835e 100644 (file)
@@ -42,8 +42,8 @@ static const struct vport_ops *base_vport_ops_list[] = {
        &ovs_gre_vport_ops,
        &ovs_gre64_vport_ops,
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
-       &ovs_capwap_vport_ops,
        &ovs_vxlan_vport_ops,
+       &ovs_lisp_vport_ops,
 #endif
 };
 
index ed089a9..94c9e97 100644 (file)
 #include <linux/spinlock.h>
 #include <linux/u64_stats_sync.h>
 
-#include "vport-capwap.h"
-
 struct vport;
 struct vport_parms;
 
-struct vport_net {
-       struct capwap_net capwap;
-};
-
 /* The following definitions are for users of the vport subsytem: */
 
 int ovs_vport_init(void);
@@ -230,7 +224,7 @@ extern const struct vport_ops ovs_netdev_vport_ops;
 extern const struct vport_ops ovs_internal_vport_ops;
 extern const struct vport_ops ovs_gre_vport_ops;
 extern const struct vport_ops ovs_gre64_vport_ops;
-extern const struct vport_ops ovs_capwap_vport_ops;
 extern const struct vport_ops ovs_vxlan_vport_ops;
+extern const struct vport_ops ovs_lisp_vport_ops;
 
 #endif /* vport.h */
index d3a8faf..7bab3e0 100644 (file)
@@ -1,16 +1,69 @@
-openvswitch (1.9.90-1) unstable; urgency=low
+openvswitch (1.10.90-1) unstable; urgency=low
    [ Open vSwitch team ]
    * New upstream version
-    - Nothing yet!  Try NEWS...
+     - Nothing yet!  Try NEWS...
 
- -- Open vSwitch team <dev@openvswitch.org>  Wed, 24 Oct 2012 16:12:57 -0700
+ -- Open vSwitch team <dev@openvswitch.org>  Mon, 04 Feb 2013 21:52:34 -0700
+
+openvswitch (1.10.0-1) unstable; urgency=low
+   [ Open vSwitch team ]
+   * New upstream version
+    - Bridge compatibility support has been removed.  Any uses that
+      rely on ovs-brcompatd will have to stick with Open vSwitch 1.9.x
+      or adapt to native Open vSwitch support (e.g. use ovs-vsctl instead
+      of brctl).
+    - The maximum size of the MAC learning table is now configurable.
+    - With the Linux datapath, packets for new flows are now queued
+      separately on a per-port basis, so it should no longer be
+      possible for a large number of new flows arriving on one port to
+      prevent new flows from being processed on other ports.
+    - Many "ovs-vsctl" database commands now accept an --if-exists option.
+      Please refer to the ovs-vsctl manpage for details.
+    - OpenFlow:
+      - Experimental support for newer versions of OpenFlow.  See
+        the "What versions of OpenFlow does Open vSwitch support?"
+        question in the FAQ for more details.
+      - The OpenFlow "dp_desc" may now be configured by setting the
+        value of other-config:dp-desc in the Bridge table.
+      - It is possible to request the OpenFlow port number with the
+        "ofport_request" column in the Interface table.
+    - Tunneling:
+      - New support for the VXLAN tunnel protocol (see the IETF draft here:
+        http://tools.ietf.org/html/draft-mahalingam-dutt-dcops-vxlan-03).
+      - Tunneling requires the version of the kernel module paired with
+        Open vSwitch 1.9.0 or later.
+      - Inheritance of the Don't Fragment bit in IP tunnels (df_inherit)
+        is no longer supported.
+      - Path MTU discovery is no longer supported.
+    - ovs-dpctl:
+      - The "dump-flows" and "del-flows" no longer require an argument
+        if only one datapath exists.
+    - ovs-appctl:
+      - New "vlog/disable-rate-limit" and "vlog/enable-rate-limit"
+        commands available allow control over logging rate limits.
+      - New "dpif/dump-dps", "dpif/show", and "dpif/dump-flows" command
+        that mimic the equivalent ovs-dpctl commands.
+    - The ofproto library is now responsible for assigning OpenFlow port
+      numbers.  An ofproto implementation should assign them when
+      port_construct() is called.
+    - All dpif-based bridges of a particular type share a common
+      datapath called "ovs-<type>", e.g. "ovs-system".  The ovs-dpctl
+      commands will now return information on that shared datapath.  To
+      get the equivalent bridge-specific information, use the new
+      "ovs-appctl dpif/*" commands.
+    - Backward-incompatible changes:
+      - Earlier Open vSwitch versions treated ANY as a wildcard in flow
+        syntax.  OpenFlow 1.1 adds a port named ANY, which introduces a
+        conflict.  ANY was rarely used in flow syntax, so we chose to
+        retire that meaning of ANY in favor of the OpenFlow 1.1 meaning.
+    - Patch ports no longer require kernel support, so they now work
+      with FreeBSD and the kernel module built into Linux 3.3 and later.
+
+ -- Open vSwitch team <dev@openvswitch.org>  Mon, 04 Feb 2013 21:52:34 -0700
 
 openvswitch (1.9.0-1) unstable; urgency=low
    [ Open vSwitch team ]
    * New upstream version
-    - The tunneling code no longer assumes input and output keys are symmetric.
-      If they are not, PMTUD needs to be disabled for tunneling to work. Note
-      this only applies to flow-based keys.
     - Datapath:
       - Support for ipv6 set action.
       - SKB mark matching and setting.
@@ -25,6 +78,14 @@ openvswitch (1.9.0-1) unstable; urgency=low
       - Allow bitwise masking for SHA and THA fields in ARP, SLL and TLL
         fields in IPv6 neighbor discovery messages, and IPv6 flow label.
       - Adds support for writing to the metadata field for a flow.
+    - Tunneling:
+      - The tunneling code no longer assumes input and output keys are
+        symmetric.  If they are not, PMTUD needs to be disabled for
+        tunneling to work. Note this only applies to flow-based keys.
+      - New support for a nonstandard form of GRE that supports a 64-bit key.
+      - Tunnel Path MTU Discovery default value was set to 'disabled'.
+        This feature is deprecated and will be removed soon.
+      - Tunnel header caching removed.
     - ovs-ofctl:
       - Commands and actions that accept port numbers now also accept keywords
         that represent those ports (such as LOCAL, NONE, and ALL).  This is
@@ -40,12 +101,8 @@ openvswitch (1.9.0-1) unstable; urgency=low
       are true, but because we do not know of any users for this
       feature it seems better on balance to remove it.  (The ovs-pki-cgi
       program was not included in distribution packaging.)
-    - Tunnel Path MTU Discovery default value was set to 'disabled'.  This
-      feature is deprecated and will be removed soon.
     - ovsdb-server now enforces the immutability of immutable columns.  This
       was not enforced in earlier versions due to an oversight.
-    - New support for a nonstandard form of GRE that supports a 64-bit key.
-    - Tunnel header caching removed.
     - The following features are now deprecated.  They will be removed no
       earlier than February 2013.  Please email dev@openvswitch.org with
       concerns.
index ae88be2..acf47b9 100644 (file)
@@ -142,7 +142,6 @@ Depends:
  ${shlibs:Depends}, ${misc:Depends},
  openvswitch-common (= ${binary:Version}),
  openvswitch-controller (= ${binary:Version}),
- openvswitch-ipsec (= ${binary:Version}),
  openvswitch-switch (= ${binary:Version})
 Description: Debug symbols for Open vSwitch packages
  Open vSwitch is a production quality, multilayer, software-based, Ethernet
index b12bf0c..63d1cac 100644 (file)
@@ -148,7 +148,8 @@ enum ovs_packet_cmd {
  * for %OVS_PACKET_CMD_EXECUTE.  It has nested %OVS_ACTION_ATTR_* attributes.
  * @OVS_PACKET_ATTR_USERDATA: Present for an %OVS_PACKET_CMD_ACTION
  * notification if the %OVS_ACTION_ATTR_USERSPACE action specified an
- * %OVS_USERSPACE_ATTR_USERDATA attribute.
+ * %OVS_USERSPACE_ATTR_USERDATA attribute, with the same length and content
+ * specified there.
  *
  * These attributes follow the &struct ovs_header within the Generic Netlink
  * payload for %OVS_PACKET_* commands.
@@ -158,7 +159,7 @@ enum ovs_packet_attr {
        OVS_PACKET_ATTR_PACKET,      /* Packet data. */
        OVS_PACKET_ATTR_KEY,         /* Nested OVS_KEY_ATTR_* attributes. */
        OVS_PACKET_ATTR_ACTIONS,     /* Nested OVS_ACTION_ATTR_* attributes. */
-       OVS_PACKET_ATTR_USERDATA,    /* u64 OVS_ACTION_ATTR_USERSPACE arg. */
+       OVS_PACKET_ATTR_USERDATA,    /* OVS_ACTION_ATTR_USERSPACE arg. */
        __OVS_PACKET_ATTR_MAX
 };
 
@@ -184,8 +185,8 @@ enum ovs_vport_type {
        OVS_VPORT_TYPE_INTERNAL, /* network device implemented by datapath */
        OVS_VPORT_TYPE_GRE,      /* GRE tunnel. */
        OVS_VPORT_TYPE_VXLAN,    /* VXLAN tunnel */
-       OVS_VPORT_TYPE_CAPWAP = 102,  /* CAPWAP tunnel */
        OVS_VPORT_TYPE_GRE64 = 104, /* GRE tunnel with 64-bit keys */
+       OVS_VPORT_TYPE_LISP = 105,  /* LISP tunnel */
        __OVS_VPORT_TYPE_MAX
 };
 
@@ -283,6 +284,8 @@ enum ovs_key_attr {
 #ifdef __KERNEL__
        OVS_KEY_ATTR_IPV4_TUNNEL,  /* struct ovs_key_ipv4_tunnel */
 #endif
+
+       OVS_KEY_ATTR_MPLS = 62, /* struct ovs_key_mpls */
        OVS_KEY_ATTR_TUN_ID = 63,  /* be64 tunnel ID */
        __OVS_KEY_ATTR_MAX
 };
@@ -325,6 +328,10 @@ struct ovs_key_ethernet {
        __u8     eth_dst[6];
 };
 
+struct ovs_key_mpls {
+       __be32 mpls_top_lse;
+};
+
 struct ovs_key_ipv4 {
        __be32 ipv4_src;
        __be32 ipv4_dst;
@@ -442,18 +449,31 @@ enum ovs_sample_attr {
  * enum ovs_userspace_attr - Attributes for %OVS_ACTION_ATTR_USERSPACE action.
  * @OVS_USERSPACE_ATTR_PID: u32 Netlink PID to which the %OVS_PACKET_CMD_ACTION
  * message should be sent.  Required.
- * @OVS_USERSPACE_ATTR_USERDATA: If present, its u64 argument is copied to the
- * %OVS_PACKET_CMD_ACTION message as %OVS_PACKET_ATTR_USERDATA,
+ * @OVS_USERSPACE_ATTR_USERDATA: If present, its variable-length argument is
+ * copied to the %OVS_PACKET_CMD_ACTION message as %OVS_PACKET_ATTR_USERDATA.
  */
 enum ovs_userspace_attr {
        OVS_USERSPACE_ATTR_UNSPEC,
        OVS_USERSPACE_ATTR_PID,       /* u32 Netlink PID to receive upcalls. */
-       OVS_USERSPACE_ATTR_USERDATA,  /* u64 optional user-specified cookie. */
+       OVS_USERSPACE_ATTR_USERDATA,  /* Optional user-specified cookie. */
        __OVS_USERSPACE_ATTR_MAX
 };
 
 #define OVS_USERSPACE_ATTR_MAX (__OVS_USERSPACE_ATTR_MAX - 1)
 
+/**
+ * struct ovs_action_push_mpls - %OVS_ACTION_ATTR_PUSH_MPLS action argument.
+ * @mpls_lse: MPLS label stack entry to push.
+ * @mpls_ethertype: Ethertype to set in the encapsulating ethernet frame.
+ *
+ * The only values @mpls_ethertype should ever be given are %ETH_P_MPLS_UC and
+ * %ETH_P_MPLS_MC, indicating MPLS unicast or multicast. Other are rejected.
+ */
+struct ovs_action_push_mpls {
+       __be32 mpls_lse;
+       __be16 mpls_ethertype; /* Either %ETH_P_MPLS_UC or %ETH_P_MPLS_MC */
+};
+
 /**
  * struct ovs_action_push_vlan - %OVS_ACTION_ATTR_PUSH_VLAN action argument.
  * @vlan_tpid: Tag protocol identifier (TPID) to push.
@@ -476,14 +496,23 @@ struct ovs_action_push_vlan {
  * @OVS_ACTION_ATTR_OUTPUT: Output packet to port.
  * @OVS_ACTION_ATTR_USERSPACE: Send packet to userspace according to nested
  * %OVS_USERSPACE_ATTR_* attributes.
- * @OVS_ACTION_ATTR_SET: Replaces the contents of an existing header.  The
- * single nested %OVS_KEY_ATTR_* attribute specifies a header to modify and its
- * value.
  * @OVS_ACTION_ATTR_PUSH_VLAN: Push a new outermost 802.1Q header onto the
  * packet.
  * @OVS_ACTION_ATTR_POP_VLAN: Pop the outermost 802.1Q header off the packet.
  * @OVS_ACTION_ATTR_SAMPLE: Probabilitically executes actions, as specified in
  * the nested %OVS_SAMPLE_ATTR_* attributes.
+ * @OVS_ACTION_ATTR_SET: Replaces the contents of an existing header.  The
+ * single nested %OVS_KEY_ATTR_* attribute specifies a header to modify and its
+ * value.
+ * @OVS_ACTION_ATTR_PUSH_MPLS: Push a new MPLS label stack entry onto the
+ * top of the packets MPLS label stack. Set the ethertype of the
+ * encapsulating frame to either %ETH_P_MPLS_UC or %ETH_P_MPLS_MC to
+ * indicate the new packet contents.
+ * @OVS_ACTION_ATTR_POP_MPLS: Pop an MPLS label stack entry off of the
+ * packet's MPLS label stack.  Set the encapsulating frame's ethertype to
+ * indicate the new packet contents This could potentially still be
+ * %ETH_P_MPLS_* if the resulting MPLS label stack is not empty.  If there
+ * is no MPLS label stack, as determined by ethertype, no action is taken.
  *
  * Only a single header can be set with a single %OVS_ACTION_ATTR_SET.  Not all
  * fields within a header are modifiable, e.g. the IPv4 protocol and fragment
@@ -498,6 +527,8 @@ enum ovs_action_attr {
        OVS_ACTION_ATTR_PUSH_VLAN,    /* struct ovs_action_push_vlan. */
        OVS_ACTION_ATTR_POP_VLAN,     /* No argument. */
        OVS_ACTION_ATTR_SAMPLE,       /* Nested OVS_SAMPLE_ATTR_*. */
+       OVS_ACTION_ATTR_PUSH_MPLS,    /* struct ovs_action_push_mpls. */
+       OVS_ACTION_ATTR_POP_MPLS,     /* __be16 ethertype. */
        __OVS_ACTION_ATTR_MAX
 };
 
index 91c96b3..c4ff904 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 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.
@@ -292,7 +292,7 @@ enum nx_action_subtype {
     NXAST_NOTE,                 /* struct nx_action_note */
     NXAST_SET_TUNNEL64,         /* struct nx_action_set_tunnel64 */
     NXAST_MULTIPATH,            /* struct nx_action_multipath */
-    NXAST_AUTOPATH__DEPRECATED, /* struct nx_action_autopath */
+    NXAST_AUTOPATH__OBSOLETE,   /* No longer used. */
     NXAST_BUNDLE,               /* struct nx_action_bundle */
     NXAST_BUNDLE_LOAD,          /* struct nx_action_bundle */
     NXAST_RESUBMIT_TABLE,       /* struct nx_action_resubmit */
@@ -304,6 +304,8 @@ enum nx_action_subtype {
     NXAST_CONTROLLER,           /* struct nx_action_controller */
     NXAST_DEC_TTL_CNT_IDS,      /* struct nx_action_cnt_ids */
     NXAST_WRITE_METADATA,       /* struct nx_action_write_metadata */
+    NXAST_PUSH_MPLS,            /* struct nx_action_push_mpls */
+    NXAST_POP_MPLS,             /* struct nx_action_pop_mpls */
 };
 
 /* Header for Nicira-defined actions. */
@@ -942,50 +944,6 @@ struct nx_action_fin_timeout {
 };
 OFP_ASSERT(sizeof(struct nx_action_fin_timeout) == 16);
 \f
-/* Action structure for NXAST_AUTOPATH.
- *
- * This action performs the following steps in sequence:
- *
- *    1. Hashes the flow using an implementation-defined hash function.
- *
- *       The hashed fields' values are drawn from the current state of the
- *       flow, including all modifications that have been made by actions up to
- *       this point.
- *
- *    2. Selects an OpenFlow 'port'.
- *
- *       'port' is selected in an implementation-defined manner, taking into
- *       account 'id' and the hash value calculated in step 1.
- *
- *       Generally a switch will have been configured with a set of ports that
- *       may be chosen given 'id'.  The switch may take into account any number
- *       of factors when choosing 'port' from its configured set.  Factors may
- *       include carrier, load, and the results of configuration protocols such
- *       as LACP.
- *
- *    3. Stores 'port' in dst[ofs:ofs+n_bits].
- *
- *       The format and semantics of 'dst' and 'ofs_nbits' are similar to those
- *       for the NXAST_REG_LOAD action.
- *
- * The switch will reject actions in which ofs+n_bits is greater than the width
- * of 'dst', with error type OFPET_BAD_ACTION, code OFPBAC_BAD_ARGUMENT.
- */
-struct nx_action_autopath {
-    ovs_be16 type;              /* OFPAT_VENDOR. */
-    ovs_be16 len;               /* Length is 24. */
-    ovs_be32 vendor;            /* NX_VENDOR_ID. */
-    ovs_be16 subtype;           /* NXAST_AUTOPATH. */
-
-    /* Where to store the result. */
-    ovs_be16 ofs_nbits;         /* (ofs << 6) | (n_bits - 1). */
-    ovs_be32 dst;               /* Destination. */
-
-    ovs_be32 id;                /* Autopath ID. */
-    ovs_be32 pad;
-};
-OFP_ASSERT(sizeof(struct nx_action_autopath) == 24);
-\f
 /* Action structure for NXAST_BUNDLE and NXAST_BUNDLE_LOAD.
  *
  * The bundle actions choose a slave from a supplied list of options.
@@ -1579,9 +1537,9 @@ OFP_ASSERT(sizeof(struct nx_action_output_reg) == 24);
 
 /* Tunnel ID.
  *
- * For a packet received via a GRE or VXLAN tunnel including a (32-bit) key, the
- * key is stored in the low 32-bits and the high bits are zeroed.  For other
- * packets, the value is 0.
+ * For a packet received via a GRE, VXLAN or LISP tunnel including a (32-bit)
+ * key, the key is stored in the low 32-bits and the high bits are zeroed.  For
+ * other packets, the value is 0.
  *
  * All zero bits, for packets not received via a keyed tunnel.
  *
@@ -2212,4 +2170,26 @@ struct nx_action_write_metadata {
 };
 OFP_ASSERT(sizeof(struct nx_action_write_metadata) == 32);
 
+/* Action structure for NXAST_PUSH_MPLS. */
+struct nx_action_push_mpls {
+    ovs_be16 type;                  /* OFPAT_VENDOR. */
+    ovs_be16 len;                   /* Length is 8. */
+    ovs_be32 vendor;                /* NX_VENDOR_ID. */
+    ovs_be16 subtype;               /* NXAST_PUSH_MPLS. */
+    ovs_be16 ethertype;             /* Ethertype */
+    uint8_t  pad[4];
+};
+OFP_ASSERT(sizeof(struct nx_action_push_mpls) == 16);
+
+/* Action structure for NXAST_POP_MPLS. */
+struct nx_action_pop_mpls {
+    ovs_be16 type;                  /* OFPAT_VENDOR. */
+    ovs_be16 len;                   /* Length is 8. */
+    ovs_be32 vendor;                /* NX_VENDOR_ID. */
+    ovs_be16 subtype;               /* NXAST_POP_MPLS. */
+    ovs_be16 ethertype;             /* Ethertype */
+    uint8_t  pad[4];
+};
+OFP_ASSERT(sizeof(struct nx_action_pop_mpls) == 16);
+
 #endif /* openflow/nicira-ext.h */
index 8dfd795..ec94cee 100644 (file)
@@ -204,8 +204,8 @@ enum ofp11_action_type {
 
     OFPAT11_PUSH_VLAN,        /* Push a new VLAN tag */
     OFPAT11_POP_VLAN,         /* Pop the outer VLAN tag */
-    OFPAT11_PUSH_MPLS,        /* Push a new MPLS tag */
-    OFPAT11_POP_MPLS,         /* Pop the outer MPLS tag */
+    OFPAT11_PUSH_MPLS,        /* Push a new MPLS Label Stack Entry */
+    OFPAT11_POP_MPLS,         /* Pop the outer MPLS Label Stack Entry */
     OFPAT11_SET_QUEUE,        /* Set queue id when outputting to a port */
     OFPAT11_GROUP,            /* Apply group. */
     OFPAT11_SET_NW_TTL,       /* IP TTL. */
index d9f92d5..c535a50 100644 (file)
@@ -72,6 +72,6 @@ enum {
                                          * not IP. */
 /* Bit 5 was previously used for path MTU discovery. " */
 /* Bit 6 is reserved since it was previously used for Tunnel header caching. */
-#define TNL_F_IPSEC            (1 << 7) /* Traffic is IPsec encrypted. */
+/* Bit 7 was previously used for IPsec tunnel ports. */
 
 #endif /* openvswitch/tunnel.h */
index 58d8da2..fb9dde6 100644 (file)
@@ -10,8 +10,6 @@ noinst_LIBRARIES += lib/libopenvswitch.a
 lib_libopenvswitch_a_SOURCES = \
        lib/aes128.c \
        lib/aes128.h \
-       lib/autopath.c \
-       lib/autopath.h \
        lib/backtrace.c \
        lib/backtrace.h \
        lib/bitmap.c \
diff --git a/lib/autopath.c b/lib/autopath.c
deleted file mode 100644 (file)
index 9da6463..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (c) 2011, 2012 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 "autopath.h"
-
-#include <inttypes.h>
-#include <stdlib.h>
-
-#include "flow.h"
-#include "meta-flow.h"
-#include "nx-match.h"
-#include "ofp-actions.h"
-#include "ofp-errors.h"
-#include "ofp-util.h"
-#include "openflow/nicira-ext.h"
-#include "vlog.h"
-
-VLOG_DEFINE_THIS_MODULE(autopath);
-
-void
-autopath_parse(struct ofpact_autopath *ap, const char *s_)
-{
-    char *s;
-    char *id_str, *dst, *save_ptr;
-    uint16_t port;
-
-    ofpact_init_AUTOPATH(ap);
-
-    s = xstrdup(s_);
-    save_ptr = NULL;
-    id_str = strtok_r(s, ", ", &save_ptr);
-    dst = strtok_r(NULL, ", ", &save_ptr);
-
-    if (!dst) {
-        ovs_fatal(0, "%s: not enough arguments to autopath action", s_);
-    }
-
-    if (!ofputil_port_from_string(id_str, &port)) {
-        ovs_fatal(0, "%s: bad port number", s_);
-    }
-    ap->port = port;
-
-    mf_parse_subfield(&ap->dst, dst);
-    if (ap->dst.n_bits < 16) {
-        ovs_fatal(0, "%s: %d-bit destination field has %u possible values, "
-                  "less than required 65536",
-                  s_, ap->dst.n_bits, 1u << ap->dst.n_bits);
-    }
-
-    free(s);
-}
-
-enum ofperr
-autopath_from_openflow(const struct nx_action_autopath *nap,
-                       struct ofpact_autopath *autopath)
-{
-    ofpact_init_AUTOPATH(autopath);
-    autopath->dst.field = mf_from_nxm_header(ntohl(nap->dst));
-    autopath->dst.ofs = nxm_decode_ofs(nap->ofs_nbits);
-    autopath->dst.n_bits = nxm_decode_n_bits(nap->ofs_nbits);
-    autopath->port = ntohl(nap->id);
-
-    if (autopath->dst.n_bits < 16) {
-        VLOG_WARN("at least 16 bit destination is required for autopath "
-                  "action.");
-        return OFPERR_OFPBAC_BAD_ARGUMENT;
-    }
-
-    return autopath_check(autopath, NULL);
-}
-
-enum ofperr
-autopath_check(const struct ofpact_autopath *autopath, const struct flow *flow)
-{
-    VLOG_WARN_ONCE("The autopath action is deprecated and may be removed in"
-                   " February 2013.  Please email dev@openvswitch.org with"
-                   " concerns.");
-    return mf_check_dst(&autopath->dst, flow);
-}
-
-void
-autopath_to_nxast(const struct ofpact_autopath *autopath,
-                  struct ofpbuf *openflow)
-{
-    struct nx_action_autopath *ap;
-
-    ap = ofputil_put_NXAST_AUTOPATH__DEPRECATED(openflow);
-    ap->ofs_nbits = nxm_encode_ofs_nbits(autopath->dst.ofs,
-                                         autopath->dst.n_bits);
-    ap->dst = htonl(autopath->dst.field->nxm_header);
-    ap->id = htonl(autopath->port);
-}
diff --git a/lib/autopath.h b/lib/autopath.h
deleted file mode 100644 (file)
index 337e7d1..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2011, 2012 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.
- */
-
-#ifndef AUTOPATH_H
-#define AUTOPATH_H 1
-
-#include <stdint.h>
-#include "ofp-errors.h"
-
-struct flow;
-struct nx_action_autopath;
-struct ofpact_autopath;
-struct ofpbuf;
-
-/* NXAST_AUTOPATH  helper functions.
- *
- * See include/openflow/nicira-ext.h for NXAST_AUTOPATH specification. */
-
-void autopath_parse(struct ofpact_autopath *, const char *);
-
-enum ofperr autopath_from_openflow(const struct nx_action_autopath *,
-                                   struct ofpact_autopath *);
-enum ofperr autopath_check(const struct ofpact_autopath *,
-                           const struct flow *);
-void autopath_to_nxast(const struct ofpact_autopath *,
-                       struct ofpbuf *openflow);
-
-#endif /* autopath.h */
index 06680ee..aca18a2 100644 (file)
@@ -75,9 +75,6 @@ struct bond_slave {
     struct list bal_node;       /* In bond_rebalance()'s 'bals' list. */
     struct list entries;        /* 'struct bond_entry's assigned here. */
     uint64_t tx_bytes;          /* Sum across 'tx_bytes' of entries. */
-
-    /* BM_STABLE specific bonding info. */
-    uint32_t stb_id;            /* ID used for 'stb_slaves' ordering. */
 };
 
 /* A bond, that is, a set of network devices grouped to improve performance or
@@ -104,9 +101,6 @@ struct bond {
     long long int next_rebalance; /* Next rebalancing time. */
     bool send_learning_packets;
 
-    /* BM_STABLE specific bonding info. */
-    tag_type stb_tag;               /* Tag associated with this bond. */
-
     /* Legacy compatibility. */
     long long int next_fake_iface_update; /* LLONG_MAX if disabled. */
 
@@ -147,8 +141,6 @@ bond_mode_from_string(enum bond_mode *balance, const char *s)
         *balance = BM_TCP;
     } else if (!strcmp(s, bond_mode_to_string(BM_SLB))) {
         *balance = BM_SLB;
-    } else if (!strcmp(s, bond_mode_to_string(BM_STABLE))) {
-        *balance = BM_STABLE;
     } else if (!strcmp(s, bond_mode_to_string(BM_AB))) {
         *balance = BM_AB;
     } else {
@@ -165,8 +157,6 @@ bond_mode_to_string(enum bond_mode balance) {
         return "balance-tcp";
     case BM_SLB:
         return "balance-slb";
-    case BM_STABLE:
-        return "stable";
     case BM_AB:
         return "active-backup";
     }
@@ -187,7 +177,6 @@ bond_create(const struct bond_settings *s)
     bond = xzalloc(sizeof *bond);
     hmap_init(&bond->slaves);
     bond->no_slaves_tag = tag_create_random();
-    bond->stb_tag = tag_create_random();
     bond->next_fake_iface_update = LLONG_MAX;
 
     bond_reconfigure(bond, s);
@@ -256,12 +245,6 @@ bond_reconfigure(struct bond *bond, const struct bond_settings *s)
     if (bond->balance != s->balance) {
         bond->balance = s->balance;
         revalidate = true;
-
-        if (bond->balance == BM_STABLE) {
-            VLOG_WARN_ONCE("Stable bond mode is deprecated and may be removed"
-                           " in February 2013. Please email"
-                           " dev@openvswitch.org with concerns.");
-        }
     }
 
     if (bond->basis != s->basis) {
@@ -303,17 +286,12 @@ bond_slave_set_netdev__(struct bond_slave *slave, struct netdev *netdev)
  * bond.  If 'slave_' already exists within 'bond' then this function
  * reconfigures the existing slave.
  *
- * 'stb_id' is used in BM_STABLE bonds to guarantee consistent slave choices
- * across restarts and distributed vswitch instances.  It should be unique per
- * slave, and preferably consistent across restarts and reconfigurations.
- *
  * 'netdev' must be the network device that 'slave_' represents.  It is owned
  * by the client, so the client must not close it before either unregistering
  * 'slave_' or destroying 'bond'.
  */
 void
-bond_slave_register(struct bond *bond, void *slave_, uint32_t stb_id,
-                    struct netdev *netdev)
+bond_slave_register(struct bond *bond, void *slave_, struct netdev *netdev)
 {
     struct bond_slave *slave = bond_slave_lookup(bond, slave_);
 
@@ -331,11 +309,6 @@ bond_slave_register(struct bond *bond, void *slave_, uint32_t stb_id,
         bond_enable_slave(slave, netdev_get_carrier(netdev), NULL);
     }
 
-    if (slave->stb_id != stb_id) {
-        slave->stb_id = stb_id;
-        bond->bond_revalidate = true;
-    }
-
     bond_slave_set_netdev__(slave, netdev);
 
     free(slave->name);
@@ -438,17 +411,12 @@ bond_run(struct bond *bond, struct tag_set *tags, enum lacp_status lacp_status)
     }
 
     if (bond->bond_revalidate) {
-        bond->bond_revalidate = false;
+        struct bond_slave *slave;
 
+        bond->bond_revalidate = false;
         bond_entry_reset(bond);
-        if (bond->balance != BM_STABLE) {
-            struct bond_slave *slave;
-
-            HMAP_FOR_EACH (slave, hmap_node, &bond->slaves) {
-                tag_set_add(tags, slave->tag);
-            }
-        } else {
-            tag_set_add(tags, bond->stb_tag);
+        HMAP_FOR_EACH (slave, hmap_node, &bond->slaves) {
+            tag_set_add(tags, slave->tag);
         }
         tag_set_add(tags, bond->no_slaves_tag);
     }
@@ -621,9 +589,6 @@ bond_check_admissibility(struct bond *bond, const void *slave_,
          * exception is if we locked the learning table to avoid reflections on
          * bond slaves. */
         return BV_DROP_IF_MOVED;
-
-    case BM_STABLE:
-        return BV_ACCEPT;
     }
 
     NOT_REACHED();
@@ -647,7 +612,7 @@ bond_choose_output_slave(struct bond *bond, const struct flow *flow,
 {
     struct bond_slave *slave = choose_output_slave(bond, flow, vlan, tags);
     if (slave) {
-        *tags |= bond->balance == BM_STABLE ? bond->stb_tag : slave->tag;
+        *tags |= slave->tag;
         return slave->aux;
     } else {
         *tags |= bond->no_slaves_tag;
@@ -1297,23 +1262,18 @@ bond_slave_lookup(struct bond *bond, const void *slave_)
 static void
 bond_enable_slave(struct bond_slave *slave, bool enable, struct tag_set *tags)
 {
-    struct bond *bond = slave->bond;
     slave->delay_expires = LLONG_MAX;
     if (enable != slave->enabled) {
         slave->enabled = enable;
         if (!slave->enabled) {
-            VLOG_WARN("interface %s: disabled", slave->name);
+            VLOG_INFO("interface %s: disabled", slave->name);
             if (tags) {
                 tag_set_add(tags, slave->tag);
             }
         } else {
-            VLOG_WARN("interface %s: enabled", slave->name);
+            VLOG_INFO("interface %s: enabled", slave->name);
             slave->tag = tag_create_random();
         }
-
-        if (bond->balance == BM_STABLE) {
-            bond->bond_revalidate = true;
-        }
     }
 }
 
@@ -1387,35 +1347,6 @@ lookup_bond_entry(const struct bond *bond, const struct flow *flow,
     return &bond->hash[bond_hash(bond, flow, vlan) & BOND_MASK];
 }
 
-/* This function uses Highest Random Weight hashing to choose an output slave.
- * This approach only reassigns a minimal number of flows when slaves are
- * enabled or disabled.  Unfortunately, it has O(n) performance against the
- * number of slaves.  There exist algorithms which are O(1), but have slightly
- * more complex implementations and require the use of memory.  This may need
- * to be reimplemented if it becomes a performance bottleneck. */
-static struct bond_slave *
-choose_stb_slave(const struct bond *bond, uint32_t flow_hash)
-{
-    struct bond_slave *best, *slave;
-    uint32_t best_hash;
-
-    best = NULL;
-    best_hash = 0;
-    HMAP_FOR_EACH (slave, hmap_node, &bond->slaves) {
-        if (slave->enabled) {
-            uint32_t hash;
-
-            hash = hash_2words(flow_hash, slave->stb_id);
-            if (!best || hash > best_hash) {
-                best = slave;
-                best_hash = hash;
-            }
-        }
-    }
-
-    return best;
-}
-
 static struct bond_slave *
 choose_output_slave(const struct bond *bond, const struct flow *flow,
                     uint16_t vlan, tag_type *tags)
@@ -1432,9 +1363,6 @@ choose_output_slave(const struct bond *bond, const struct flow *flow,
     case BM_AB:
         return bond->active_slave;
 
-    case BM_STABLE:
-        return choose_stb_slave(bond, bond_hash_tcp(flow, vlan, bond->basis));
-
     case BM_TCP:
         if (bond->lacp_status != LACP_NEGOTIATED) {
             /* Must have LACP negotiations for TCP balanced bonds. */
@@ -1442,9 +1370,6 @@ choose_output_slave(const struct bond *bond, const struct flow *flow,
         }
         /* Fall Through. */
     case BM_SLB:
-        if (!bond_is_balanced(bond)) {
-            return choose_stb_slave(bond, bond_hash(bond, flow, vlan));
-        }
         e = lookup_bond_entry(bond, flow, vlan);
         if (!e->slave || !e->slave->enabled) {
             e->slave = CONTAINER_OF(hmap_random_node(&bond->slaves),
@@ -1512,7 +1437,7 @@ bond_choose_active_slave(struct bond *bond, struct tag_set *tags)
 
         bond->send_learning_packets = true;
     } else if (old_active_slave) {
-        VLOG_WARN_RL(&rl, "bond %s: all interfaces disabled", bond->name);
+        VLOG_INFO_RL(&rl, "bond %s: all interfaces disabled", bond->name);
     }
 }
 
index 7329db7..6190081 100644 (file)
@@ -32,7 +32,6 @@ enum lacp_status;
 enum bond_mode {
     BM_TCP, /* Transport Layer Load Balance. */
     BM_SLB, /* Source Load Balance. */
-    BM_STABLE, /* Stable. */
     BM_AB   /* Active Backup. */
 };
 
@@ -65,8 +64,7 @@ struct bond *bond_create(const struct bond_settings *);
 void bond_destroy(struct bond *);
 
 bool bond_reconfigure(struct bond *, const struct bond_settings *);
-void bond_slave_register(struct bond *, void *slave_,
-                         uint32_t stable_id, struct netdev *);
+void bond_slave_register(struct bond *, void *slave_, struct netdev *);
 void bond_slave_set_netdev(struct bond *, void *slave_, struct netdev *);
 void bond_slave_unregister(struct bond *, const void *slave);
 
index 7192602..2d1e50b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 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.
@@ -33,11 +33,19 @@ static struct cls_table *insert_table(struct classifier *,
 
 static void destroy_table(struct classifier *, struct cls_table *);
 
+static void update_tables_after_insertion(struct classifier *,
+                                          struct cls_table *,
+                                          unsigned int new_priority);
+static void update_tables_after_removal(struct classifier *,
+                                        struct cls_table *,
+                                        unsigned int del_priority);
+
 static struct cls_rule *find_match(const struct cls_table *,
                                    const struct flow *);
 static struct cls_rule *find_equal(struct cls_table *,
                                    const struct miniflow *, uint32_t hash);
-static struct cls_rule *insert_rule(struct cls_table *, struct cls_rule *);
+static struct cls_rule *insert_rule(struct classifier *,
+                                    struct cls_table *, struct cls_rule *);
 
 /* Iterates RULE over HEAD and all of the cls_rules on HEAD->list. */
 #define FOR_EACH_RULE_IN_LIST(RULE, HEAD)                               \
@@ -134,6 +142,7 @@ classifier_init(struct classifier *cls)
 {
     cls->n_rules = 0;
     hmap_init(&cls->tables);
+    list_init(&cls->tables_priority);
 }
 
 /* Destroys 'cls'.  Rules within 'cls', if any, are not freed; this is the
@@ -189,7 +198,7 @@ classifier_replace(struct classifier *cls, struct cls_rule *rule)
         table = insert_table(cls, &rule->match.mask);
     }
 
-    old_rule = insert_rule(table, rule);
+    old_rule = insert_rule(cls, table, rule);
     if (!old_rule) {
         table->n_table_rules++;
         cls->n_rules++;
@@ -235,8 +244,9 @@ classifier_remove(struct classifier *cls, struct cls_rule *rule)
 
     if (--table->n_table_rules == 0) {
         destroy_table(cls, table);
+    } else {
+        update_tables_after_removal(cls, table, rule->priority);
     }
-
     cls->n_rules--;
 }
 
@@ -250,10 +260,22 @@ classifier_lookup(const struct classifier *cls, const struct flow *flow)
     struct cls_rule *best;
 
     best = NULL;
-    HMAP_FOR_EACH (table, hmap_node, &cls->tables) {
+    LIST_FOR_EACH (table, list_node, &cls->tables_priority) {
         struct cls_rule *rule = find_match(table, flow);
-        if (rule && (!best || rule->priority > best->priority)) {
+        if (rule) {
             best = rule;
+            LIST_FOR_EACH_CONTINUE (table, list_node, &cls->tables_priority) {
+                if (table->max_priority <= best->priority) {
+                    /* Tables in descending priority order,
+                     * can not find anything better. */
+                    return best;
+                }
+                rule = find_match(table, flow);
+                if (rule && rule->priority > best->priority) {
+                    best = rule;
+                }
+            }
+            break;
         }
     }
     return best;
@@ -274,6 +296,11 @@ classifier_find_rule_exactly(const struct classifier *cls,
         return NULL;
     }
 
+    /* Skip if there is no hope. */
+    if (target->priority > table->max_priority) {
+        return NULL;
+    }
+
     head = find_equal(table, &target->match.flow,
                       miniflow_hash_in_minimask(&target->match.flow,
                                                 &target->match.mask, 0));
@@ -312,16 +339,24 @@ classifier_rule_overlaps(const struct classifier *cls,
 {
     struct cls_table *table;
 
-    HMAP_FOR_EACH (table, hmap_node, &cls->tables) {
+    /* Iterate tables in the descending max priority order. */
+    LIST_FOR_EACH (table, list_node, &cls->tables_priority) {
         uint32_t storage[FLOW_U32S];
         struct minimask mask;
         struct cls_rule *head;
 
+        if (target->priority > table->max_priority) {
+            break; /* Can skip this and the rest of the tables. */
+        }
+
         minimask_combine(&mask, &target->match.mask, &table->mask, storage);
         HMAP_FOR_EACH (head, hmap_node, &table->rules) {
             struct cls_rule *rule;
 
             FOR_EACH_RULE_IN_LIST (rule, head) {
+                if (rule->priority < target->priority) {
+                    break; /* Rules in descending priority order. */
+                }
                 if (rule->priority == target->priority
                     && miniflow_equal_in_minimask(&target->match.flow,
                                                   &rule->match.flow, &mask)) {
@@ -494,6 +529,7 @@ insert_table(struct classifier *cls, const struct minimask *mask)
     hmap_init(&table->rules);
     minimask_clone(&table->mask, mask);
     hmap_insert(&cls->tables, &table->hmap_node, minimask_hash(mask, 0));
+    list_push_back(&cls->tables_priority, &table->list_node);
 
     return table;
 }
@@ -504,9 +540,100 @@ destroy_table(struct classifier *cls, struct cls_table *table)
     minimask_destroy(&table->mask);
     hmap_remove(&cls->tables, &table->hmap_node);
     hmap_destroy(&table->rules);
+    list_remove(&table->list_node);
     free(table);
 }
 
+/* This function performs the following updates for 'table' in 'cls' following
+ * the addition of a new rule with priority 'new_priority' to 'table':
+ *
+ *    - Update 'table->max_priority' and 'table->max_count' if necessary.
+ *
+ *    - Update 'table''s position in 'cls->tables_priority' if necessary.
+ *
+ * This function should only be called after adding a new rule, not after
+ * replacing a rule by an identical one or modifying a rule in-place. */
+static void
+update_tables_after_insertion(struct classifier *cls, struct cls_table *table,
+                              unsigned int new_priority)
+{
+    if (new_priority == table->max_priority) {
+        ++table->max_count;
+    } else if (new_priority > table->max_priority) {
+        struct cls_table *iter;
+
+        table->max_priority = new_priority;
+        table->max_count = 1;
+
+        /* Possibly move 'table' earlier in the priority list.  If we break out
+         * of the loop, then 'table' should be moved just after that 'iter'.
+         * If the loop terminates normally, then 'iter' will be the list head
+         * and we'll move table just after that (e.g. to the front of the
+         * list). */
+        iter = table;
+        LIST_FOR_EACH_REVERSE_CONTINUE (iter, list_node,
+                                        &cls->tables_priority) {
+            if (iter->max_priority >= table->max_priority) {
+                break;
+            }
+        }
+
+        /* Move 'table' just after 'iter' (unless it's already there). */
+        if (iter->list_node.next != &table->list_node) {
+            list_splice(iter->list_node.next,
+                        &table->list_node, table->list_node.next);
+        }
+    }
+}
+
+/* This function performs the following updates for 'table' in 'cls' following
+ * the deletion of a rule with priority 'del_priority' from 'table':
+ *
+ *    - Update 'table->max_priority' and 'table->max_count' if necessary.
+ *
+ *    - Update 'table''s position in 'cls->tables_priority' if necessary.
+ *
+ * This function should only be called after removing a rule, not after
+ * replacing a rule by an identical one or modifying a rule in-place. */
+static void
+update_tables_after_removal(struct classifier *cls, struct cls_table *table,
+                            unsigned int del_priority)
+{
+    struct cls_table *iter;
+
+    if (del_priority == table->max_priority && --table->max_count == 0) {
+        struct cls_rule *head;
+
+        table->max_priority = 0;
+        HMAP_FOR_EACH (head, hmap_node, &table->rules) {
+            if (head->priority > table->max_priority) {
+                table->max_priority = head->priority;
+                table->max_count = 1;
+            } else if (head->priority == table->max_priority) {
+                ++table->max_count;
+            }
+        }
+
+        /* Possibly move 'table' later in the priority list.  If we break out
+         * of the loop, then 'table' should be moved just before that 'iter'.
+         * If the loop terminates normally, then 'iter' will be the list head
+         * and we'll move table just before that (e.g. to the back of the
+         * list). */
+        iter = table;
+        LIST_FOR_EACH_CONTINUE (iter, list_node, &cls->tables_priority) {
+            if (iter->max_priority <= table->max_priority) {
+                break;
+            }
+        }
+
+        /* Move 'table' just before 'iter' (unless it's already there). */
+        if (iter->list_node.prev != &table->list_node) {
+            list_splice(&iter->list_node,
+                        &table->list_node, table->list_node.next);
+        }
+    }
+}
+
 static struct cls_rule *
 find_match(const struct cls_table *table, const struct flow *flow)
 {
@@ -537,9 +664,11 @@ find_equal(struct cls_table *table, const struct miniflow *flow, uint32_t hash)
 }
 
 static struct cls_rule *
-insert_rule(struct cls_table *table, struct cls_rule *new)
+insert_rule(struct classifier *cls,
+            struct cls_table *table, struct cls_rule *new)
 {
     struct cls_rule *head;
+    struct cls_rule *old = NULL;
 
     new->hmap_node.hash = miniflow_hash_in_minimask(&new->match.flow,
                                                     &new->match.mask, 0);
@@ -548,7 +677,7 @@ insert_rule(struct cls_table *table, struct cls_rule *new)
     if (!head) {
         hmap_insert(&table->rules, &new->hmap_node, new->hmap_node.hash);
         list_init(&new->list);
-        return NULL;
+        goto out;
     } else {
         /* Scan the list for the insertion point that will keep the list in
          * order of decreasing priority. */
@@ -563,18 +692,24 @@ insert_rule(struct cls_table *table, struct cls_rule *new)
 
                 if (new->priority == rule->priority) {
                     list_replace(&new->list, &rule->list);
-                    return rule;
+                    old = rule;
+                    goto out;
                 } else {
                     list_insert(&rule->list, &new->list);
-                    return NULL;
+                    goto out;
                 }
             }
         }
 
         /* Insert 'new' at the end of the list. */
         list_push_back(&head->list, &new->list);
-        return NULL;
     }
+
+ out:
+    if (!old) {
+        update_tables_after_insertion(cls, table, new->priority);
+    }
+    return old;
 }
 
 static struct cls_rule *
index bc9db33..d318864 100644 (file)
@@ -41,14 +41,18 @@ extern "C" {
 struct classifier {
     int n_rules;                /* Total number of rules. */
     struct hmap tables;         /* Contains "struct cls_table"s.  */
+    struct list tables_priority; /* Tables in descending priority order */
 };
 
 /* A set of rules that all have the same fields wildcarded. */
 struct cls_table {
     struct hmap_node hmap_node; /* Within struct classifier 'tables' hmap. */
+    struct list list_node;      /* Within classifier 'tables_priority_list' */
     struct hmap rules;          /* Contains "struct cls_rule"s. */
     struct minimask mask;       /* Wildcards for fields. */
     int n_table_rules;          /* Number of rules, including duplicates. */
+    unsigned int max_priority;  /* Max priority of any rule in the table. */
+    unsigned int max_count;     /* Count of max_priority rules. */
 };
 
 /* Returns true if 'table' is a "catch-all" table that will match every
index b6eba39..1b23b39 100644 (file)
@@ -439,12 +439,12 @@ get_vport_type(const struct dpif_linux_vport *vport)
     case OVS_VPORT_TYPE_GRE64:
         return "gre64";
 
-    case OVS_VPORT_TYPE_CAPWAP:
-        return "capwap";
-
     case OVS_VPORT_TYPE_VXLAN:
         return "vxlan";
 
+    case OVS_VPORT_TYPE_LISP:
+        return "lisp";
+
     case OVS_VPORT_TYPE_UNSPEC:
     case __OVS_VPORT_TYPE_MAX:
         break;
@@ -468,10 +468,10 @@ netdev_to_ovs_vport_type(const struct netdev *netdev)
         return OVS_VPORT_TYPE_GRE64;
     } else if (strstr(type, "gre")) {
         return OVS_VPORT_TYPE_GRE;
-    } else if (!strcmp(type, "capwap")) {
-        return OVS_VPORT_TYPE_CAPWAP;
     } else if (!strcmp(type, "vxlan")) {
         return OVS_VPORT_TYPE_VXLAN;
+    } else if (!strcmp(type, "lisp")) {
+        return OVS_VPORT_TYPE_LISP;
     } else {
         return OVS_VPORT_TYPE_UNSPEC;
     }
@@ -482,12 +482,15 @@ dpif_linux_port_add(struct dpif *dpif_, struct netdev *netdev,
                     uint32_t *port_nop)
 {
     struct dpif_linux *dpif = dpif_linux_cast(dpif_);
+    const struct netdev_tunnel_config *tnl_cfg;
     const char *name = netdev_vport_get_dpif_port(netdev);
     const char *type = netdev_get_type(netdev);
     struct dpif_linux_vport request, reply;
     struct nl_sock *sock = NULL;
     uint32_t upcall_pid;
     struct ofpbuf *buf;
+    uint64_t options_stub[64 / 8];
+    struct ofpbuf options;
     int error;
 
     if (dpif->epoll_fd >= 0) {
@@ -514,6 +517,15 @@ dpif_linux_port_add(struct dpif *dpif_, struct netdev *netdev,
         netdev_linux_ethtool_set_flag(netdev, ETH_FLAG_LRO, "LRO", false);
     }
 
+    tnl_cfg = netdev_get_tunnel_config(netdev);
+    if (tnl_cfg && tnl_cfg->dst_port != 0) {
+        ofpbuf_use_stack(&options, options_stub, sizeof options_stub);
+        nl_msg_put_u16(&options, OVS_TUNNEL_ATTR_DST_PORT,
+                       ntohs(tnl_cfg->dst_port));
+        request.options = options.data;
+        request.options_len = options.size;
+    }
+
     request.port_no = *port_nop;
     upcall_pid = sock ? nl_sock_pid(sock) : 0;
     request.upcall_pid = &upcall_pid;
@@ -1225,7 +1237,7 @@ parse_odp_packet(struct ofpbuf *buf, struct dpif_upcall *upcall,
         [OVS_PACKET_ATTR_KEY] = { .type = NL_A_NESTED },
 
         /* OVS_PACKET_CMD_ACTION only. */
-        [OVS_PACKET_ATTR_USERDATA] = { .type = NL_A_U64, .optional = true },
+        [OVS_PACKET_ATTR_USERDATA] = { .type = NL_A_UNSPEC, .optional = true },
     };
 
     struct ovs_header *ovs_header;
@@ -1263,9 +1275,7 @@ parse_odp_packet(struct ofpbuf *buf, struct dpif_upcall *upcall,
     upcall->key = CONST_CAST(struct nlattr *,
                              nl_attr_get(a[OVS_PACKET_ATTR_KEY]));
     upcall->key_len = nl_attr_get_size(a[OVS_PACKET_ATTR_KEY]);
-    upcall->userdata = (a[OVS_PACKET_ATTR_USERDATA]
-                        ? nl_attr_get_u64(a[OVS_PACKET_ATTR_USERDATA])
-                        : 0);
+    upcall->userdata = a[OVS_PACKET_ATTR_USERDATA];
     *dp_ifindex = ovs_header->dp_ifindex;
 
     return 0;
index 129839c..80d0c43 100644 (file)
@@ -151,7 +151,7 @@ static int dpif_netdev_open(const struct dpif_class *, const char *name,
                             bool create, struct dpif **);
 static int dp_netdev_output_userspace(struct dp_netdev *, const struct ofpbuf *,
                                     int queue_no, const struct flow *,
-                                    uint64_t arg);
+                                    const struct nlattr *userdata);
 static void dp_netdev_execute_actions(struct dp_netdev *,
                                       struct ofpbuf *, struct flow *,
                                       const struct nlattr *actions,
@@ -1051,7 +1051,7 @@ dp_netdev_port_input(struct dp_netdev *dp, struct dp_netdev_port *port,
         dp->n_hit++;
     } else {
         dp->n_missed++;
-        dp_netdev_output_userspace(dp, packet, DPIF_UC_MISS, &key, 0);
+        dp_netdev_output_userspace(dp, packet, DPIF_UC_MISS, &key, NULL);
     }
 }
 
@@ -1116,37 +1116,51 @@ dp_netdev_output_port(struct dp_netdev *dp, struct ofpbuf *packet,
 
 static int
 dp_netdev_output_userspace(struct dp_netdev *dp, const struct ofpbuf *packet,
-                         int queue_no, const struct flow *flow, uint64_t arg)
+                           int queue_no, const struct flow *flow,
+                           const struct nlattr *userdata)
 {
     struct dp_netdev_queue *q = &dp->queues[queue_no];
-    struct dp_netdev_upcall *u;
-    struct dpif_upcall *upcall;
-    struct ofpbuf *buf;
-    size_t key_len;
-
-    if (q->head - q->tail >= MAX_QUEUE_LEN) {
-        dp->n_lost++;
-        return ENOBUFS;
-    }
+    if (q->head - q->tail < MAX_QUEUE_LEN) {
+        struct dp_netdev_upcall *u = &q->upcalls[q->head++ & QUEUE_MASK];
+        struct dpif_upcall *upcall = &u->upcall;
+        struct ofpbuf *buf = &u->buf;
+        size_t buf_size;
+
+        upcall->type = queue_no;
+
+        /* Allocate buffer big enough for everything. */
+        buf_size = ODPUTIL_FLOW_KEY_BYTES + 2 + packet->size;
+        if (userdata) {
+            buf_size += NLA_ALIGN(userdata->nla_len);
+        }
+        ofpbuf_init(buf, buf_size);
 
-    u = &q->upcalls[q->head++ & QUEUE_MASK];
+        /* Put ODP flow. */
+        odp_flow_key_from_flow(buf, flow, flow->in_port);
+        upcall->key = buf->data;
+        upcall->key_len = buf->size;
 
-    buf = &u->buf;
-    ofpbuf_init(buf, ODPUTIL_FLOW_KEY_BYTES + 2 + packet->size);
-    odp_flow_key_from_flow(buf, flow, flow->in_port);
-    key_len = buf->size;
-    ofpbuf_pull(buf, key_len);
-    ofpbuf_reserve(buf, 2);
-    ofpbuf_put(buf, packet->data, packet->size);
+        /* Put userdata. */
+        if (userdata) {
+            upcall->userdata = ofpbuf_put(buf, userdata,
+                                          NLA_ALIGN(userdata->nla_len));
+        }
 
-    upcall = &u->upcall;
-    upcall->type = queue_no;
-    upcall->packet = buf;
-    upcall->key = buf->base;
-    upcall->key_len = key_len;
-    upcall->userdata = arg;
+        /* Put packet.
+         *
+         * We adjust 'data' and 'size' in 'buf' so that only the packet itself
+         * is visible in 'upcall->packet'.  The ODP flow and (if present)
+         * userdata become part of the headroom. */
+        ofpbuf_put_zeros(buf, 2);
+        buf->data = ofpbuf_put(buf, packet->data, packet->size);
+        buf->size = packet->size;
+        upcall->packet = buf;
 
-    return 0;
+        return 0;
+    } else {
+        dp->n_lost++;
+        return ENOBUFS;
+    }
 }
 
 static void
@@ -1188,11 +1202,9 @@ dp_netdev_action_userspace(struct dp_netdev *dp,
                           struct ofpbuf *packet, struct flow *key,
                           const struct nlattr *a)
 {
-    const struct nlattr *userdata_attr;
-    uint64_t userdata;
+    const struct nlattr *userdata;
 
-    userdata_attr = nl_attr_find_nested(a, OVS_USERSPACE_ATTR_USERDATA);
-    userdata = userdata_attr ? nl_attr_get_u64(userdata_attr) : 0;
+    userdata = nl_attr_find_nested(a, OVS_USERSPACE_ATTR_USERDATA);
     dp_netdev_output_userspace(dp, packet, DPIF_UC_ACTION, key, userdata);
 }
 
@@ -1241,6 +1253,10 @@ execute_set_action(struct ofpbuf *packet, const struct nlattr *a)
         packet_set_udp_port(packet, udp_key->udp_src, udp_key->udp_dst);
         break;
 
+     case OVS_KEY_ATTR_MPLS:
+         set_mpls_lse(packet, nl_attr_get_be32(a));
+         break;
+
      case OVS_KEY_ATTR_UNSPEC:
      case OVS_KEY_ATTR_ENCAP:
      case OVS_KEY_ATTR_ETHERTYPE:
@@ -1287,6 +1303,16 @@ dp_netdev_execute_actions(struct dp_netdev *dp,
             eth_pop_vlan(packet);
             break;
 
+        case OVS_ACTION_ATTR_PUSH_MPLS: {
+            const struct ovs_action_push_mpls *mpls = nl_attr_get(a);
+            push_mpls(packet, mpls->mpls_ethertype, mpls->mpls_lse);
+            break;
+         }
+
+        case OVS_ACTION_ATTR_POP_MPLS:
+            pop_mpls(packet, nl_attr_get_be16(a));
+            break;
+
         case OVS_ACTION_ATTR_SET:
             execute_set_action(packet, nl_attr_get(a));
             break;
index c5e3fc8..fd05b2f 100644 (file)
@@ -540,10 +540,10 @@ const char *dpif_upcall_type_to_string(enum dpif_upcall_type);
 
 /* A packet passed up from the datapath to userspace.
  *
- * If 'key' or 'actions' is nonnull, then it points into data owned by
- * 'packet', so their memory cannot be freed separately.  (This is hardly a
- * great way to do things but it works out OK for the dpif providers and
- * clients that exist so far.)
+ * If 'key', 'actions', or 'userdata' is nonnull, then it points into data
+ * owned by 'packet', so their memory cannot be freed separately.  (This is
+ * hardly a great way to do things but it works out OK for the dpif providers
+ * and clients that exist so far.)
  */
 struct dpif_upcall {
     /* All types. */
@@ -553,7 +553,7 @@ struct dpif_upcall {
     size_t key_len;             /* Length of 'key' in bytes. */
 
     /* DPIF_UC_ACTION only. */
-    uint64_t userdata;          /* Argument to OVS_ACTION_ATTR_USERSPACE. */
+    struct nlattr *userdata;    /* Argument to OVS_ACTION_ATTR_USERSPACE. */
 };
 
 int dpif_recv_set(struct dpif *, bool enable);
index 2a3dd3d..397bda1 100644 (file)
@@ -93,6 +93,21 @@ pull_icmpv6(struct ofpbuf *packet)
     return ofpbuf_try_pull(packet, sizeof(struct icmp6_hdr));
 }
 
+static void
+parse_mpls(struct ofpbuf *b, struct flow *flow)
+{
+    struct mpls_hdr *mh;
+
+    while ((mh = ofpbuf_try_pull(b, sizeof *mh))) {
+        if (flow->mpls_depth++ == 0) {
+            flow->mpls_lse = mh->mpls_lse;
+        }
+        if (mh->mpls_lse & htonl(MPLS_BOS_MASK)) {
+            break;
+        }
+    }
+}
+
 static void
 parse_vlan(struct ofpbuf *b, struct flow *flow)
 {
@@ -132,7 +147,12 @@ parse_ethertype(struct ofpbuf *b)
     }
 
     ofpbuf_pull(b, sizeof *llc);
-    return llc->snap.snap_type;
+
+    if (ntohs(llc->snap.snap_type) >= ETH_TYPE_MIN) {
+        return llc->snap.snap_type;
+    }
+
+    return htons(FLOW_DL_TYPE_NONE);
 }
 
 static int
@@ -324,6 +344,8 @@ invalid:
  *
  *    - packet->l2 to the start of the Ethernet header.
  *
+ *    - packet->l2_5 to the start of the MPLS shim header.
+ *
  *    - packet->l3 to just past the Ethernet header, or just past the
  *      vlan_header if one is present, to the first byte of the payload of the
  *      Ethernet frame.
@@ -354,10 +376,11 @@ flow_extract(struct ofpbuf *packet, uint32_t skb_priority, uint32_t skb_mark,
     flow->skb_priority = skb_priority;
     flow->skb_mark = skb_mark;
 
-    packet->l2 = b.data;
-    packet->l3 = NULL;
-    packet->l4 = NULL;
-    packet->l7 = NULL;
+    packet->l2   = b.data;
+    packet->l2_5 = NULL;
+    packet->l3   = NULL;
+    packet->l4   = NULL;
+    packet->l7   = NULL;
 
     if (b.size < sizeof *eth) {
         return;
@@ -375,6 +398,12 @@ flow_extract(struct ofpbuf *packet, uint32_t skb_priority, uint32_t skb_mark,
     }
     flow->dl_type = parse_ethertype(&b);
 
+    /* Parse mpls, copy l3 ttl. */
+    if (eth_type_mpls(flow->dl_type)) {
+        packet->l2_5 = b.data;
+        parse_mpls(&b, flow);
+    }
+
     packet->l3 = b.data;
     flow_extract_l3_onwards(packet, flow, flow->dl_type);
 }
@@ -487,7 +516,7 @@ flow_zero_wildcards(struct flow *flow, const struct flow_wildcards *wildcards)
 void
 flow_get_metadata(const struct flow *flow, struct flow_metadata *fmd)
 {
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 18);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 19);
 
     fmd->tun_id = flow->tunnel.tun_id;
     fmd->metadata = flow->metadata;
@@ -811,6 +840,29 @@ flow_set_vlan_pcp(struct flow *flow, uint8_t pcp)
     flow->vlan_tci |= htons((pcp << VLAN_PCP_SHIFT) | VLAN_CFI);
 }
 
+/* Sets the MPLS Label that 'flow' matches to 'label', which is interpreted
+ * as an OpenFlow 1.1 "mpls_label" value. */
+void
+flow_set_mpls_label(struct flow *flow, ovs_be32 label)
+{
+    set_mpls_lse_label(&flow->mpls_lse, label);
+}
+
+/* Sets the MPLS TC that 'flow' matches to 'tc', which should be in the
+ * range 0...7. */
+void
+flow_set_mpls_tc(struct flow *flow, uint8_t tc)
+{
+    set_mpls_lse_tc(&flow->mpls_lse, tc);
+}
+
+/* Sets the MPLS BOS bit that 'flow' matches to which should be 0 or 1. */
+void
+flow_set_mpls_bos(struct flow *flow, uint8_t bos)
+{
+    set_mpls_lse_bos(&flow->mpls_lse, bos);
+}
+
 /* Puts into 'b' a packet that flow_extract() would parse as having the given
  * 'flow'.
  *
@@ -820,6 +872,9 @@ flow_set_vlan_pcp(struct flow *flow, uint8_t pcp)
 void
 flow_compose(struct ofpbuf *b, const struct flow *flow)
 {
+    ovs_be16 inner_dl_type;
+
+    inner_dl_type = flow_innermost_dl_type(flow);
     eth_compose(b, flow->dl_dst, flow->dl_src, ntohs(flow->dl_type), 0);
     if (flow->dl_type == htons(FLOW_DL_TYPE_NONE)) {
         struct eth_header *eth = b->l2;
@@ -831,7 +886,7 @@ flow_compose(struct ofpbuf *b, const struct flow *flow)
         eth_push_vlan(b, flow->vlan_tci);
     }
 
-    if (flow->dl_type == htons(ETH_TYPE_IP)) {
+    if (inner_dl_type == htons(ETH_TYPE_IP)) {
         struct ip_header *ip;
 
         b->l3 = ip = ofpbuf_put_zeros(b, sizeof *ip);
@@ -877,10 +932,10 @@ flow_compose(struct ofpbuf *b, const struct flow *flow)
         ip->ip_tot_len = htons((uint8_t *) b->data + b->size
                                - (uint8_t *) b->l3);
         ip->ip_csum = csum(ip, sizeof *ip);
-    } else if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
+    } else if (inner_dl_type == htons(ETH_TYPE_IPV6)) {
         /* XXX */
-    } else if (flow->dl_type == htons(ETH_TYPE_ARP) ||
-               flow->dl_type == htons(ETH_TYPE_RARP)) {
+    } else if (inner_dl_type == htons(ETH_TYPE_ARP) ||
+               inner_dl_type == htons(ETH_TYPE_RARP)) {
         struct arp_eth_header *arp;
 
         b->l3 = arp = ofpbuf_put_zeros(b, sizeof *arp);
@@ -898,6 +953,11 @@ flow_compose(struct ofpbuf *b, const struct flow *flow)
             memcpy(arp->ar_tha, flow->arp_tha, ETH_ADDR_LEN);
         }
     }
+
+    if (eth_type_mpls(flow->dl_type)) {
+        b->l2_5 = b->l3;
+        push_mpls(b, flow->dl_type, flow->mpls_lse);
+    }
 }
 \f
 /* Compressed flow. */
index 8e79e62..e6da480 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 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.
@@ -36,7 +36,7 @@ struct ofpbuf;
 /* This sequence number should be incremented whenever anything involving flows
  * or the wildcarding of flows changes.  This will cause build assertion
  * failures in places which likely need to be updated. */
-#define FLOW_WC_SEQ 18
+#define FLOW_WC_SEQ 19
 
 #define FLOW_N_REGS 8
 BUILD_ASSERT_DECL(FLOW_N_REGS <= NXM_NX_MAX_REGS);
@@ -91,8 +91,11 @@ struct flow {
                                    unless in DPIF code, in which case it
                                    is the datapath port number. */
     uint32_t skb_mark;          /* Packet mark. */
+    ovs_be32 mpls_lse;          /* MPLS label stack entry. */
+    uint16_t mpls_depth;        /* Depth of MPLS stack. */
     ovs_be16 vlan_tci;          /* If 802.1Q, TCI | VLAN_CFI; otherwise 0. */
     ovs_be16 dl_type;           /* Ethernet frame type. */
+    ovs_be16 encap_dl_type;     /* MPLS encapsulated Ethernet frame type */
     ovs_be16 tp_src;            /* TCP/UDP source port. */
     ovs_be16 tp_dst;            /* TCP/UDP destination port. */
     uint8_t dl_src[6];          /* Ethernet source address. */
@@ -110,8 +113,8 @@ BUILD_ASSERT_DECL(sizeof(struct flow) % 4 == 0);
 #define FLOW_U32S (sizeof(struct flow) / 4)
 
 /* Remember to update FLOW_WC_SEQ when changing 'struct flow'. */
-BUILD_ASSERT_DECL(sizeof(struct flow) == sizeof(struct flow_tnl) + 152 &&
-                  FLOW_WC_SEQ == 18);
+BUILD_ASSERT_DECL(sizeof(struct flow) == sizeof(struct flow_tnl) + 160 &&
+                  FLOW_WC_SEQ == 19);
 
 /* Represents the metadata fields of struct flow. */
 struct flow_metadata {
@@ -125,6 +128,18 @@ void flow_extract(struct ofpbuf *, uint32_t priority, uint32_t mark,
                   const struct flow_tnl *, uint16_t in_port, struct flow *);
 void flow_extract_l3_onwards(struct ofpbuf *, struct flow *,
                              ovs_be16 dl_type);
+
+/* Returns the innermost dl_type.
+ * If there's an outer and an inner type then the inner type is returned.
+ * Otherwise, if there is only one type then it is returned. */
+static inline ovs_be16
+flow_innermost_dl_type(const struct flow *flow)
+{
+    return (flow->encap_dl_type == htons(0)
+            ? flow->dl_type
+            : flow->encap_dl_type);
+}
+
 void flow_zero_wildcards(struct flow *, const struct flow_wildcards *);
 void flow_get_metadata(const struct flow *, struct flow_metadata *);
 
@@ -142,6 +157,11 @@ void flow_set_dl_vlan(struct flow *, ovs_be16 vid);
 void flow_set_vlan_vid(struct flow *, ovs_be16 vid);
 void flow_set_vlan_pcp(struct flow *, uint8_t pcp);
 
+void flow_set_mpls_label(struct flow *flow, ovs_be32 label);
+void flow_set_mpls_ttl(struct flow *flow, uint8_t ttl);
+void flow_set_mpls_tc(struct flow *flow, uint8_t tc);
+void flow_set_mpls_bos(struct flow *flow, uint8_t stack);
+
 void flow_compose(struct ofpbuf *, const struct flow *);
 
 static inline int
index 8ffa797..55e0d0a 100644 (file)
@@ -60,10 +60,18 @@ bool list_is_short(const struct list *);
     for (ASSIGN_CONTAINER(ITER, (LIST)->next, MEMBER);                  \
          &(ITER)->MEMBER != (LIST);                                     \
          ASSIGN_CONTAINER(ITER, (ITER)->MEMBER.next, MEMBER))
+#define LIST_FOR_EACH_CONTINUE(ITER, MEMBER, LIST)                      \
+    for (ASSIGN_CONTAINER(ITER, (ITER)->MEMBER.next, MEMBER);           \
+         &(ITER)->MEMBER != (LIST);                                     \
+         ASSIGN_CONTAINER(ITER, (ITER)->MEMBER.next, MEMBER))
 #define LIST_FOR_EACH_REVERSE(ITER, MEMBER, LIST)                       \
     for (ASSIGN_CONTAINER(ITER, (LIST)->prev, MEMBER);                  \
          &(ITER)->MEMBER != (LIST);                                     \
          ASSIGN_CONTAINER(ITER, (ITER)->MEMBER.prev, MEMBER))
+#define LIST_FOR_EACH_REVERSE_CONTINUE(ITER, MEMBER, LIST)              \
+    for (ASSIGN_CONTAINER(ITER, (ITER)->MEMBER.prev, MEMBER);           \
+         &(ITER)->MEMBER != (LIST);                                     \
+         ASSIGN_CONTAINER(ITER, (ITER)->MEMBER.prev, MEMBER))
 #define LIST_FOR_EACH_SAFE(ITER, NEXT, MEMBER, LIST)            \
     for (ASSIGN_CONTAINER(ITER, (LIST)->next, MEMBER);          \
          (&(ITER)->MEMBER != (LIST)                             \
index bedb1a1..f4b0a6c 100644 (file)
@@ -460,6 +460,57 @@ match_set_dl_vlan_pcp(struct match *match, uint8_t dl_vlan_pcp)
     match->wc.masks.vlan_tci |= htons(VLAN_CFI | VLAN_PCP_MASK);
 }
 
+/* Modifies 'match' so that the MPLS label is wildcarded. */
+void
+match_set_any_mpls_label(struct match *match)
+{
+    match->wc.masks.mpls_lse &= ~htonl(MPLS_LABEL_MASK);
+    flow_set_mpls_label(&match->flow, htonl(0));
+}
+
+/* Modifies 'match' so that it matches only packets with an MPLS header whose
+ * label equals the low 20 bits of 'mpls_label'. */
+void
+match_set_mpls_label(struct match *match, ovs_be32 mpls_label)
+{
+    match->wc.masks.mpls_lse |= htonl(MPLS_LABEL_MASK);
+    flow_set_mpls_label(&match->flow, mpls_label);
+}
+
+/* Modifies 'match' so that the MPLS TC is wildcarded. */
+void
+match_set_any_mpls_tc(struct match *match)
+{
+    match->wc.masks.mpls_lse &= ~htonl(MPLS_TC_MASK);
+    flow_set_mpls_tc(&match->flow, 0);
+}
+
+/* Modifies 'match' so that it matches only packets with an MPLS header whose
+ * Traffic Class equals the low 3 bits of 'mpls_tc'. */
+void
+match_set_mpls_tc(struct match *match, uint8_t mpls_tc)
+{
+    match->wc.masks.mpls_lse |= htonl(MPLS_TC_MASK);
+    flow_set_mpls_tc(&match->flow, mpls_tc);
+}
+
+/* Modifies 'match' so that the MPLS stack flag is wildcarded. */
+void
+match_set_any_mpls_bos(struct match *match)
+{
+    match->wc.masks.mpls_lse &= ~htonl(MPLS_BOS_MASK);
+    flow_set_mpls_bos(&match->flow, 0);
+}
+
+/* Modifies 'match' so that it matches only packets with an MPLS header whose
+ * Stack Flag equals the lower bit of 'mpls_bos' */
+void
+match_set_mpls_bos(struct match *match, uint8_t mpls_bos)
+{
+    match->wc.masks.mpls_lse |= htonl(MPLS_BOS_MASK);
+    flow_set_mpls_bos(&match->flow, mpls_bos);
+}
+
 void
 match_set_tp_src(struct match *match, ovs_be16 tp_src)
 {
@@ -767,6 +818,24 @@ format_flow_tunnel(struct ds *s, const struct match *match)
     }
 }
 
+static void
+flow_format_mpls(const struct flow *flow, struct ds *s)
+{
+    if (flow->dl_type == htons(ETH_TYPE_MPLS)) {
+        ds_put_cstr(s, "mpls");
+    } else if (flow->dl_type == htons(ETH_TYPE_MPLS_MCAST)) {
+        ds_put_cstr(s, "mplsm");
+    } else {
+        return;
+    }
+
+    ds_put_format(s, "(label:%"PRIu32",tc:%d,ttl:%d,bos:%d),",
+                  mpls_lse_to_label(flow->mpls_lse),
+                  mpls_lse_to_tc(flow->mpls_lse),
+                  mpls_lse_to_ttl(flow->mpls_lse),
+                  mpls_lse_to_bos(flow->mpls_lse));
+}
+
 /* Appends a string representation of 'match' to 's'.  If 'priority' is
  * different from OFP_DEFAULT_PRIORITY, includes it in 's'. */
 void
@@ -780,7 +849,7 @@ match_format(const struct match *match, struct ds *s, unsigned int priority)
 
     int i;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 18);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 19);
 
     if (priority != OFP_DEFAULT_PRIORITY) {
         ds_put_format(s, "priority=%u,", priority);
@@ -832,6 +901,8 @@ match_format(const struct match *match, struct ds *s, unsigned int priority)
             ds_put_cstr(s, "arp,");
         } else if (f->dl_type == htons(ETH_TYPE_RARP)) {
             ds_put_cstr(s, "rarp,");
+        } else if (f->mpls_depth) {
+            flow_format_mpls(f, s);
         } else {
             skip_type = false;
         }
@@ -940,6 +1011,18 @@ match_format(const struct match *match, struct ds *s, unsigned int priority)
     if (wc->masks.nw_ttl) {
         ds_put_format(s, "nw_ttl=%"PRIu8",", f->nw_ttl);
     }
+    if (wc->masks.mpls_lse & htonl(MPLS_LABEL_MASK)) {
+        ds_put_format(s, "mpls_label=%"PRIu32",",
+                 mpls_lse_to_label(f->mpls_lse));
+    }
+    if (wc->masks.mpls_lse & htonl(MPLS_TC_MASK)) {
+        ds_put_format(s, "mpls_tc=%"PRIu8",",
+                 mpls_lse_to_tc(f->mpls_lse));
+    }
+    if (wc->masks.mpls_lse & htonl(MPLS_BOS_MASK)) {
+        ds_put_format(s, "mpls_bos=%"PRIu8",",
+                 mpls_lse_to_bos(f->mpls_lse));
+    }
     switch (wc->masks.nw_frag) {
     case FLOW_NW_FRAG_ANY | FLOW_NW_FRAG_LATER:
         ds_put_format(s, "nw_frag=%s,",
index ff0b5f2..d435aa4 100644 (file)
@@ -78,6 +78,12 @@ void match_set_vlan_vid(struct match *, ovs_be16);
 void match_set_vlan_vid_masked(struct match *, ovs_be16 vid, ovs_be16 mask);
 void match_set_any_pcp(struct match *);
 void match_set_dl_vlan_pcp(struct match *, uint8_t);
+void match_set_any_mpls_label(struct match *);
+void match_set_mpls_label(struct match *, ovs_be32);
+void match_set_any_mpls_tc(struct match *);
+void match_set_mpls_tc(struct match *, uint8_t);
+void match_set_any_mpls_bos(struct match *);
+void match_set_mpls_bos(struct match *, uint8_t);
 void match_set_tp_src(struct match *, ovs_be16);
 void match_set_tp_src_masked(struct match *, ovs_be16 port, ovs_be16 mask);
 void match_set_tp_dst(struct match *, ovs_be16);
index e25103d..6f7a3aa 100644 (file)
@@ -256,6 +256,38 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         OXM_OF_VLAN_PCP, "OXM_OF_VLAN_PCP",
     },
 
+    /* ## ---- ## */
+    /* ## L2.5 ## */
+    /* ## ---- ## */
+    {
+        MFF_MPLS_LABEL, "mpls_label", NULL,
+        4, 20,
+        MFM_NONE,
+        MFS_DECIMAL,
+        MFP_MPLS,
+        true,
+        OXM_OF_MPLS_LABEL, "OXM_OF_MPLS_LABEL",
+        OXM_OF_MPLS_LABEL, "OXM_OF_MPLS_LABEL",
+    }, {
+        MFF_MPLS_TC, "mpls_tc", NULL,
+        1, 3,
+        MFM_NONE,
+        MFS_DECIMAL,
+        MFP_MPLS,
+        true,
+        OXM_OF_MPLS_TC, "OXM_OF_MPLS_TC",
+        OXM_OF_MPLS_TC, "OXM_OF_MPLS_TC",
+    }, {
+        MFF_MPLS_BOS, "mpls_bos", NULL,
+        1, 1,
+        MFM_NONE,
+        MFS_DECIMAL,
+        MFP_MPLS,
+        false,
+        OXM_OF_MPLS_BOS, "OXM_OF_MPLS_BOS",
+        OXM_OF_MPLS_BOS, "OXM_OF_MPLS_BOS",
+    },
+
     /* ## -- ## */
     /* ## L3 ## */
     /* ## -- ## */
@@ -678,6 +710,13 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc)
     case MFF_VLAN_PCP:
         return !(wc->masks.vlan_tci & htons(VLAN_PCP_MASK));
 
+    case MFF_MPLS_LABEL:
+        return !(wc->masks.mpls_lse & htonl(MPLS_LABEL_MASK));
+    case MFF_MPLS_TC:
+        return !(wc->masks.mpls_lse & htonl(MPLS_TC_MASK));
+    case MFF_MPLS_BOS:
+        return !(wc->masks.mpls_lse & htonl(MPLS_BOS_MASK));
+
     case MFF_IPV4_SRC:
         return !wc->masks.nw_src;
     case MFF_IPV4_DST:
@@ -791,6 +830,8 @@ mf_are_prereqs_ok(const struct mf_field *mf, const struct flow *flow)
         return flow->dl_type == htons(ETH_TYPE_IPV6);
     case MFP_VLAN_VID:
         return (flow->vlan_tci & htons(VLAN_CFI)) != 0;
+    case MFP_MPLS:
+        return eth_type_mpls(flow->dl_type);
     case MFP_IP_ANY:
         return is_ip_any(flow);
 
@@ -895,6 +936,15 @@ mf_is_value_valid(const struct mf_field *mf, const union mf_value *value)
     case MFF_IPV6_LABEL:
         return !(value->be32 & ~htonl(IPV6_LABEL_MASK));
 
+    case MFF_MPLS_LABEL:
+        return !(value->be32 & ~htonl(MPLS_LABEL_MASK >> MPLS_LABEL_SHIFT));
+
+    case MFF_MPLS_TC:
+        return !(value->u8 & ~(MPLS_TC_MASK >> MPLS_TC_SHIFT));
+
+    case MFF_MPLS_BOS:
+        return !(value->u8 & ~(MPLS_BOS_MASK >> MPLS_BOS_SHIFT));
+
     case MFF_N_IDS:
     default:
         NOT_REACHED();
@@ -975,6 +1025,18 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow,
         value->u8 = vlan_tci_to_pcp(flow->vlan_tci);
         break;
 
+    case MFF_MPLS_LABEL:
+        value->be32 = htonl(mpls_lse_to_label(flow->mpls_lse));
+        break;
+
+    case MFF_MPLS_TC:
+        value->u8 = mpls_lse_to_tc(flow->mpls_lse);
+        break;
+
+    case MFF_MPLS_BOS:
+        value->u8 = mpls_lse_to_bos(flow->mpls_lse);
+        break;
+
     case MFF_IPV4_SRC:
         value->be32 = flow->nw_src;
         break;
@@ -1142,6 +1204,18 @@ mf_set_value(const struct mf_field *mf,
         match_set_dl_vlan_pcp(match, value->u8);
         break;
 
+    case MFF_MPLS_LABEL:
+        match_set_mpls_label(match, value->be32);
+        break;
+
+    case MFF_MPLS_TC:
+        match_set_mpls_tc(match, value->u8);
+        break;
+
+    case MFF_MPLS_BOS:
+        match_set_mpls_bos(match, value->u8);
+        break;
+
     case MFF_IPV4_SRC:
         match_set_nw_src(match, value->be32);
         break;
@@ -1309,6 +1383,18 @@ mf_set_flow_value(const struct mf_field *mf,
         flow_set_vlan_pcp(flow, value->u8);
         break;
 
+    case MFF_MPLS_LABEL:
+        flow_set_mpls_label(flow, value->be32);
+        break;
+
+    case MFF_MPLS_TC:
+        flow_set_mpls_tc(flow, value->u8);
+        break;
+
+    case MFF_MPLS_BOS:
+        flow_set_mpls_bos(flow, value->u8);
+        break;
+
     case MFF_IPV4_SRC:
         flow->nw_src = value->be32;
         break;
@@ -1445,6 +1531,7 @@ mf_set_wild(const struct mf_field *mf, struct match *match)
 
     case MFF_METADATA:
         match_set_metadata_masked(match, htonll(0), htonll(0));
+        break;
 
     case MFF_IN_PORT:
         match->flow.in_port = 0;
@@ -1494,6 +1581,18 @@ mf_set_wild(const struct mf_field *mf, struct match *match)
         match_set_any_pcp(match);
         break;
 
+    case MFF_MPLS_LABEL:
+        match_set_any_mpls_label(match);
+        break;
+
+    case MFF_MPLS_TC:
+        match_set_any_mpls_tc(match);
+        break;
+
+    case MFF_MPLS_BOS:
+        match_set_any_mpls_bos(match);
+        break;
+
     case MFF_IPV4_SRC:
     case MFF_ARP_SPA:
         match_set_nw_src_masked(match, htonl(0), htonl(0));
@@ -1621,6 +1720,9 @@ mf_set(const struct mf_field *mf,
     case MFF_DL_VLAN:
     case MFF_DL_VLAN_PCP:
     case MFF_VLAN_PCP:
+    case MFF_MPLS_LABEL:
+    case MFF_MPLS_TC:
+    case MFF_MPLS_BOS:
     case MFF_IP_PROTO:
     case MFF_IP_TTL:
     case MFF_IP_DSCP:
@@ -1878,6 +1980,18 @@ mf_random_value(const struct mf_field *mf, union mf_value *value)
         value->u8 &= 0x07;
         break;
 
+    case MFF_MPLS_LABEL:
+        value->be32 &= htonl(MPLS_LABEL_MASK >> MPLS_LABEL_SHIFT);
+        break;
+
+    case MFF_MPLS_TC:
+        value->u8 &= MPLS_TC_MASK >> MPLS_TC_SHIFT;
+        break;
+
+    case MFF_MPLS_BOS:
+        value->u8 &= MPLS_BOS_MASK >> MPLS_BOS_SHIFT;
+        break;
+
     case MFF_N_IDS:
     default:
         NOT_REACHED();
@@ -2235,15 +2349,12 @@ mf_format_integer_string(const struct mf_field *mf, const uint8_t *valuep,
 }
 
 static void
-mf_format_frag_string(const uint8_t *valuep, const uint8_t *maskp,
-                      struct ds *s)
+mf_format_frag_string(uint8_t value, uint8_t mask, struct ds *s)
 {
     const struct frag_handling *h;
-    uint8_t value = *valuep;
-    uint8_t mask = *maskp;
 
-    value &= mask;
     mask &= FLOW_NW_FRAG_MASK;
+    value &= mask;
 
     for (h = all_frags; h < &all_frags[ARRAY_SIZE(all_frags)]; h++) {
         if (value == h->value && mask == h->mask) {
@@ -2302,7 +2413,7 @@ mf_format(const struct mf_field *mf,
         break;
 
     case MFS_FRAG:
-        mf_format_frag_string(&value->u8, &mask->u8, s);
+        mf_format_frag_string(value->u8, mask ? mask->u8 : UINT8_MAX, s);
         break;
 
     case MFS_TNL_FLAGS:
index 3675883..57f6df5 100644 (file)
@@ -78,6 +78,11 @@ enum mf_field_id {
     MFF_DL_VLAN_PCP,            /* u8 (OpenFlow 1.0 compatibility) */
     MFF_VLAN_PCP,               /* be16 (OpenFlow 1.2 compatibility) */
 
+    /* L2.5 */
+    MFF_MPLS_LABEL,             /* be32 */
+    MFF_MPLS_TC,                /* u8 */
+    MFF_MPLS_BOS,               /* u8 */
+
     /* L3. */
     MFF_IPV4_SRC,               /* be32 */
     MFF_IPV4_DST,               /* be32 */
@@ -168,6 +173,9 @@ enum mf_prereqs {
     MFP_IPV6,
     MFP_IP_ANY,
 
+    /* L2.5 requirements. */
+    MFP_MPLS,
+
     /* L2+L3 requirements. */
     MFP_TCP,                    /* On IPv4 or IPv6. */
     MFP_UDP,                    /* On IPv4 or IPv6. */
@@ -220,6 +228,9 @@ struct mf_field {
      *     - "dl_vlan_pcp" is 1 byte but only 3 bits.
      *     - "is_frag" is 1 byte but only 2 bits.
      *     - "ipv6_label" is 4 bytes but only 20 bits.
+     *     - "mpls_label" is 4 bytes but only 20 bits.
+     *     - "mpls_tc"    is 1 byte but only 3 bits.
+     *     - "mpls_bos"   is 1 byte but only 1 bit.
      */
     unsigned int n_bytes;       /* Width of the field in bytes. */
     unsigned int n_bits;        /* Number of significant bits in field. */
index f81b68e..234d7bc 100644 (file)
@@ -204,6 +204,19 @@ netdev_dummy_drain(struct netdev *netdev_)
     return 0;
 }
 
+static int
+netdev_dummy_send(struct netdev *netdev, const void *buffer OVS_UNUSED,
+                  size_t size)
+{
+    struct netdev_dev_dummy *dev =
+        netdev_dev_dummy_cast(netdev_get_dev(netdev));
+
+    dev->stats.tx_packets++;
+    dev->stats.tx_bytes += size;
+
+    return 0;
+}
+
 static int
 netdev_dummy_set_etheraddr(struct netdev *netdev,
                            const uint8_t mac[ETH_ADDR_LEN])
@@ -336,7 +349,7 @@ static const struct netdev_class dummy_class = {
     netdev_dummy_recv_wait,
     netdev_dummy_drain,
 
-    NULL,                       /* send */
+    netdev_dummy_send,          /* send */
     NULL,                       /* send_wait */
 
     netdev_dummy_set_etheraddr,
@@ -443,6 +456,9 @@ netdev_dummy_receive(struct unixctl_conn *conn,
             return;
         }
 
+        dummy_dev->stats.rx_packets++;
+        dummy_dev->stats.rx_bytes += packet->size;
+
         n_listeners = 0;
         LIST_FOR_EACH (dev, node, &dummy_dev->devs) {
             if (dev->listening) {
index 5de4fa2..4ea7a36 100644 (file)
@@ -4639,7 +4639,11 @@ af_packet_sock(void)
     if (sock == INT_MIN) {
         sock = socket(AF_PACKET, SOCK_RAW, 0);
         if (sock >= 0) {
-            set_nonblocking(sock);
+            int error = set_nonblocking(sock);
+            if (error) {
+                close(sock);
+                sock = -error;
+            }
         } else {
             sock = -errno;
             VLOG_ERR("failed to create packet socket: %s", strerror(errno));
index b892f8f..d696404 100644 (file)
@@ -44,6 +44,8 @@ VLOG_DEFINE_THIS_MODULE(netdev_vport);
 /* Default to the OTV port, per the VXLAN IETF draft. */
 #define VXLAN_DST_PORT 8472
 
+#define LISP_DST_PORT 4341
+
 #define DEFAULT_TTL 64
 
 struct netdev_dev_vport {
@@ -67,6 +69,7 @@ struct vport_class {
 static int netdev_vport_create(const struct netdev_class *, const char *,
                                struct netdev_dev **);
 static int get_patch_config(struct netdev_dev *, struct smap *args);
+static int get_tunnel_config(struct netdev_dev *, struct smap *args);
 static void netdev_vport_poll_notify(struct netdev_dev_vport *);
 
 static bool
@@ -110,6 +113,16 @@ netdev_vport_is_patch(const struct netdev *netdev)
     return class->get_config == get_patch_config;
 }
 
+static bool
+netdev_vport_needs_dst_port(const struct netdev_dev *dev)
+{
+    const struct netdev_class *class = netdev_dev_get_class(dev);
+    const char *type = netdev_dev_get_type(dev);
+
+    return (class->get_config == get_tunnel_config &&
+            (!strcmp("vxlan", type) || !strcmp("lisp", type)));
+}
+
 const char *
 netdev_vport_get_dpif_port(const struct netdev *netdev)
 {
@@ -117,9 +130,27 @@ netdev_vport_get_dpif_port(const struct netdev *netdev)
     const struct netdev_class *class = netdev_dev_get_class(dev);
     const char *dpif_port;
 
-    dpif_port = (is_vport_class(class)
-                 ? vport_class_cast(class)->dpif_port
-                 : NULL);
+    if (netdev_vport_needs_dst_port(dev)) {
+        const struct netdev_dev_vport *vport = netdev_vport_get_dev(netdev);
+        const char *type = netdev_dev_get_type(dev);
+        static char dpif_port_combined[IFNAMSIZ];
+
+        /*
+         * Note: IFNAMSIZ is 16 bytes long. The maximum length of a VXLAN
+         * or LISP port name below is 15 or 14 bytes respectively. Still,
+         * assert here on the size of strlen(type) in case that changes
+         * in the future.
+         */
+        ovs_assert(strlen(type) + 10 < IFNAMSIZ);
+        snprintf(dpif_port_combined, IFNAMSIZ, "%s_sys_%d", type,
+                 ntohs(vport->tnl_cfg.dst_port));
+        return dpif_port_combined;
+    } else {
+        dpif_port = (is_vport_class(class)
+                     ? vport_class_cast(class)->dpif_port
+                     : NULL);
+    }
+
     return dpif_port ? dpif_port : netdev_get_name(netdev);
 }
 
@@ -289,11 +320,7 @@ set_tunnel_config(struct netdev_dev *dev_, const struct smap *args)
     ipsec_mech_set = false;
     memset(&tnl_cfg, 0, sizeof tnl_cfg);
 
-    if (!strcmp(type, "capwap")) {
-        VLOG_WARN_ONCE("CAPWAP tunnel support is deprecated.");
-    }
-
-    needs_dst_port = !strcmp(type, "vxlan");
+    needs_dst_port = netdev_vport_needs_dst_port(dev_);
     tnl_cfg.ipsec = strstr(type, "ipsec");
     tnl_cfg.dont_fragment = true;
 
@@ -378,10 +405,15 @@ set_tunnel_config(struct netdev_dev *dev_, const struct smap *args)
     }
 
     /* Add a default destination port for VXLAN if none specified. */
-    if (needs_dst_port && !tnl_cfg.dst_port) {
+    if (!strcmp(type, "vxlan") && !tnl_cfg.dst_port) {
         tnl_cfg.dst_port = htons(VXLAN_DST_PORT);
     }
 
+    /* Add a default destination port for LISP if none specified. */
+    if (!strcmp(type, "lisp") && !tnl_cfg.dst_port) {
+        tnl_cfg.dst_port = htons(LISP_DST_PORT);
+    }
+
     if (tnl_cfg.ipsec) {
         static pid_t pid = 0;
         if (pid <= 0) {
@@ -661,8 +693,8 @@ netdev_vport_tunnel_register(void)
         TUNNEL_CLASS("ipsec_gre", "gre_system"),
         TUNNEL_CLASS("gre64", "gre64_system"),
         TUNNEL_CLASS("ipsec_gre64", "gre64_system"),
-        TUNNEL_CLASS("capwap", "capwap_system"),
-        TUNNEL_CLASS("vxlan", "vxlan_system")
+        TUNNEL_CLASS("vxlan", "vxlan_system"),
+        TUNNEL_CLASS("lisp", "lisp_system")
     };
 
     int i;
index 847f11f..e6b10a1 100644 (file)
@@ -128,8 +128,12 @@ nl_sock_create(int protocol, struct nl_sock **sockp)
     rcvbuf = 1024 * 1024;
     if (setsockopt(sock->fd, SOL_SOCKET, SO_RCVBUFFORCE,
                    &rcvbuf, sizeof rcvbuf)) {
-        VLOG_WARN_RL(&rl, "setting %d-byte socket receive buffer failed (%s)",
-                     rcvbuf, strerror(errno));
+        /* Only root can use SO_RCVBUFFORCE.  Everyone else gets EPERM.
+         * Warn only if the failure is therefore unexpected. */
+        if (errno != EPERM || !getuid()) {
+            VLOG_WARN_RL(&rl, "setting %d-byte socket receive buffer failed "
+                         "(%s)", rcvbuf, strerror(errno));
+        }
     }
 
     retval = get_socket_rcvbuf(sock->fd);
index 4d7fcd6..4ff516e 100644 (file)
@@ -573,7 +573,7 @@ nx_put_raw(struct ofpbuf *b, bool oxm, const struct match *match,
     int match_len;
     int i;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 18);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 19);
 
     /* Metadata. */
     if (match->wc.masks.in_port) {
@@ -615,6 +615,22 @@ nx_put_raw(struct ofpbuf *b, bool oxm, const struct match *match,
                     match->wc.masks.vlan_tci);
     }
 
+    /* MPLS. */
+    if (eth_type_mpls(flow->dl_type)) {
+        if (match->wc.masks.mpls_lse & htonl(MPLS_TC_MASK)) {
+            nxm_put_8(b, OXM_OF_MPLS_TC, mpls_lse_to_tc(flow->mpls_lse));
+        }
+
+        if (match->wc.masks.mpls_lse & htonl(MPLS_BOS_MASK)) {
+            nxm_put_8(b, OXM_OF_MPLS_BOS, mpls_lse_to_bos(flow->mpls_lse));
+        }
+
+        if (match->wc.masks.mpls_lse & htonl(MPLS_LABEL_MASK)) {
+            nxm_put_32(b, OXM_OF_MPLS_LABEL,
+                       htonl(mpls_lse_to_label(flow->mpls_lse)));
+        }
+    }
+
     /* L3. */
     if (flow->dl_type == htons(ETH_TYPE_IP)) {
         /* IP. */
index 7e48981..7bc1f6c 100644 (file)
@@ -73,6 +73,8 @@ odp_action_len(uint16_t type)
     case OVS_ACTION_ATTR_USERSPACE: return -2;
     case OVS_ACTION_ATTR_PUSH_VLAN: return sizeof(struct ovs_action_push_vlan);
     case OVS_ACTION_ATTR_POP_VLAN: return 0;
+    case OVS_ACTION_ATTR_PUSH_MPLS: return sizeof(struct ovs_action_push_mpls);
+    case OVS_ACTION_ATTR_POP_MPLS: return sizeof(ovs_be16);
     case OVS_ACTION_ATTR_SET: return -2;
     case OVS_ACTION_ATTR_SAMPLE: return -2;
 
@@ -108,6 +110,7 @@ ovs_key_attr_to_string(enum ovs_key_attr attr)
     case OVS_KEY_ATTR_ICMPV6: return "icmpv6";
     case OVS_KEY_ATTR_ARP: return "arp";
     case OVS_KEY_ATTR_ND: return "nd";
+    case OVS_KEY_ATTR_MPLS: return "mpls";
 
     case __OVS_KEY_ATTR_MAX:
     default:
@@ -245,9 +248,11 @@ format_odp_userspace_action(struct ds *ds, const struct nlattr *attr)
 {
     static const struct nl_policy ovs_userspace_policy[] = {
         [OVS_USERSPACE_ATTR_PID] = { .type = NL_A_U32 },
-        [OVS_USERSPACE_ATTR_USERDATA] = { .type = NL_A_U64, .optional = true },
+        [OVS_USERSPACE_ATTR_USERDATA] = { .type = NL_A_UNSPEC,
+                                          .optional = true },
     };
     struct nlattr *a[ARRAY_SIZE(ovs_userspace_policy)];
+    const struct nlattr *userdata_attr;
 
     if (!nl_parse_nested(attr, ovs_userspace_policy, a, ARRAY_SIZE(a))) {
         ds_put_cstr(ds, "userspace(error)");
@@ -257,7 +262,8 @@ format_odp_userspace_action(struct ds *ds, const struct nlattr *attr)
     ds_put_format(ds, "userspace(pid=%"PRIu32,
                   nl_attr_get_u32(a[OVS_USERSPACE_ATTR_PID]));
 
-    if (a[OVS_USERSPACE_ATTR_USERDATA]) {
+    userdata_attr = a[OVS_USERSPACE_ATTR_USERDATA];
+    if (userdata_attr && nl_attr_get_size(userdata_attr) == sizeof(uint64_t)) {
         uint64_t userdata = nl_attr_get_u64(a[OVS_USERSPACE_ATTR_USERDATA]);
         union user_action_cookie cookie;
 
@@ -284,6 +290,16 @@ format_odp_userspace_action(struct ds *ds, const struct nlattr *attr)
             ds_put_format(ds, ",userdata=0x%"PRIx64, userdata);
             break;
         }
+    } else if (userdata_attr) {
+        const uint8_t *userdata = nl_attr_get(userdata_attr);
+        size_t len = nl_attr_get_size(userdata_attr);
+        size_t i;
+
+        ds_put_format(ds, ",userdata(");
+        for (i = 0; i < len; i++) {
+            ds_put_format(ds, "%02x", userdata[i]);
+        }
+        ds_put_char(ds, ')');
     }
 
     ds_put_char(ds, ')');
@@ -300,6 +316,16 @@ format_vlan_tci(struct ds *ds, ovs_be16 vlan_tci)
     }
 }
 
+static void
+format_mpls_lse(struct ds *ds, ovs_be32 mpls_lse)
+{
+    ds_put_format(ds, "label=%"PRIu32",tc=%d,ttl=%d,bos=%d",
+                  mpls_lse_to_label(mpls_lse),
+                  mpls_lse_to_tc(mpls_lse),
+                  mpls_lse_to_ttl(mpls_lse),
+                  mpls_lse_to_bos(mpls_lse));
+}
+
 static void
 format_odp_action(struct ds *ds, const struct nlattr *a)
 {
@@ -339,6 +365,18 @@ format_odp_action(struct ds *ds, const struct nlattr *a)
     case OVS_ACTION_ATTR_POP_VLAN:
         ds_put_cstr(ds, "pop_vlan");
         break;
+    case OVS_ACTION_ATTR_PUSH_MPLS: {
+        const struct ovs_action_push_mpls *mpls = nl_attr_get(a);
+        ds_put_cstr(ds, "push_mpls(");
+        format_mpls_lse(ds, mpls->mpls_lse);
+        ds_put_format(ds, ",eth_type=0x%"PRIx16")", ntohs(mpls->mpls_ethertype));
+        break;
+    }
+    case OVS_ACTION_ATTR_POP_MPLS: {
+        ovs_be16 ethertype = nl_attr_get_be16(a);
+        ds_put_format(ds, "pop_mpls(eth_type=0x%"PRIx16")", ntohs(ethertype));
+        break;
+    }
     case OVS_ACTION_ATTR_SAMPLE:
         format_odp_sample_action(ds, a);
         break;
@@ -424,7 +462,7 @@ parse_odp_action(const char *s, const struct simap *port_names,
         int n = -1;
 
         if (sscanf(s, "userspace(pid=%lli)%n", &pid, &n) > 0 && n > 0) {
-            odp_put_userspace_action(pid, NULL, actions);
+            odp_put_userspace_action(pid, NULL, 0, actions);
             return n;
         } else if (sscanf(s, "userspace(pid=%lli,sFlow(vid=%i,"
                           "pcp=%i,output=%lli))%n",
@@ -440,7 +478,7 @@ parse_odp_action(const char *s, const struct simap *port_names,
             cookie.type = USER_ACTION_COOKIE_SFLOW;
             cookie.sflow.vlan_tci = htons(tci);
             cookie.sflow.output = output;
-            odp_put_userspace_action(pid, &cookie, actions);
+            odp_put_userspace_action(pid, &cookie, sizeof cookie, actions);
             return n;
         } else if (sscanf(s, "userspace(pid=%lli,slow_path%n", &pid, &n) > 0
                    && n > 0) {
@@ -462,18 +500,29 @@ parse_odp_action(const char *s, const struct simap *port_names,
             }
             n++;
 
-            odp_put_userspace_action(pid, &cookie, actions);
+            odp_put_userspace_action(pid, &cookie, sizeof cookie, actions);
             return n;
         } else if (sscanf(s, "userspace(pid=%lli,userdata="
                           "%31[x0123456789abcdefABCDEF])%n", &pid, userdata_s,
                           &n) > 0 && n > 0) {
-            union user_action_cookie cookie;
             uint64_t userdata;
 
             userdata = strtoull(userdata_s, NULL, 0);
-            memcpy(&cookie, &userdata, sizeof cookie);
-            odp_put_userspace_action(pid, &cookie, actions);
+            odp_put_userspace_action(pid, &userdata, sizeof(userdata),
+                                     actions);
             return n;
+        } else if (sscanf(s, "userspace(pid=%lli,userdata(%n", &pid, &n) > 0
+                   && n > 0) {
+            struct ofpbuf buf;
+            char *end;
+
+            ofpbuf_init(&buf, 16);
+            end = ofpbuf_put_hex(&buf, &s[n], NULL);
+            if (end[0] == ')' && end[1] == ')') {
+                odp_put_userspace_action(pid, buf.data, buf.size, actions);
+                ofpbuf_uninit(&buf);
+                return (end + 2) - s;
+            }
         }
     }
 
@@ -622,6 +671,7 @@ odp_flow_key_attr_len(uint16_t type)
     case OVS_KEY_ATTR_ETHERNET: return sizeof(struct ovs_key_ethernet);
     case OVS_KEY_ATTR_VLAN: return sizeof(ovs_be16);
     case OVS_KEY_ATTR_ETHERTYPE: return 2;
+    case OVS_KEY_ATTR_MPLS: return sizeof(struct ovs_key_mpls);
     case OVS_KEY_ATTR_IPV4: return sizeof(struct ovs_key_ipv4);
     case OVS_KEY_ATTR_IPV6: return sizeof(struct ovs_key_ipv6);
     case OVS_KEY_ATTR_TCP: return sizeof(struct ovs_key_tcp);
@@ -859,6 +909,14 @@ format_odp_key_attr(const struct nlattr *a, struct ds *ds)
         ds_put_char(ds, ')');
         break;
 
+    case OVS_KEY_ATTR_MPLS: {
+        const struct ovs_key_mpls *mpls_key = nl_attr_get(a);
+        ds_put_char(ds, '(');
+        format_mpls_lse(ds, mpls_key->mpls_top_lse);
+        ds_put_char(ds, ')');
+        break;
+    }
+
     case OVS_KEY_ATTR_ETHERTYPE:
         ds_put_format(ds, "(0x%04"PRIx16")",
                       ntohs(nl_attr_get_be16(a)));
@@ -1019,6 +1077,15 @@ ovs_frag_type_from_string(const char *s, enum ovs_frag_type *type)
     return true;
 }
 
+static ovs_be32
+mpls_lse_from_components(int mpls_label, int mpls_tc, int mpls_ttl, int mpls_bos)
+{
+    return (htonl((mpls_label << MPLS_LABEL_SHIFT) |
+                  (mpls_tc << MPLS_TC_SHIFT)       |
+                  (mpls_ttl << MPLS_TTL_SHIFT)     |
+                  (mpls_bos << MPLS_BOS_SHIFT)));
+}
+
 static int
 parse_odp_key_attr(const char *s, const struct simap *port_names,
                    struct ofpbuf *key)
@@ -1171,6 +1238,22 @@ parse_odp_key_attr(const char *s, const struct simap *port_names,
         }
     }
 
+    {
+        int label, tc, ttl, bos;
+        int n = -1;
+
+        if (sscanf(s, "mpls(label=%"SCNi32",tc=%i,ttl=%i,bos=%i)%n",
+                    &label, &tc, &ttl, &bos, &n) > 0 &&
+                    n > 0) {
+            struct ovs_key_mpls *mpls;
+
+            mpls = nl_msg_put_unspec_uninit(key, OVS_KEY_ATTR_MPLS,
+                                            sizeof *mpls);
+            mpls->mpls_top_lse = mpls_lse_from_components(label, tc, ttl, bos);
+            return n;
+        }
+    }
+
     {
         ovs_be32 ipv4_src;
         ovs_be32 ipv4_dst;
@@ -1526,6 +1609,14 @@ odp_flow_key_from_flow(struct ofpbuf *buf, const struct flow *flow,
         memcpy(arp_key->arp_tha, flow->arp_tha, ETH_ADDR_LEN);
     }
 
+    if (flow->mpls_depth) {
+        struct ovs_key_mpls *mpls_key;
+
+        mpls_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_MPLS,
+                                            sizeof *mpls_key);
+        mpls_key->mpls_top_lse = flow->mpls_lse;
+    }
+
     if (is_ip_any(flow) && !(flow->nw_frag & FLOW_NW_FRAG_LATER)) {
         if (flow->nw_proto == IPPROTO_TCP) {
             struct ovs_key_tcp *tcp_key;
@@ -1728,14 +1819,38 @@ parse_ethertype(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1],
 }
 
 static enum odp_key_fitness
-parse_l3_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1],
-                uint64_t present_attrs, int out_of_range_attr,
-                uint64_t expected_attrs, struct flow *flow,
-                const struct nlattr *key, size_t key_len)
+parse_l2_5_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1],
+                  uint64_t present_attrs, int out_of_range_attr,
+                  uint64_t expected_attrs, struct flow *flow,
+                  const struct nlattr *key, size_t key_len)
 {
     static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+    ovs_be16 dl_type;
 
-    if (flow->dl_type == htons(ETH_TYPE_IP)) {
+    /* Parse MPLS label stack entry */
+    if (eth_type_mpls(flow->dl_type)) {
+        /* Calculate fitness of outer attributes. */
+        expected_attrs |= (UINT64_C(1) << OVS_KEY_ATTR_MPLS);
+
+        /* Get the MPLS LSE value. */
+        if (!(present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_MPLS))) {
+            return ODP_FIT_TOO_LITTLE;
+        }
+        flow->mpls_lse = nl_attr_get_be32(attrs[OVS_KEY_ATTR_MPLS]);
+        flow->mpls_depth++;
+
+        if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_IPV4)) {
+            flow->encap_dl_type = htons(ETH_TYPE_IP);
+        } else if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_IPV6)) {
+            flow->encap_dl_type = htons(ETH_TYPE_IPV6);
+        } else if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_ARP)) {
+            flow->encap_dl_type = htons(ETH_TYPE_ARP);
+        }
+    }
+
+    dl_type = flow_innermost_dl_type(flow);
+
+    if (dl_type == htons(ETH_TYPE_IP)) {
         expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_IPV4;
         if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_IPV4)) {
             const struct ovs_key_ipv4 *ipv4_key;
@@ -1750,7 +1865,7 @@ parse_l3_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1],
                 return ODP_FIT_ERROR;
             }
         }
-    } else if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
+    } else if (dl_type == htons(ETH_TYPE_IPV6)) {
         expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_IPV6;
         if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_IPV6)) {
             const struct ovs_key_ipv6 *ipv6_key;
@@ -1766,8 +1881,8 @@ parse_l3_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1],
                 return ODP_FIT_ERROR;
             }
         }
-    } else if (flow->dl_type == htons(ETH_TYPE_ARP) ||
-               flow->dl_type == htons(ETH_TYPE_RARP)) {
+    } else if (dl_type == htons(ETH_TYPE_ARP) ||
+               dl_type == htons(ETH_TYPE_RARP)) {
         expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_ARP;
         if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_ARP)) {
             const struct ovs_key_arp *arp_key;
@@ -1787,7 +1902,8 @@ parse_l3_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1],
     }
 
     if (flow->nw_proto == IPPROTO_TCP
-        && is_ip_any(flow)
+        && (dl_type == htons(ETH_TYPE_IP) ||
+            dl_type == htons(ETH_TYPE_IPV6))
         && !(flow->nw_frag & FLOW_NW_FRAG_LATER)) {
         expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_TCP;
         if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_TCP)) {
@@ -1798,7 +1914,8 @@ parse_l3_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1],
             flow->tp_dst = tcp_key->tcp_dst;
         }
     } else if (flow->nw_proto == IPPROTO_UDP
-               && is_ip_any(flow)
+               && (dl_type == htons(ETH_TYPE_IP) ||
+                   dl_type == htons(ETH_TYPE_IPV6))
                && !(flow->nw_frag & FLOW_NW_FRAG_LATER)) {
         expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_UDP;
         if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_UDP)) {
@@ -1809,7 +1926,7 @@ parse_l3_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1],
             flow->tp_dst = udp_key->udp_dst;
         }
     } else if (flow->nw_proto == IPPROTO_ICMP
-               && flow->dl_type == htons(ETH_TYPE_IP)
+               && dl_type == htons(ETH_TYPE_IP)
                && !(flow->nw_frag & FLOW_NW_FRAG_LATER)) {
         expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_ICMP;
         if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_ICMP)) {
@@ -1820,7 +1937,7 @@ parse_l3_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1],
             flow->tp_dst = htons(icmp_key->icmp_code);
         }
     } else if (flow->nw_proto == IPPROTO_ICMPV6
-               && flow->dl_type == htons(ETH_TYPE_IPV6)
+               && dl_type == htons(ETH_TYPE_IPV6)
                && !(flow->nw_frag & FLOW_NW_FRAG_LATER)) {
         expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_ICMPV6;
         if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_ICMPV6)) {
@@ -1904,8 +2021,8 @@ parse_8021q_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1],
     if (!parse_ethertype(attrs, present_attrs, &expected_attrs, flow)) {
         return ODP_FIT_ERROR;
     }
-    encap_fitness = parse_l3_onward(attrs, present_attrs, out_of_range_attr,
-                                    expected_attrs, flow, key, key_len);
+    encap_fitness = parse_l2_5_onward(attrs, present_attrs, out_of_range_attr,
+                                      expected_attrs, flow, key, key_len);
 
     /* The overall fitness is the worse of the outer and inner attributes. */
     return MAX(fitness, encap_fitness);
@@ -1997,8 +2114,8 @@ odp_flow_key_to_flow(const struct nlattr *key, size_t key_len,
         return parse_8021q_onward(attrs, present_attrs, out_of_range_attr,
                                   expected_attrs, flow, key, key_len);
     }
-    return parse_l3_onward(attrs, present_attrs, out_of_range_attr,
-                           expected_attrs, flow, key, key_len);
+    return parse_l2_5_onward(attrs, present_attrs, out_of_range_attr,
+                             expected_attrs, flow, key, key_len);
 }
 
 /* Returns 'fitness' as a string, for use in debug messages. */
@@ -2020,25 +2137,30 @@ odp_key_fitness_to_string(enum odp_key_fitness fitness)
 }
 
 /* Appends an OVS_ACTION_ATTR_USERSPACE action to 'odp_actions' that specifies
- * Netlink PID 'pid'.  If 'cookie' is nonnull, adds a userdata attribute whose
- * contents contains 'cookie' and returns the offset within 'odp_actions' of
- * the start of the cookie.  (If 'cookie' is null, then the return value is not
- * meaningful.) */
+ * Netlink PID 'pid'.  If 'userdata' is nonnull, adds a userdata attribute
+ * whose contents are the 'userdata_size' bytes at 'userdata' and returns the
+ * offset within 'odp_actions' of the start of the cookie.  (If 'userdata' is
+ * null, then the return value is not meaningful.) */
 size_t
-odp_put_userspace_action(uint32_t pid, const union user_action_cookie *cookie,
+odp_put_userspace_action(uint32_t pid,
+                         const void *userdata, size_t userdata_size,
                          struct ofpbuf *odp_actions)
 {
+    size_t userdata_ofs;
     size_t offset;
 
     offset = nl_msg_start_nested(odp_actions, OVS_ACTION_ATTR_USERSPACE);
     nl_msg_put_u32(odp_actions, OVS_USERSPACE_ATTR_PID, pid);
-    if (cookie) {
+    if (userdata) {
+        userdata_ofs = odp_actions->size + NLA_HDRLEN;
         nl_msg_put_unspec(odp_actions, OVS_USERSPACE_ATTR_USERDATA,
-                          cookie, sizeof *cookie);
+                          userdata, userdata_size);
+    } else {
+        userdata_ofs = 0;
     }
     nl_msg_end_nested(odp_actions, offset);
 
-    return cookie ? odp_actions->size - NLA_ALIGN(sizeof *cookie) : 0;
+    return userdata_ofs;
 }
 
 void
@@ -2061,6 +2183,14 @@ commit_set_action(struct ofpbuf *odp_actions, enum ovs_key_attr key_type,
     nl_msg_end_nested(odp_actions, offset);
 }
 
+void
+odp_put_skb_mark_action(const uint32_t skb_mark,
+                        struct ofpbuf *odp_actions)
+{
+    commit_set_action(odp_actions, OVS_KEY_ATTR_SKB_MARK, &skb_mark,
+                      sizeof(skb_mark));
+}
+
 /* If any of the flow key data that ODP actions can modify are different in
  * 'base->tunnel' and 'flow->tunnel', appends a set_tunnel ODP action to
  * 'odp_actions' that change the flow tunneling information in key from
@@ -2129,6 +2259,50 @@ commit_vlan_action(const struct flow *flow, struct flow *base,
     base->vlan_tci = flow->vlan_tci;
 }
 
+static void
+commit_mpls_action(const struct flow *flow, struct flow *base,
+                   struct ofpbuf *odp_actions)
+{
+    if (flow->mpls_lse == base->mpls_lse &&
+        flow->mpls_depth == base->mpls_depth) {
+        return;
+    }
+
+    if (flow->mpls_depth < base->mpls_depth) {
+        if (base->mpls_depth - flow->mpls_depth > 1) {
+            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(10, 10);
+            VLOG_WARN_RL(&rl, "Multiple mpls_pop actions reduced to "
+                         " a single mpls_pop action");
+        }
+
+        nl_msg_put_be16(odp_actions, OVS_ACTION_ATTR_POP_MPLS, flow->dl_type);
+    } else if (flow->mpls_depth > base->mpls_depth) {
+        struct ovs_action_push_mpls *mpls;
+
+        if (flow->mpls_depth - base->mpls_depth > 1) {
+            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(10, 10);
+            VLOG_WARN_RL(&rl, "Multiple mpls_push actions reduced to "
+                         " a single mpls_push action");
+        }
+
+        mpls = nl_msg_put_unspec_uninit(odp_actions, OVS_ACTION_ATTR_PUSH_MPLS,
+                                        sizeof *mpls);
+        memset(mpls, 0, sizeof *mpls);
+        mpls->mpls_ethertype = flow->dl_type;
+        mpls->mpls_lse = flow->mpls_lse;
+    } else {
+        struct ovs_key_mpls mpls_key;
+
+        mpls_key.mpls_top_lse = flow->mpls_lse;
+        commit_set_action(odp_actions, OVS_KEY_ATTR_MPLS,
+                          &mpls_key, sizeof(mpls_key));
+    }
+
+    base->dl_type = flow->dl_type;
+    base->mpls_lse = flow->mpls_lse;
+    base->mpls_depth = flow->mpls_depth;
+}
+
 static void
 commit_set_ipv4_action(const struct flow *flow, struct flow *base,
                      struct ofpbuf *odp_actions)
@@ -2188,14 +2362,16 @@ static void
 commit_set_nw_action(const struct flow *flow, struct flow *base,
                      struct ofpbuf *odp_actions)
 {
+    ovs_be16 dl_type = flow_innermost_dl_type(flow);
+
     /* Check if flow really have an IP header. */
     if (!flow->nw_proto) {
         return;
     }
 
-    if (base->dl_type == htons(ETH_TYPE_IP)) {
+    if (dl_type == htons(ETH_TYPE_IP)) {
         commit_set_ipv4_action(flow, base, odp_actions);
-    } else if (base->dl_type == htons(ETH_TYPE_IPV6)) {
+    } else if (dl_type == htons(ETH_TYPE_IPV6)) {
         commit_set_ipv6_action(flow, base, odp_actions);
     }
 }
@@ -2255,8 +2431,7 @@ commit_set_skb_mark_action(const struct flow *flow, struct flow *base,
     }
     base->skb_mark = flow->skb_mark;
 
-    commit_set_action(odp_actions, OVS_KEY_ATTR_SKB_MARK,
-                      &base->skb_mark, sizeof(base->skb_mark));
+    odp_put_skb_mark_action(base->skb_mark, odp_actions);
 }
 /* If any of the flow key data that ODP actions can modify are different in
  * 'base' and 'flow', appends ODP actions to 'odp_actions' that change the flow
@@ -2269,6 +2444,7 @@ commit_odp_actions(const struct flow *flow, struct flow *base,
 {
     commit_set_ether_addr_action(flow, base, odp_actions);
     commit_vlan_action(flow, base, odp_actions);
+    commit_mpls_action(flow, base, odp_actions);
     commit_set_nw_action(flow, base, odp_actions);
     commit_set_port_action(flow, base, odp_actions);
     commit_set_priority_action(flow, base, odp_actions);
index ccf6c2a..1b13e64 100644 (file)
@@ -152,10 +152,12 @@ union user_action_cookie {
 BUILD_ASSERT_DECL(sizeof(union user_action_cookie) == 8);
 
 size_t odp_put_userspace_action(uint32_t pid,
-                                const union user_action_cookie *,
+                                const void *userdata, size_t userdata_size,
                                 struct ofpbuf *odp_actions);
 void odp_put_tunnel_action(const struct flow_tnl *tunnel,
                            struct ofpbuf *odp_actions);
+void odp_put_skb_mark_action(const uint32_t skb_mark,
+                             struct ofpbuf *odp_actions);
 
 /* Reasons why a subfacet might not be fast-pathable. */
 enum slow_path_reason {
index a439d13..d6fc429 100644 (file)
@@ -16,7 +16,6 @@
 
 #include <config.h>
 #include "ofp-actions.h"
-#include "autopath.h"
 #include "bundle.h"
 #include "byte-order.h"
 #include "compiler.h"
@@ -357,11 +356,6 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code,
                                         ofpact_put_MULTIPATH(out));
         break;
 
-    case OFPUTIL_NXAST_AUTOPATH__DEPRECATED:
-        error = autopath_from_openflow((const struct nx_action_autopath *) a,
-                                       ofpact_put_AUTOPATH(out));
-        break;
-
     case OFPUTIL_NXAST_BUNDLE:
     case OFPUTIL_NXAST_BUNDLE_LOAD:
         error = bundle_from_openflow((const struct nx_action_bundle *) a, out);
@@ -402,6 +396,24 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code,
     case OFPUTIL_NXAST_CONTROLLER:
         controller_from_openflow((const struct nx_action_controller *) a, out);
         break;
+
+    case OFPUTIL_NXAST_PUSH_MPLS: {
+        struct nx_action_push_mpls *nxapm = (struct nx_action_push_mpls *)a;
+        if (!eth_type_mpls(nxapm->ethertype)) {
+            return OFPERR_OFPBAC_BAD_ARGUMENT;
+        }
+        ofpact_put_PUSH_MPLS(out)->ethertype = nxapm->ethertype;
+        break;
+    }
+
+    case OFPUTIL_NXAST_POP_MPLS: {
+        struct nx_action_pop_mpls *nxapm = (struct nx_action_pop_mpls *)a;
+        if (eth_type_mpls(nxapm->ethertype)) {
+            return OFPERR_OFPBAC_BAD_ARGUMENT;
+        }
+        ofpact_put_POP_MPLS(out)->ethertype = nxapm->ethertype;
+        break;
+    }
     }
 
     return error;
@@ -774,6 +786,24 @@ ofpact_from_openflow11(const union ofp_action *a, struct ofpbuf *out)
         return nxm_reg_load_from_openflow12_set_field(
             (const struct ofp12_action_set_field *)a, out);
 
+    case OFPUTIL_OFPAT11_PUSH_MPLS: {
+        struct ofp11_action_push *oap = (struct ofp11_action_push *)a;
+        if (!eth_type_mpls(oap->ethertype)) {
+            return OFPERR_OFPBAC_BAD_ARGUMENT;
+        }
+        ofpact_put_PUSH_MPLS(out)->ethertype = oap->ethertype;
+        break;
+    }
+
+    case OFPUTIL_OFPAT11_POP_MPLS: {
+        struct ofp11_action_pop_mpls *oapm = (struct ofp11_action_pop_mpls *)a;
+        if (eth_type_mpls(oapm->ethertype)) {
+            return OFPERR_OFPBAC_BAD_ARGUMENT;
+        }
+        ofpact_put_POP_MPLS(out)->ethertype = oapm->ethertype;
+        break;
+    }
+
 #define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) case OFPUTIL_##ENUM:
 #include "ofp-util.def"
         return ofpact_from_nxast(a, code, out);
@@ -1053,7 +1083,8 @@ exit:
 }
 \f
 static enum ofperr
-ofpact_check__(const struct ofpact *a, const struct flow *flow, int max_ports)
+ofpact_check__(const struct ofpact *a, const struct flow *flow, int max_ports,
+               ovs_be16 *dl_type)
 {
     const struct ofpact_enqueue *enqueue;
 
@@ -1096,7 +1127,13 @@ ofpact_check__(const struct ofpact *a, const struct flow *flow, int max_ports)
         return nxm_reg_move_check(ofpact_get_REG_MOVE(a), flow);
 
     case OFPACT_REG_LOAD:
-        return nxm_reg_load_check(ofpact_get_REG_LOAD(a), flow);
+        if (*dl_type != flow->dl_type) {
+            struct flow updated_flow = *flow;
+            updated_flow.dl_type = *dl_type;
+            return nxm_reg_load_check(ofpact_get_REG_LOAD(a), &updated_flow);
+        } else {
+            return nxm_reg_load_check(ofpact_get_REG_LOAD(a), flow);
+        }
 
     case OFPACT_DEC_TTL:
     case OFPACT_SET_TUNNEL:
@@ -1112,13 +1149,18 @@ ofpact_check__(const struct ofpact *a, const struct flow *flow, int max_ports)
     case OFPACT_MULTIPATH:
         return multipath_check(ofpact_get_MULTIPATH(a), flow);
 
-    case OFPACT_AUTOPATH:
-        return autopath_check(ofpact_get_AUTOPATH(a), flow);
-
     case OFPACT_NOTE:
     case OFPACT_EXIT:
         return 0;
 
+    case OFPACT_PUSH_MPLS:
+        *dl_type = ofpact_get_PUSH_MPLS(a)->ethertype;
+        return 0;
+
+    case OFPACT_POP_MPLS:
+        *dl_type = ofpact_get_POP_MPLS(a)->ethertype;
+        return 0;
+
     case OFPACT_CLEAR_ACTIONS:
     case OFPACT_WRITE_METADATA:
     case OFPACT_GOTO_TABLE:
@@ -1137,9 +1179,10 @@ ofpacts_check(const struct ofpact ofpacts[], size_t ofpacts_len,
               const struct flow *flow, int max_ports)
 {
     const struct ofpact *a;
+    ovs_be16 dl_type = flow->dl_type;
 
     OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
-        enum ofperr error = ofpact_check__(a, flow, max_ports);
+        enum ofperr error = ofpact_check__(a, flow, max_ports, &dl_type);
         if (error) {
             return error;
         }
@@ -1373,10 +1416,6 @@ ofpact_to_nxast(const struct ofpact *a, struct ofpbuf *out)
         multipath_to_nxast(ofpact_get_MULTIPATH(a), out);
         break;
 
-    case OFPACT_AUTOPATH:
-        autopath_to_nxast(ofpact_get_AUTOPATH(a), out);
-        break;
-
     case OFPACT_NOTE:
         ofpact_note_to_nxast(ofpact_get_NOTE(a), out);
         break;
@@ -1385,6 +1424,16 @@ ofpact_to_nxast(const struct ofpact *a, struct ofpbuf *out)
         ofputil_put_NXAST_EXIT(out);
         break;
 
+    case OFPACT_PUSH_MPLS:
+        ofputil_put_NXAST_PUSH_MPLS(out)->ethertype =
+            ofpact_get_PUSH_MPLS(a)->ethertype;
+        break;
+
+    case OFPACT_POP_MPLS:
+        ofputil_put_NXAST_POP_MPLS(out)->ethertype =
+            ofpact_get_POP_MPLS(a)->ethertype;
+        break;
+
     case OFPACT_OUTPUT:
     case OFPACT_ENQUEUE:
     case OFPACT_SET_VLAN_VID:
@@ -1509,9 +1558,10 @@ ofpact_to_openflow10(const struct ofpact *a, struct ofpbuf *out)
     case OFPACT_RESUBMIT:
     case OFPACT_LEARN:
     case OFPACT_MULTIPATH:
-    case OFPACT_AUTOPATH:
     case OFPACT_NOTE:
     case OFPACT_EXIT:
+    case OFPACT_PUSH_MPLS:
+    case OFPACT_POP_MPLS:
         ofpact_to_nxast(a, out);
         break;
     }
@@ -1636,6 +1686,17 @@ ofpact_to_openflow11(const struct ofpact *a, struct ofpbuf *out)
         /* OpenFlow 1.1 uses OFPIT_WRITE_METADATA to express this action. */
         break;
 
+    case OFPACT_PUSH_MPLS:
+        ofputil_put_OFPAT11_PUSH_MPLS(out)->ethertype =
+            ofpact_get_PUSH_MPLS(a)->ethertype;
+        break;
+
+    case OFPACT_POP_MPLS:
+        ofputil_put_OFPAT11_POP_MPLS(out)->ethertype =
+            ofpact_get_POP_MPLS(a)->ethertype;
+
+        break;
+
     case OFPACT_CLEAR_ACTIONS:
     case OFPACT_GOTO_TABLE:
         NOT_REACHED();
@@ -1651,7 +1712,6 @@ ofpact_to_openflow11(const struct ofpact *a, struct ofpbuf *out)
     case OFPACT_RESUBMIT:
     case OFPACT_LEARN:
     case OFPACT_MULTIPATH:
-    case OFPACT_AUTOPATH:
     case OFPACT_NOTE:
     case OFPACT_EXIT:
         ofpact_to_nxast(a, out);
@@ -1774,9 +1834,10 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, uint16_t port)
     case OFPACT_RESUBMIT:
     case OFPACT_LEARN:
     case OFPACT_MULTIPATH:
-    case OFPACT_AUTOPATH:
     case OFPACT_NOTE:
     case OFPACT_EXIT:
+    case OFPACT_PUSH_MPLS:
+    case OFPACT_POP_MPLS:
     case OFPACT_CLEAR_ACTIONS:
     case OFPACT_GOTO_TABLE:
     default:
@@ -1865,7 +1926,6 @@ ofpact_format(const struct ofpact *a, struct ds *s)
 {
     const struct ofpact_enqueue *enqueue;
     const struct ofpact_resubmit *resubmit;
-    const struct ofpact_autopath *autopath;
     const struct ofpact_controller *controller;
     const struct ofpact_metadata *metadata;
     const struct ofpact_tunnel *tunnel;
@@ -2035,19 +2095,20 @@ ofpact_format(const struct ofpact *a, struct ds *s)
         multipath_format(ofpact_get_MULTIPATH(a), s);
         break;
 
-    case OFPACT_AUTOPATH:
-        autopath = ofpact_get_AUTOPATH(a);
-        ds_put_cstr(s, "autopath(");
-        ofputil_format_port(autopath->port, s);
-        ds_put_char(s, ',');
-        mf_format_subfield(&autopath->dst, s);
-        ds_put_char(s, ')');
-        break;
-
     case OFPACT_NOTE:
         print_note(ofpact_get_NOTE(a), s);
         break;
 
+    case OFPACT_PUSH_MPLS:
+        ds_put_format(s, "push_mpls:0x%04"PRIx16,
+                      ntohs(ofpact_get_PUSH_MPLS(a)->ethertype));
+        break;
+
+    case OFPACT_POP_MPLS:
+        ds_put_format(s, "pop_mpls:0x%04"PRIx16,
+                      ntohs(ofpact_get_POP_MPLS(a)->ethertype));
+        break;
+
     case OFPACT_EXIT:
         ds_put_cstr(s, "exit");
         break;
index e930986..c4e1b4a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 Nicira, Inc.
+ * Copyright (c) 2012, 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.
@@ -71,6 +71,8 @@
     DEFINE_OFPACT(REG_MOVE,        ofpact_reg_move,      ofpact)    \
     DEFINE_OFPACT(REG_LOAD,        ofpact_reg_load,      ofpact)    \
     DEFINE_OFPACT(DEC_TTL,         ofpact_cnt_ids,       cnt_ids)   \
+    DEFINE_OFPACT(PUSH_MPLS,       ofpact_push_mpls,     ofpact)    \
+    DEFINE_OFPACT(POP_MPLS,        ofpact_pop_mpls,      ofpact)    \
                                                                     \
     /* Metadata. */                                                 \
     DEFINE_OFPACT(SET_TUNNEL,      ofpact_tunnel,        ofpact)    \
@@ -84,7 +86,6 @@
                                                                     \
     /* Arithmetic. */                                               \
     DEFINE_OFPACT(MULTIPATH,       ofpact_multipath,     ofpact)    \
-    DEFINE_OFPACT(AUTOPATH,        ofpact_autopath,      ofpact)    \
                                                                     \
     /* Other. */                                                    \
     DEFINE_OFPACT(NOTE,            ofpact_note,          data)      \
@@ -310,6 +311,22 @@ struct ofpact_reg_load {
     union mf_subvalue subvalue; /* Least-significant bits are used. */
 };
 
+/* OFPACT_PUSH_VLAN/MPLS/PBB
+ *
+ * Used for NXAST_PUSH_MPLS, OFPAT11_PUSH_MPLS. */
+struct ofpact_push_mpls {
+    struct ofpact ofpact;
+    ovs_be16 ethertype;
+};
+
+/* OFPACT_POP_MPLS
+ *
+ * Used for NXAST_POP_MPLS, OFPAT11_POP_MPLS.. */
+struct ofpact_pop_mpls {
+    struct ofpact ofpact;
+    ovs_be16 ethertype;
+};
+
 /* OFPACT_SET_TUNNEL.
  *
  * Used for NXAST_SET_TUNNEL, NXAST_SET_TUNNEL64. */
@@ -403,15 +420,6 @@ struct ofpact_multipath {
     struct mf_subfield dst;
 };
 
-/* OFPACT_AUTOPATH.
- *
- * Used for NXAST_AUTOPATH. */
-struct ofpact_autopath {
-    struct ofpact ofpact;
-    struct mf_subfield dst;
-    uint32_t port;
-};
-
 /* OFPACT_NOTE.
  *
  * Used for NXAST_NOTE. */
index 47d7615..af4178e 100644 (file)
@@ -320,6 +320,23 @@ ofpraw_decode(enum ofpraw *raw, const struct ofp_header *oh)
     return ofpraw_pull(raw, &msg);
 }
 
+/* Does the same job as ofpraw_decode(), except that it assert-fails if
+ * ofpraw_decode() would have reported an error.  Thus, it's able to use the
+ * return value for the OFPRAW_* message type instead of an error code.
+ *
+ * (It only makes sense to use this function if you previously called
+ * ofpraw_decode() on the message and thus know that it's OK.) */
+enum ofpraw
+ofpraw_decode_assert(const struct ofp_header *oh)
+{
+    enum ofperr error;
+    enum ofpraw raw;
+
+    error = ofpraw_decode(&raw, oh);
+    ovs_assert(!error);
+    return raw;
+}
+
 /* Determines the OFPRAW_* type of the OpenFlow message in 'msg', which starts
  * at 'msg->data' and has length 'msg->size' bytes.  On success, returns 0 and
  * stores the type into '*rawp'.  On failure, returns an OFPERR_* error code
@@ -403,11 +420,11 @@ ofpraw_pull(enum ofpraw *rawp, struct ofpbuf *msg)
 }
 
 /* Does the same job as ofpraw_pull(), except that it assert-fails if
- * ofpbuf_pull() would have reported an error.  Thus, it's able to use the
+ * ofpraw_pull() would have reported an error.  Thus, it's able to use the
  * return value for the OFPRAW_* message type instead of an error code.
  *
  * (It only makes sense to use this function if you previously called
- * ofpbuf_decode() on the message and thus know that it's OK.) */
+ * ofpraw_decode() on the message and thus know that it's OK.) */
 enum ofpraw
 ofpraw_pull_assert(struct ofpbuf *msg)
 {
@@ -834,6 +851,8 @@ ofpmp_reserve(struct list *replies, size_t len)
 
         next = ofpbuf_new(MAX(1024, hdrs_len + len));
         ofpbuf_put(next, msg->data, hdrs_len);
+        next->l2 = next->data;
+        next->l3 = ofpbuf_tail(next);
         list_push_back(replies, &next->list_node);
 
         *ofpmp_flags__(msg->data) |= htons(OFPSF_REPLY_MORE);
index 2db4fc9..66ec448 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 Nicira, Inc.
+ * Copyright (c) 2012, 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.
@@ -387,6 +387,7 @@ enum ofpraw {
 
 /* Decoding messages into OFPRAW_* values. */
 enum ofperr ofpraw_decode(enum ofpraw *, const struct ofp_header *);
+enum ofpraw ofpraw_decode_assert(const struct ofp_header *);
 enum ofperr ofpraw_pull(enum ofpraw *, struct ofpbuf *);
 enum ofpraw ofpraw_pull_assert(struct ofpbuf *);
 
index 6f35c12..5fda08a 100644 (file)
@@ -22,7 +22,6 @@
 #include <errno.h>
 #include <stdlib.h>
 
-#include "autopath.h"
 #include "bundle.h"
 #include "byte-order.h"
 #include "dynamic-string.h"
@@ -526,10 +525,6 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow,
         multipath_parse(ofpact_put_MULTIPATH(ofpacts), arg);
         break;
 
-    case OFPUTIL_NXAST_AUTOPATH__DEPRECATED:
-        autopath_parse(ofpact_put_AUTOPATH(ofpacts), arg);
-        break;
-
     case OFPUTIL_NXAST_BUNDLE:
         bundle_parse(arg, ofpacts);
         break;
@@ -562,6 +557,18 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow,
     case OFPUTIL_NXAST_CONTROLLER:
         parse_controller(ofpacts, arg);
         break;
+
+    case OFPUTIL_OFPAT11_PUSH_MPLS:
+    case OFPUTIL_NXAST_PUSH_MPLS:
+        ofpact_put_PUSH_MPLS(ofpacts)->ethertype =
+            htons(str_to_u16(arg, "push_mpls"));
+        break;
+
+    case OFPUTIL_OFPAT11_POP_MPLS:
+    case OFPUTIL_NXAST_POP_MPLS:
+        ofpact_put_POP_MPLS(ofpacts)->ethertype =
+            htons(str_to_u16(arg, "pop_mpls"));
+        break;
     }
 }
 
@@ -726,7 +733,9 @@ parse_protocol(const char *name, const struct protocol **p_out)
         { "tcp6", ETH_TYPE_IPV6, IPPROTO_TCP },
         { "udp6", ETH_TYPE_IPV6, IPPROTO_UDP },
         { "rarp", ETH_TYPE_RARP, 0},
-};
+        { "mpls", ETH_TYPE_MPLS, 0 },
+        { "mplsm", ETH_TYPE_MPLS_MCAST, 0 },
+    };
     const struct protocol *p;
 
     for (p = protocols; p < &protocols[ARRAY_SIZE(protocols)]; p++) {
@@ -914,7 +923,9 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_,
                 parse_field(mf_from_name(name), value, &fm->match);
             } else if (!strcmp(name, "duration")
                        || !strcmp(name, "n_packets")
-                       || !strcmp(name, "n_bytes")) {
+                       || !strcmp(name, "n_bytes")
+                       || !strcmp(name, "idle_age")
+                       || !strcmp(name, "hard_age")) {
                 /* Ignore these, so that users can feed the output of
                  * "ovs-ofctl dump-flows" back into commands that parse
                  * flows. */
index b97180e..f7872cb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 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.
@@ -642,6 +642,10 @@ ofp10_match_to_string(const struct ofp10_match *om, int verbosity)
             ds_put_cstr(&f, "arp,");
         } else if (om->dl_type == htons(ETH_TYPE_RARP)){
             ds_put_cstr(&f, "rarp,");
+        } else if (om->dl_type == htons(ETH_TYPE_MPLS)) {
+            ds_put_cstr(&f, "mpls,");
+        } else if (om->dl_type == htons(ETH_TYPE_MPLS_MCAST)) {
+            ds_put_cstr(&f, "mplsm,");
         } else {
             skip_type = false;
         }
@@ -1546,19 +1550,18 @@ ofp_print_role_message(struct ds *string, const struct ofp_header *oh)
     }
 
     ds_put_cstr(string, " role=");
-    if (rr.request_current_role_only) {
-        ds_put_cstr(string, "nochange");
-        return;
-    }
 
     switch (rr.role) {
-    case NX_ROLE_OTHER:
+    case OFPCR12_ROLE_NOCHANGE:
+        ds_put_cstr(string, "nochange");
+        break;
+    case OFPCR12_ROLE_EQUAL:
         ds_put_cstr(string, "equal"); /* OF 1.2 wording */
         break;
-    case NX_ROLE_MASTER:
+    case OFPCR12_ROLE_MASTER:
         ds_put_cstr(string, "master");
         break;
-    case NX_ROLE_SLAVE:
+    case OFPCR12_ROLE_SLAVE:
         ds_put_cstr(string, "slave");
         break;
     default:
index c66cd40..dd6eed8 100644 (file)
@@ -23,7 +23,6 @@
 #include <netinet/in.h>
 #include <netinet/icmp6.h>
 #include <stdlib.h>
-#include "autopath.h"
 #include "bundle.h"
 #include "byte-order.h"
 #include "classifier.h"
@@ -85,7 +84,7 @@ ofputil_netmask_to_wcbits(ovs_be32 netmask)
 void
 ofputil_wildcard_from_ofpfw10(uint32_t ofpfw, struct flow_wildcards *wc)
 {
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 18);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 19);
 
     /* Initialize most of wc. */
     flow_wildcards_init_catchall(wc);
@@ -440,8 +439,7 @@ ofputil_match_from_ofp11_match(const struct ofp11_match *ofmatch,
         }
     }
 
-    if (match->flow.dl_type == htons(ETH_TYPE_MPLS) ||
-        match->flow.dl_type == htons(ETH_TYPE_MPLS_MCAST)) {
+    if (eth_type_mpls(match->flow.dl_type)) {
         enum { OFPFW11_MPLS_ALL = OFPFW11_MPLS_LABEL | OFPFW11_MPLS_TC };
 
         if ((wc & OFPFW11_MPLS_ALL) != OFPFW11_MPLS_ALL) {
@@ -1060,7 +1058,7 @@ ofputil_usable_protocols(const struct match *match)
 {
     const struct flow_wildcards *wc = &match->wc;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 18);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 19);
 
     /* tunnel params other than tun_id can't be sent in a flow_mod */
     if (!tun_parms_fully_wildcarded(wc)) {
@@ -1152,6 +1150,26 @@ ofputil_usable_protocols(const struct match *match)
             | OFPUTIL_P_OF13_OXM;
     }
 
+    /* NXM and OF1.1+ support matching MPLS label */
+    if (wc->masks.mpls_lse & htonl(MPLS_LABEL_MASK)) {
+        return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
+            | OFPUTIL_P_OF13_OXM;
+    }
+
+    /* NXM and OF1.1+ support matching MPLS TC */
+    if (wc->masks.mpls_lse & htonl(MPLS_TC_MASK)) {
+        return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
+            | OFPUTIL_P_OF13_OXM;
+    }
+
+    /* NXM and OF1.3+ support matching MPLS stack flag */
+    /* Allow for OF1.2 as there doesn't seem to be a
+     * particularly good reason not to */
+    if (wc->masks.mpls_lse & htonl(MPLS_BOS_MASK)) {
+        return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
+            | OFPUTIL_P_OF13_OXM;
+    }
+
     /* Other formats can express this rule. */
     return OFPUTIL_P_ANY;
 }
@@ -3364,43 +3382,54 @@ enum ofperr
 ofputil_decode_role_message(const struct ofp_header *oh,
                             struct ofputil_role_request *rr)
 {
-    const struct ofp12_role_request *orr = ofpmsg_body(oh);
-    uint32_t role = ntohl(orr->role);
     struct ofpbuf b;
     enum ofpraw raw;
 
-    memset(rr, 0, sizeof *rr);
-
     ofpbuf_use_const(&b, oh, ntohs(oh->length));
     raw = ofpraw_pull_assert(&b);
 
-    if (raw == OFPRAW_OFPT12_ROLE_REQUEST
-        || raw == OFPRAW_OFPT12_ROLE_REPLY) {
+    if (raw == OFPRAW_OFPT12_ROLE_REQUEST ||
+        raw == OFPRAW_OFPT12_ROLE_REPLY) {
+        const struct ofp12_role_request *orr = b.l3;
 
-        if (raw == OFPRAW_OFPT12_ROLE_REQUEST) {
-            if (role == OFPCR12_ROLE_NOCHANGE) {
-                rr->request_current_role_only = true;
-                return 0;
-            }
-            if (role == OFPCR12_ROLE_MASTER || role == OFPCR12_ROLE_SLAVE) {
-                rr->generation_id = ntohll(orr->generation_id);
-                rr->have_generation_id = true;
-            }
+        if (orr->role != htonl(OFPCR12_ROLE_NOCHANGE) &&
+            orr->role != htonl(OFPCR12_ROLE_EQUAL) &&
+            orr->role != htonl(OFPCR12_ROLE_MASTER) &&
+            orr->role != htonl(OFPCR12_ROLE_SLAVE)) {
+            return OFPERR_OFPRRFC_BAD_ROLE;
         }
 
-        /* Map to enum nx_role */
-        role -= 1; /* OFPCR12_ROLE_MASTER -> NX_ROLE_MASTER etc. */
-    } else if (raw != OFPRAW_NXT_ROLE_REQUEST
-               && raw != OFPRAW_NXT_ROLE_REPLY) {
-        return OFPERR_OFPBRC_BAD_TYPE;
-    }
+        rr->role = ntohl(orr->role);
+        if (raw == OFPRAW_OFPT12_ROLE_REQUEST
+            ? orr->role == htonl(OFPCR12_ROLE_NOCHANGE)
+            : orr->generation_id == htonll(UINT64_MAX)) {
+            rr->have_generation_id = false;
+            rr->generation_id = 0;
+        } else {
+            rr->have_generation_id = true;
+            rr->generation_id = ntohll(orr->generation_id);
+        }
+    } else if (raw == OFPRAW_NXT_ROLE_REQUEST ||
+               raw == OFPRAW_NXT_ROLE_REPLY) {
+        const struct nx_role_request *nrr = b.l3;
+
+        BUILD_ASSERT(NX_ROLE_OTHER + 1 == OFPCR12_ROLE_EQUAL);
+        BUILD_ASSERT(NX_ROLE_MASTER + 1 == OFPCR12_ROLE_MASTER);
+        BUILD_ASSERT(NX_ROLE_SLAVE + 1 == OFPCR12_ROLE_SLAVE);
+
+        if (nrr->role != htonl(NX_ROLE_OTHER) &&
+            nrr->role != htonl(NX_ROLE_MASTER) &&
+            nrr->role != htonl(NX_ROLE_SLAVE)) {
+            return OFPERR_OFPRRFC_BAD_ROLE;
+        }
 
-    if (role != NX_ROLE_OTHER && role != NX_ROLE_MASTER
-        && role != NX_ROLE_SLAVE) {
-        return OFPERR_OFPRRFC_BAD_ROLE;
+        rr->role = ntohl(nrr->role) + 1;
+        rr->have_generation_id = false;
+        rr->generation_id = 0;
+    } else {
+        NOT_REACHED();
     }
 
-    rr->role = role;
     return 0;
 }
 
@@ -3408,47 +3437,35 @@ ofputil_decode_role_message(const struct ofp_header *oh,
  * buffer owned by the caller. */
 struct ofpbuf *
 ofputil_encode_role_reply(const struct ofp_header *request,
-                          enum nx_role role)
+                          const struct ofputil_role_request *rr)
 {
-    struct ofp12_role_request *reply;
     struct ofpbuf *buf;
-    size_t reply_size;
-
-    struct ofpbuf b;
     enum ofpraw raw;
 
-    ofpbuf_use_const(&b, request, ntohs(request->length));
-    raw = ofpraw_pull_assert(&b);
+    raw = ofpraw_decode_assert(request);
     if (raw == OFPRAW_OFPT12_ROLE_REQUEST) {
-        reply_size = sizeof (struct ofp12_role_request);
-        raw = OFPRAW_OFPT12_ROLE_REPLY;
-    }
-    else if (raw == OFPRAW_NXT_ROLE_REQUEST) {
-        reply_size = sizeof (struct nx_role_request);
-        raw = OFPRAW_NXT_ROLE_REPLY;
-    } else {
-        NOT_REACHED();
-    }
+        struct ofp12_role_request *orr;
 
-    buf = ofpraw_alloc_reply(raw, request, 0);
-    reply = ofpbuf_put_zeros(buf, reply_size);
+        buf = ofpraw_alloc_reply(OFPRAW_OFPT12_ROLE_REPLY, request, 0);
+        orr = ofpbuf_put_zeros(buf, sizeof *orr);
 
-    if (raw == OFPRAW_OFPT12_ROLE_REPLY) {
-        /* Map to OpenFlow enum ofp12_controller_role */
-        role += 1; /* NX_ROLE_MASTER -> OFPCR12_ROLE_MASTER etc. */
-        /*
-         * OpenFlow specification does not specify use of generation_id field
-         * on reply messages.  Intuitively, it would seem a good idea to return
-         * the current value.  However, the current value is undefined
-         * initially, and there is no way to insert an undefined value in the
-         * message.  Therefore we leave the generation_id zeroed on reply
-         * messages.
-         *
-         * A request for clarification has been filed with the Open Networking
-         * Foundation as EXT-272.
-         */
+        orr->role = htonl(rr->role);
+        orr->generation_id = htonll(rr->have_generation_id
+                                    ? rr->generation_id
+                                    : UINT64_MAX);
+    } else if (raw == OFPRAW_NXT_ROLE_REQUEST) {
+        struct nx_role_request *nrr;
+
+        BUILD_ASSERT(NX_ROLE_OTHER == OFPCR12_ROLE_EQUAL - 1);
+        BUILD_ASSERT(NX_ROLE_MASTER == OFPCR12_ROLE_MASTER - 1);
+        BUILD_ASSERT(NX_ROLE_SLAVE == OFPCR12_ROLE_SLAVE - 1);
+
+        buf = ofpraw_alloc_reply(OFPRAW_NXT_ROLE_REPLY, request, 0);
+        nrr = ofpbuf_put_zeros(buf, sizeof *nrr);
+        nrr->role = htonl(rr->role - 1);
+    } else {
+        NOT_REACHED();
     }
-    reply->role = htonl(role);
 
     return buf;
 }
@@ -4115,14 +4132,14 @@ ofputil_port_from_string(const char *s, uint16_t *portp)
             *portp = port32;
             return true;
         } else if (port32 <= OFPP_LAST_RESV) {
-            struct ds s;
+            struct ds msg;
 
-            ds_init(&s);
-            ofputil_format_port(port32, &s);
+            ds_init(&msg);
+            ofputil_format_port(port32, &msg);
             VLOG_WARN_ONCE("referring to port %s as %u is deprecated for "
                            "compatibility with future versions of OpenFlow",
-                           ds_cstr(&s), port32);
-            ds_destroy(&s);
+                           ds_cstr(&msg), port32);
+            ds_destroy(&msg);
 
             *portp = port32;
             return true;
@@ -4307,7 +4324,8 @@ ofputil_normalize_match__(struct match *match, bool may_log)
         MAY_ARP_SHA     = 1 << 4, /* arp_sha */
         MAY_ARP_THA     = 1 << 5, /* arp_tha */
         MAY_IPV6        = 1 << 6, /* ipv6_src, ipv6_dst, ipv6_label */
-        MAY_ND_TARGET   = 1 << 7  /* nd_target */
+        MAY_ND_TARGET   = 1 << 7, /* nd_target */
+        MAY_MPLS        = 1 << 8, /* mpls label and tc */
     } may_match;
 
     struct flow_wildcards wc;
@@ -4336,6 +4354,8 @@ ofputil_normalize_match__(struct match *match, bool may_log)
     } else if (match->flow.dl_type == htons(ETH_TYPE_ARP) ||
                match->flow.dl_type == htons(ETH_TYPE_RARP)) {
         may_match = MAY_NW_PROTO | MAY_NW_ADDR | MAY_ARP_SHA | MAY_ARP_THA;
+    } else if (eth_type_mpls(match->flow.dl_type)) {
+        may_match = MAY_MPLS;
     } else {
         may_match = 0;
     }
@@ -4368,6 +4388,10 @@ ofputil_normalize_match__(struct match *match, bool may_log)
     if (!(may_match & MAY_ND_TARGET)) {
         wc.masks.nd_target = in6addr_any;
     }
+    if (!(may_match & MAY_MPLS)) {
+        wc.masks.mpls_lse = htonl(0);
+        wc.masks.mpls_depth = 0;
+    }
 
     /* Log any changes. */
     if (!flow_wildcards_equal(&wc, &match->wc)) {
index 6d08d8a..ff7e1b3 100644 (file)
@@ -32,6 +32,8 @@ OFPAT11_ACTION(OFPAT11_SET_TP_SRC,   ofp_action_tp_port,  0, "mod_tp_src")
 OFPAT11_ACTION(OFPAT11_SET_TP_DST,   ofp_action_tp_port,  0, "mod_tp_dst")
 OFPAT11_ACTION(OFPAT11_PUSH_VLAN,    ofp11_action_push,   0, "push_vlan")
 OFPAT11_ACTION(OFPAT11_POP_VLAN,     ofp_action_header,   0, "pop_vlan")
+OFPAT11_ACTION(OFPAT11_PUSH_MPLS,    ofp11_action_push,   0, "push_mpls")
+OFPAT11_ACTION(OFPAT11_POP_MPLS,     ofp11_action_pop_mpls, 0, "pop_mpls")
 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)
@@ -49,7 +51,6 @@ NXAST_ACTION(NXAST_REG_LOAD,        nx_action_reg_load,     0, "load")
 NXAST_ACTION(NXAST_NOTE,            nx_action_note,         1, "note")
 NXAST_ACTION(NXAST_SET_TUNNEL64,    nx_action_set_tunnel64, 0, "set_tunnel64")
 NXAST_ACTION(NXAST_MULTIPATH,       nx_action_multipath,    0, "multipath")
-NXAST_ACTION(NXAST_AUTOPATH__DEPRECATED,nx_action_autopath, 0, "autopath")
 NXAST_ACTION(NXAST_BUNDLE,          nx_action_bundle,       1, "bundle")
 NXAST_ACTION(NXAST_BUNDLE_LOAD,     nx_action_bundle,       1, "bundle_load")
 NXAST_ACTION(NXAST_RESUBMIT_TABLE,  nx_action_resubmit,     0, NULL)
@@ -62,6 +63,8 @@ NXAST_ACTION(NXAST_CONTROLLER,      nx_action_controller,   0, "controller")
 NXAST_ACTION(NXAST_DEC_TTL_CNT_IDS, nx_action_cnt_ids,      1, NULL)
 NXAST_ACTION(NXAST_WRITE_METADATA,  nx_action_write_metadata, 0,
              "write_metadata")
+NXAST_ACTION(NXAST_PUSH_MPLS,       nx_action_push_mpls,    0, "push_mpls")
+NXAST_ACTION(NXAST_POP_MPLS,        nx_action_pop_mpls,     0, "pop_mpls")
 
 #undef OFPAT10_ACTION
 #undef OFPAT11_ACTION
index 77162bf..db28c58 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 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.
@@ -508,16 +508,15 @@ struct ofpbuf *ofputil_encode_port_mod(const struct ofputil_port_mod *,
 
 /* Abstract ofp_role_request and reply. */
 struct ofputil_role_request {
-    bool request_current_role_only; /* no role change */
+    enum ofp12_controller_role role;
     bool have_generation_id;
-    enum nx_role role;
     uint64_t generation_id;
 };
 
 enum ofperr ofputil_decode_role_message(const struct ofp_header *,
                                         struct ofputil_role_request *);
 struct ofpbuf *ofputil_encode_role_reply(const struct ofp_header *,
-                                         enum nx_role current_role);
+                                         const struct ofputil_role_request *);
 
 /* Abstract table stats.
  *
@@ -615,7 +614,6 @@ bool ofputil_frag_handling_from_string(const char *, enum ofp_config_flags *);
  * OFPUTIL_NXAST_NOTE
  * OFPUTIL_NXAST_SET_TUNNEL64
  * OFPUTIL_NXAST_MULTIPATH
- * OFPUTIL_NXAST_AUTOPATH
  * OFPUTIL_NXAST_BUNDLE
  * OFPUTIL_NXAST_BUNDLE_LOAD
  * OFPUTIL_NXAST_RESUBMIT_TABLE
@@ -688,8 +686,6 @@ union ofp_action *ofputil_actions_clone(const union ofp_action *, size_t n);
 /* Handy utility for parsing flows and actions. */
 bool ofputil_parse_key_value(char **stringp, char **keyp, char **valuep);
 
-struct ofpbuf *ofputlil_dump_ports(enum ofp_version ofp_version, int16_t port);
-
 struct ofputil_port_stats {
     uint16_t port_no;
     struct netdev_stats stats;
index 6484ab3..fd10da3 100644 (file)
@@ -29,7 +29,7 @@ ofpbuf_use__(struct ofpbuf *b, void *base, size_t allocated,
     b->allocated = allocated;
     b->source = source;
     b->size = 0;
-    b->l2 = b->l3 = b->l4 = b->l7 = NULL;
+    b->l2 = b->l2_5 = b->l3 = b->l4 = b->l7 = NULL;
     list_poison(&b->list_node);
     b->private_p = NULL;
 }
@@ -176,6 +176,9 @@ ofpbuf_clone_with_headroom(const struct ofpbuf *buffer, size_t headroom)
     if (buffer->l2) {
         new_buffer->l2 = (char *) buffer->l2 + data_delta;
     }
+    if (buffer->l2_5) {
+        new_buffer->l2_5 = (char *) buffer->l2_5 + data_delta;
+    }
     if (buffer->l3) {
         new_buffer->l3 = (char *) buffer->l3 + data_delta;
     }
@@ -295,6 +298,9 @@ ofpbuf_resize__(struct ofpbuf *b, size_t new_headroom, size_t new_tailroom)
         if (b->l2) {
             b->l2 = (char *) b->l2 + data_delta;
         }
+        if (b->l2_5) {
+            b->l2_5 = (char *) b->l2_5 + data_delta;
+        }
         if (b->l3) {
             b->l3 = (char *) b->l3 + data_delta;
         }
index 520455d..bae3c0a 100644 (file)
@@ -43,6 +43,7 @@ struct ofpbuf {
     size_t size;                /* Number of bytes in use. */
 
     void *l2;                   /* Link-level header. */
+    void *l2_5;                 /* MPLS label stack */
     void *l3;                   /* Network-level header. */
     void *l4;                   /* Transport-level header. */
     void *l7;                   /* Application data. */
index 0cb0759..fbf4bba 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
+/* Copyright (c) 2009, 2010, 2011, 2012, 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.
@@ -2145,6 +2145,7 @@ ovsdb_idl_txn_process_insert_reply(struct ovsdb_idl_txn_insert *insert,
         VLOG_WARN_RL(&syntax_rl, "\"insert\" reply \"uuid\" is not a JSON "
                      "UUID: %s", s);
         free(s);
+        ovsdb_error_destroy(error);
         return false;
     }
 
index fa73282..a39cddf 100644 (file)
@@ -192,7 +192,8 @@ eth_push_vlan(struct ofpbuf *packet, ovs_be16 tci)
 
 /* Removes outermost VLAN header (if any is present) from 'packet'.
  *
- * 'packet->l2' must initially point to 'packet''s Ethernet header. */
+ * 'packet->l2_5' should initially point to 'packet''s outer-most MPLS header
+ * or may be NULL if there are no MPLS headers. */
 void
 eth_pop_vlan(struct ofpbuf *packet)
 {
@@ -211,6 +212,182 @@ eth_pop_vlan(struct ofpbuf *packet)
     }
 }
 
+/* Return depth of mpls stack.
+ *
+ * 'packet->l2_5' should initially point to 'packet''s outer-most MPLS header
+ * or may be NULL if there are no MPLS headers. */
+uint16_t
+eth_mpls_depth(const struct ofpbuf *packet)
+{
+    struct mpls_hdr *mh = packet->l2_5;
+    uint16_t depth;
+
+    if (!mh) {
+        return 0;
+    }
+
+    depth = 0;
+    while (packet->size >= ((char *)mh - (char *)packet->data) + sizeof *mh) {
+        depth++;
+        if (mh->mpls_lse & htonl(MPLS_BOS_MASK)) {
+            break;
+        }
+        mh++;
+    }
+
+    return depth;
+}
+
+/* Set ethertype of the packet. */
+void
+set_ethertype(struct ofpbuf *packet, ovs_be16 eth_type)
+{
+    struct eth_header *eh = packet->data;
+
+    if (eh->eth_type == htons(ETH_TYPE_VLAN)) {
+        ovs_be16 *p;
+        p = (ovs_be16 *)((char *)(packet->l2_5 ? packet->l2_5 : packet->l3) - 2);
+        *p = eth_type;
+    } else {
+        eh->eth_type = eth_type;
+    }
+}
+
+static bool is_mpls(struct ofpbuf *packet)
+{
+    return packet->l2_5 != NULL;
+}
+
+/* Set time to live (TTL) of an MPLS label stack entry (LSE). */
+static void
+set_mpls_lse_ttl(ovs_be32 *lse, uint8_t ttl)
+{
+    *lse &= ~htonl(MPLS_TTL_MASK);
+    *lse |= htonl((ttl << MPLS_TTL_SHIFT) & MPLS_TTL_MASK);
+}
+
+/* Set traffic class (TC) of an MPLS label stack entry (LSE). */
+void
+set_mpls_lse_tc(ovs_be32 *lse, uint8_t tc)
+{
+    *lse &= ~htonl(MPLS_TC_MASK);
+    *lse |= htonl((tc << MPLS_TC_SHIFT) & MPLS_TC_MASK);
+}
+
+/* Set label of an MPLS label stack entry (LSE). */
+void
+set_mpls_lse_label(ovs_be32 *lse, ovs_be32 label)
+{
+    *lse &= ~htonl(MPLS_LABEL_MASK);
+    *lse |= htonl((ntohl(label) << MPLS_LABEL_SHIFT) & MPLS_LABEL_MASK);
+}
+
+/* Set bottom of stack (BoS) bit of an MPLS label stack entry (LSE). */
+void
+set_mpls_lse_bos(ovs_be32 *lse, uint8_t bos)
+{
+    *lse &= ~htonl(MPLS_BOS_MASK);
+    *lse |= htonl((bos << MPLS_BOS_SHIFT) & MPLS_BOS_MASK);
+}
+
+/* Compose an MPLS label stack entry (LSE) from its components:
+ * label, traffic class (TC), time to live (TTL) and
+ * bottom of stack (BoS) bit. */
+ovs_be32
+set_mpls_lse_values(uint8_t ttl, uint8_t tc, uint8_t bos, ovs_be32 label)
+{
+    ovs_be32 lse = htonl(0);
+    set_mpls_lse_ttl(&lse, ttl);
+    set_mpls_lse_tc(&lse, tc);
+    set_mpls_lse_bos(&lse, bos);
+    set_mpls_lse_label(&lse, label);
+    return lse;
+}
+
+/* Push an new MPLS stack entry onto the MPLS stack and adjust 'packet->l2' and
+ * 'packet->l2_5' accordingly.  The new entry will be the outermost entry on
+ * the stack.
+ *
+ * Previous to calling this function, 'packet->l2_5' must be set; if the MPLS
+ * label to be pushed will be the first label in 'packet', then it should be
+ * the same as 'packet->l3'. */
+static void
+push_mpls_lse(struct ofpbuf *packet, struct mpls_hdr *mh)
+{
+    char * header;
+    size_t len;
+    header = ofpbuf_push_uninit(packet, MPLS_HLEN);
+    len = (char *)packet->l2_5 - (char *)packet->l2;
+    memmove(header, packet->l2, len);
+    memcpy(header + len, mh, sizeof *mh);
+    packet->l2 = (char*)packet->l2 - MPLS_HLEN;
+    packet->l2_5 = (char*)packet->l2_5 - MPLS_HLEN;
+}
+
+/* Set MPLS label stack entry to outermost MPLS header.*/
+void
+set_mpls_lse(struct ofpbuf *packet, ovs_be32 mpls_lse)
+{
+    struct mpls_hdr *mh = packet->l2_5;
+
+    /* Packet type should be MPLS to set label stack entry. */
+    if (is_mpls(packet)) {
+        /* Update mpls label stack entry. */
+        mh->mpls_lse = mpls_lse;
+    }
+}
+
+/* Push MPLS label stack entry 'lse' onto 'packet' as the the outermost MPLS
+ * header.  If 'packet' does not already have any MPLS labels, then its
+ * Ethertype is changed to 'ethtype' (which must be an MPLS Ethertype). */
+void
+push_mpls(struct ofpbuf *packet, ovs_be16 ethtype, ovs_be32 lse)
+{
+    struct mpls_hdr mh;
+
+    if (!eth_type_mpls(ethtype)) {
+        return;
+    }
+
+    if (!is_mpls(packet)) {
+        /* Set ethtype and MPLS label stack entry. */
+        set_ethertype(packet, ethtype);
+        packet->l2_5 = packet->l3;
+    }
+
+    /* Push new MPLS shim header onto packet. */
+    mh.mpls_lse = lse;
+    push_mpls_lse(packet, &mh);
+}
+
+/* If 'packet' is an MPLS packet, removes its outermost MPLS label stack entry.
+ * If the label that was removed was the only MPLS label, changes 'packet''s
+ * Ethertype to 'ethtype' (which ordinarily should not be an MPLS
+ * Ethertype). */
+void
+pop_mpls(struct ofpbuf *packet, ovs_be16 ethtype)
+{
+    struct mpls_hdr *mh = NULL;
+
+    if (is_mpls(packet)) {
+        size_t len;
+        mh = packet->l2_5;
+        len = (char*)packet->l2_5 - (char*)packet->l2;
+        /* If bottom of the stack set ethertype. */
+        if (mh->mpls_lse & htonl(MPLS_BOS_MASK)) {
+            set_ethertype(packet, ethtype);
+            packet->l2_5 = NULL;
+        } else {
+            packet->l2_5 = (char*)packet->l2_5 + MPLS_HLEN;
+        }
+        /* Shift the l2 header forward. */
+        memmove((char*)packet->data + MPLS_HLEN, packet->data, len);
+        packet->size -= MPLS_HLEN;
+        packet->data = (char*)packet->data + MPLS_HLEN;
+        packet->l2 = (char*)packet->l2 + MPLS_HLEN;
+    }
+}
+
 /* Converts hex digits in 'hex' to an Ethernet packet in '*packetp'.  The
  * caller must free '*packetp'.  On success, returns NULL.  On failure, returns
  * an error message and stores NULL in '*packetp'. */
@@ -710,7 +887,9 @@ packet_set_udp_port(struct ofpbuf *packet, ovs_be16 src, ovs_be16 dst)
 uint8_t
 packet_get_tcp_flags(const struct ofpbuf *packet, const struct flow *flow)
 {
-    if (is_ip_any(flow) && flow->nw_proto == IPPROTO_TCP && packet->l7) {
+    ovs_be16 dl_type = flow_innermost_dl_type(flow);
+    if (dl_type_is_ip_any(dl_type) &&
+        flow->nw_proto == IPPROTO_TCP && packet->l7) {
         const struct tcp_header *tcp = packet->l4;
         return TCP_FLAGS(tcp->tcp_ctl);
     } else {
index 8dd3ebf..0f97fe6 100644 (file)
@@ -140,6 +140,10 @@ void compose_rarp(struct ofpbuf *, const uint8_t eth_src[ETH_ADDR_LEN]);
 void eth_push_vlan(struct ofpbuf *, ovs_be16 tci);
 void eth_pop_vlan(struct ofpbuf *);
 
+uint16_t eth_mpls_depth(const struct ofpbuf *packet);
+
+void set_ethertype(struct ofpbuf *packet, ovs_be16 eth_type);
+
 const char *eth_from_hex(const char *hex, struct ofpbuf **packetp);
 void eth_format_masked(const uint8_t eth[ETH_ADDR_LEN],
                        const uint8_t mask[ETH_ADDR_LEN], struct ds *s);
@@ -147,6 +151,16 @@ void eth_addr_bitand(const uint8_t src[ETH_ADDR_LEN],
                      const uint8_t mask[ETH_ADDR_LEN],
                      uint8_t dst[ETH_ADDR_LEN]);
 
+void set_mpls_lse(struct ofpbuf *, ovs_be32 label);
+void push_mpls(struct ofpbuf *packet, ovs_be16 ethtype, ovs_be32 lse);
+void pop_mpls(struct ofpbuf *, ovs_be16 ethtype);
+
+void set_mpls_lse_tc(ovs_be32 *lse, uint8_t tc);
+void set_mpls_lse_label(ovs_be32 *lse, ovs_be32 label);
+void set_mpls_lse_bos(ovs_be32 *lse, uint8_t bos);
+ovs_be32 set_mpls_lse_values(uint8_t ttl, uint8_t tc, uint8_t bos,
+                             ovs_be32 label);
+
 /* Example:
  *
  * uint8_t mac[ETH_ADDR_LEN];
@@ -186,6 +200,12 @@ void eth_addr_bitand(const uint8_t src[ETH_ADDR_LEN],
 #define ETH_TYPE_MPLS          0x8847
 #define ETH_TYPE_MPLS_MCAST    0x8848
 
+static inline bool eth_type_mpls(ovs_be16 eth_type)
+{
+    return eth_type == htons(ETH_TYPE_MPLS) ||
+        eth_type == htons(ETH_TYPE_MPLS_MCAST);
+}
+
 /* Minimum value for an Ethernet type.  Values below this are IEEE 802.2 frame
  * lengths. */
 #define ETH_TYPE_MIN           0x600
@@ -272,6 +292,66 @@ struct vlan_eth_header {
 } __attribute__((packed));
 BUILD_ASSERT_DECL(VLAN_ETH_HEADER_LEN == sizeof(struct vlan_eth_header));
 
+/* MPLS related definitions */
+#define MPLS_TTL_MASK       0x000000ff
+#define MPLS_TTL_SHIFT      0
+
+#define MPLS_BOS_MASK       0x00000100
+#define MPLS_BOS_SHIFT      8
+
+#define MPLS_TC_MASK        0x00000e00
+#define MPLS_TC_SHIFT       9
+
+#define MPLS_LABEL_MASK     0xfffff000
+#define MPLS_LABEL_SHIFT    12
+
+#define MPLS_HLEN           4
+
+struct mpls_hdr {
+    ovs_be32 mpls_lse;
+};
+BUILD_ASSERT_DECL(MPLS_HLEN == sizeof(struct mpls_hdr));
+
+/* Given a mpls label stack entry in network byte order
+ * return mpls label in host byte order */
+static inline uint32_t
+mpls_lse_to_label(ovs_be32 mpls_lse)
+{
+    return (ntohl(mpls_lse) & MPLS_LABEL_MASK) >> MPLS_LABEL_SHIFT;
+}
+
+/* Given a mpls label stack entry in network byte order
+ * return mpls tc */
+static inline uint8_t
+mpls_lse_to_tc(ovs_be32 mpls_lse)
+{
+    return (ntohl(mpls_lse) & MPLS_TC_MASK) >> MPLS_TC_SHIFT;
+}
+
+/* Given a mpls label stack entry in network byte order
+ * return mpls ttl */
+static inline uint8_t
+mpls_lse_to_ttl(ovs_be32 mpls_lse)
+{
+    return (ntohl(mpls_lse) & MPLS_TTL_MASK) >> MPLS_TTL_SHIFT;
+}
+
+/* Set TTL in mpls lse. */
+static inline void
+flow_set_mpls_lse_ttl(ovs_be32 *mpls_lse, uint8_t ttl)
+{
+    *mpls_lse &= ~htonl(MPLS_TTL_MASK);
+    *mpls_lse |= htonl(ttl << MPLS_TTL_SHIFT);
+}
+
+/* Given a mpls label stack entry in network byte order
+ * return mpls BoS bit  */
+static inline uint8_t
+mpls_lse_to_bos(ovs_be32 mpls_lse)
+{
+    return (mpls_lse & htonl(MPLS_BOS_MASK)) != 0;
+}
+
 #define IP_FMT "%"PRIu32".%"PRIu32".%"PRIu32".%"PRIu32
 #define IP_ARGS(ip)                             \
     ntohl(ip) >> 24,                            \
@@ -468,10 +548,15 @@ static inline bool ipv6_mask_is_exact(const struct in6_addr *mask) {
     return ipv6_addr_equals(mask, &in6addr_exact);
 }
 
+static inline bool dl_type_is_ip_any(ovs_be16 dl_type)
+{
+    return dl_type == htons(ETH_TYPE_IP)
+        || dl_type == htons(ETH_TYPE_IPV6);
+}
+
 static inline bool is_ip_any(const struct flow *flow)
 {
-    return flow->dl_type == htons(ETH_TYPE_IP)
-        || flow->dl_type == htons(ETH_TYPE_IPV6);
+    return dl_type_is_ip_any(flow->dl_type);
 }
 
 void format_ipv6_addr(char *addr_str, const struct in6_addr *addr);
index fca1dfa..9855306 100644 (file)
@@ -165,8 +165,8 @@ log_wakeup(const char *where, const struct pollfd *pollfd, int timeout)
     cpu_usage = get_cpu_usage();
     if (VLOG_IS_DBG_ENABLED()) {
         level = VLL_DBG;
-    } else if (cpu_usage > 50 && !VLOG_DROP_WARN(&rl)) {
-        level = VLL_WARN;
+    } else if (cpu_usage > 50 && !VLOG_DROP_INFO(&rl)) {
+        level = VLL_INFO;
     } else {
         return;
     }
index 3fc2e18..795a136 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 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.
@@ -408,14 +408,20 @@ struct stream {
 static int
 stream_open(struct stream *s, size_t max_size)
 {
+    int error;
+
     s->max_size = max_size;
     ds_init(&s->log);
     if (pipe(s->fds)) {
         VLOG_WARN("failed to create pipe: %s", strerror(errno));
         return errno;
     }
-    set_nonblocking(s->fds[0]);
-    return 0;
+    error = set_nonblocking(s->fds[0]);
+    if (error) {
+        close(s->fds[0]);
+        close(s->fds[1]);
+    }
+    return error;
 }
 
 static void
index cc8ddb8..9c30f68 100644 (file)
@@ -147,6 +147,19 @@ simap_delete(struct simap *simap, struct simap_node *node)
     free(node);
 }
 
+/* Searches for 'name' in 'simap'.  If found, deletes it and returns true.  If
+ * not found, returns false without modifying 'simap'. */
+bool
+simap_find_and_delete(struct simap *simap, const char *name)
+{
+    struct simap_node *node = simap_find(simap, name);
+    if (node) {
+        simap_delete(simap, node);
+        return true;
+    }
+    return false;
+}
+
 /* Searches 'simap' for a mapping with the given 'name'.  Returns it, if found,
  * or a null pointer if not. */
 struct simap_node *
@@ -172,6 +185,13 @@ simap_get(const struct simap *simap, const char *name)
     return node ? node->data : 0;
 }
 
+/* Returns true if 'simap' contains a copy of 'name', false otherwise. */
+bool
+simap_contains(const struct simap *simap, const char *name)
+{
+    return simap_find(simap, name) != NULL;
+}
+
 /* Returns an array that contains a pointer to each mapping in 'simap',
  * ordered alphabetically by name.  The returned array has simap_count(simap)
  * elements.
index e7bf80b..3e247fc 100644 (file)
@@ -58,8 +58,10 @@ unsigned int simap_get(const struct simap *, const char *);
 struct simap_node *simap_find(const struct simap *, const char *);
 struct simap_node *simap_find_len(const struct simap *,
                                   const char *, size_t len);
+bool simap_contains(const struct simap *, const char *);
 
 void simap_delete(struct simap *, struct simap_node *);
+bool simap_find_and_delete(struct simap *, const char *);
 
 const struct simap_node **simap_sort(const struct simap *);
 
index 3e3c67f..9fea7bd 100644 (file)
@@ -409,13 +409,8 @@ make_unix_socket(int style, bool nonblock,
      * it will only happen if style is SOCK_STREAM or SOCK_SEQPACKET, and only
      * if a backlog of un-accepted connections has built up in the kernel.)  */
     if (nonblock) {
-        int flags = fcntl(fd, F_GETFL, 0);
-        if (flags == -1) {
-            error = errno;
-            goto error;
-        }
-        if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
-            error = errno;
+        error = set_nonblocking(fd);
+        if (error) {
             goto error;
         }
     }
index 6ed7648..dbee135 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 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.
@@ -29,6 +29,7 @@
 #include "packets.h"
 #include "poll-loop.h"
 #include "socket-util.h"
+#include "dirs.h"
 #include "util.h"
 #include "stream-provider.h"
 #include "stream-fd.h"
@@ -42,15 +43,19 @@ static int
 unix_open(const char *name, char *suffix, struct stream **streamp,
           uint8_t dscp OVS_UNUSED)
 {
-    const char *connect_path = suffix;
+    char *connect_path;
     int fd;
 
+    connect_path = abs_file_name(ovs_rundir(), suffix);
     fd = make_unix_socket(SOCK_STREAM, true, NULL, connect_path);
+
     if (fd < 0) {
         VLOG_DBG("%s: connection failed (%s)", connect_path, strerror(-fd));
+        free(connect_path);
         return -fd;
     }
 
+    free(connect_path);
     return new_fd_stream(name, fd, check_connection_completion(fd), streamp);
 }
 
@@ -76,11 +81,14 @@ static int
 punix_open(const char *name OVS_UNUSED, char *suffix,
            struct pstream **pstreamp, uint8_t dscp OVS_UNUSED)
 {
+    char *bind_path;
     int fd, error;
 
-    fd = make_unix_socket(SOCK_STREAM, true, suffix, NULL);
+    bind_path = abs_file_name(ovs_rundir(), suffix);
+    fd = make_unix_socket(SOCK_STREAM, true, bind_path, NULL);
     if (fd < 0) {
-        VLOG_ERR("%s: binding failed: %s", suffix, strerror(errno));
+        VLOG_ERR("%s: binding failed: %s", bind_path, strerror(errno));
+        free(bind_path);
         return errno;
     }
 
@@ -88,11 +96,11 @@ punix_open(const char *name OVS_UNUSED, char *suffix,
         error = errno;
         VLOG_ERR("%s: listen: %s", name, strerror(error));
         close(fd);
+        free(bind_path);
         return error;
     }
 
-    return new_fd_pstream(name, fd, punix_accept, NULL,
-                          xstrdup(suffix), pstreamp);
+    return new_fd_pstream(name, fd, punix_accept, NULL, bind_path, pstreamp);
 }
 
 static int
index d91305c..2f00355 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 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.
@@ -328,7 +328,7 @@ time_alarm(unsigned int secs)
     time_refresh();
 
     now = time_msec();
-    msecs = secs * 1000;
+    msecs = secs * 1000LL;
 
     block_sigalrm(&oldsigs);
     deadline = now < LLONG_MAX - msecs ? now + msecs : LLONG_MAX;
@@ -516,7 +516,7 @@ log_poll_interval(long long int last_wakeup)
 {
     long long int interval = time_msec() - last_wakeup;
 
-    if (interval >= 1000) {
+    if (interval >= 1000 && !warp_offset.tv_sec && !warp_offset.tv_nsec) {
         const struct rusage *last_rusage = get_recent_rusage();
         struct rusage rusage;
 
index e59056e..104a2d9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 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.
@@ -462,7 +462,7 @@ unixctl_client_transact(struct jsonrpc *client, const char *command, int argc,
     error = jsonrpc_transact_block(client, request, &reply);
     if (error) {
         VLOG_WARN("error communicating with %s: %s", jsonrpc_get_name(client),
-                  strerror(error));
+                  ovs_retval_to_string(error));
         return error;
     }
 
index 83d3ff8..cbaffa7 100644 (file)
@@ -810,7 +810,7 @@ log_2_floor(uint32_t n)
 int
 log_2_ceil(uint32_t n)
 {
-    return log_2_floor(n) + !IS_POW2(n);
+    return log_2_floor(n) + !is_pow2(n);
 }
 
 /* Returns the number of trailing 0-bits in 'n'.  Undefined if 'n' == 0. */
index 7867b07..8bc9938 100644 (file)
@@ -431,6 +431,16 @@ exit:
     return msg;
 }
 
+/* Set debugging levels.  Abort with an error message if 's' is invalid. */
+void
+vlog_set_levels_from_string_assert(const char *s)
+{
+    char *error = vlog_set_levels_from_string(s);
+    if (error) {
+        ovs_fatal(0, "%s", error);
+    }
+}
+
 /* If 'arg' is null, configure maximum verbosity.  Otherwise, sets
  * configuration according to 'arg' (see vlog_set_levels_from_string()). */
 void
index 2595772..ab746c8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 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.
@@ -114,7 +114,8 @@ struct vlog_rate_limit {
 enum vlog_level vlog_get_level(const struct vlog_module *, enum vlog_facility);
 void vlog_set_levels(struct vlog_module *,
                      enum vlog_facility, enum vlog_level);
-char *vlog_set_levels_from_string(const char *);
+char *vlog_set_levels_from_string(const char *) WARN_UNUSED_RESULT;
+void vlog_set_levels_from_string_assert(const char *);
 char *vlog_get_levels(void);
 bool vlog_is_enabled(const struct vlog_module *, enum vlog_level);
 bool vlog_should_drop(const struct vlog_module *, enum vlog_level,
index b0f1a82..ce4a53b 100644 (file)
@@ -379,7 +379,7 @@ worker_main(int fd)
             /* Main process closed the IPC socket.  Exit cleanly. */
             break;
         } else if (error != EAGAIN) {
-            VLOG_FATAL("RPC receive failed (%s)", strerror(error));
+            VLOG_FATAL("RPC receive failed (%s)", ovs_retval_to_string(error));
         }
 
         poll_fd_wait(server_sock, POLLIN);
index b94c337..1a9dc21 100644 (file)
@@ -60,7 +60,7 @@ struct ofconn {
 /* State that should be cleared from one connection to the next. */
 
     /* OpenFlow state. */
-    enum nx_role role;           /* Role. */
+    enum ofp12_controller_role role;           /* Role. */
     enum ofputil_protocol protocol; /* Current protocol variant. */
     enum nx_packet_in_format packet_in_format; /* OFPT_PACKET_IN format. */
 
@@ -777,12 +777,13 @@ static int
 snoop_preference(const struct ofconn *ofconn)
 {
     switch (ofconn->role) {
-    case NX_ROLE_MASTER:
+    case OFPCR12_ROLE_MASTER:
         return 3;
-    case NX_ROLE_OTHER:
+    case OFPCR12_ROLE_EQUAL:
         return 2;
-    case NX_ROLE_SLAVE:
+    case OFPCR12_ROLE_SLAVE:
         return 1;
+    case OFPCR12_ROLE_NOCHANGE:
     default:
         /* Shouldn't happen. */
         return 0;
@@ -822,6 +823,17 @@ ofconn_get_type(const struct ofconn *ofconn)
     return ofconn->type;
 }
 
+/* If a master election id is defined, stores it into '*idp' and returns
+ * true.  Otherwise, stores UINT64_MAX into '*idp' and returns false. */
+bool
+ofconn_get_master_election_id(const struct ofconn *ofconn, uint64_t *idp)
+{
+    *idp = (ofconn->connmgr->master_election_id_defined
+            ? ofconn->connmgr->master_election_id
+            : UINT64_MAX);
+    return ofconn->connmgr->master_election_id_defined;
+}
+
 /* Sets the master election id.
  *
  * Returns true if successful, false if the id is stale
@@ -844,24 +856,24 @@ ofconn_set_master_election_id(struct ofconn *ofconn, uint64_t id)
 
 /* Returns the role configured for 'ofconn'.
  *
- * The default role, if no other role has been set, is NX_ROLE_OTHER. */
-enum nx_role
+ * The default role, if no other role has been set, is OFPCR12_ROLE_EQUAL. */
+enum ofp12_controller_role
 ofconn_get_role(const struct ofconn *ofconn)
 {
     return ofconn->role;
 }
 
-/* Changes 'ofconn''s role to 'role'.  If 'role' is NX_ROLE_MASTER then any
- * existing master is demoted to a slave. */
+/* Changes 'ofconn''s role to 'role'.  If 'role' is OFPCR12_ROLE_MASTER then
+ * any existing master is demoted to a slave. */
 void
-ofconn_set_role(struct ofconn *ofconn, enum nx_role role)
+ofconn_set_role(struct ofconn *ofconn, enum ofp12_controller_role role)
 {
-    if (role == NX_ROLE_MASTER) {
+    if (role == OFPCR12_ROLE_MASTER) {
         struct ofconn *other;
 
         HMAP_FOR_EACH (other, hmap_node, &ofconn->connmgr->controllers) {
-            if (other->role == NX_ROLE_MASTER) {
-                other->role = NX_ROLE_SLAVE;
+            if (other->role == OFPCR12_ROLE_MASTER) {
+                other->role = OFPCR12_ROLE_SLAVE;
             }
         }
     }
@@ -1092,7 +1104,7 @@ ofconn_flush(struct ofconn *ofconn)
     struct ofmonitor *monitor, *next_monitor;
     int i;
 
-    ofconn->role = NX_ROLE_OTHER;
+    ofconn->role = OFPCR12_ROLE_EQUAL;
     ofconn_set_protocol(ofconn, OFPUTIL_P_NONE);
     ofconn->packet_in_format = NXPIF_OPENFLOW10;
 
@@ -1307,7 +1319,7 @@ ofconn_receives_async_msg(const struct ofconn *ofconn,
         return false;
     }
 
-    async_config = (ofconn->role == NX_ROLE_SLAVE
+    async_config = (ofconn->role == OFPCR12_ROLE_SLAVE
                     ? ofconn->slave_async_config
                     : ofconn->master_async_config);
     if (!(async_config[type] & (1u << reason))) {
index 6ce413e..48b8119 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 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.
@@ -96,9 +96,10 @@ void connmgr_get_snoops(const struct connmgr *, struct sset *snoops);
 /* Individual connections to OpenFlow controllers. */
 enum ofconn_type ofconn_get_type(const struct ofconn *);
 
+bool ofconn_get_master_election_id(const struct ofconn *, uint64_t *idp);
 bool ofconn_set_master_election_id(struct ofconn *, uint64_t);
-enum nx_role ofconn_get_role(const struct ofconn *);
-void ofconn_set_role(struct ofconn *, enum nx_role);
+enum ofp12_controller_role ofconn_get_role(const struct ofconn *);
+void ofconn_set_role(struct ofconn *, enum ofp12_controller_role);
 
 enum ofputil_protocol ofconn_get_protocol(const struct ofconn *);
 void ofconn_set_protocol(struct ofconn *, enum ofputil_protocol);
index 3b98005..1a08fcc 100644 (file)
@@ -464,7 +464,7 @@ in_band_create(struct ofproto *ofproto, const char *local_name,
     int error;
 
     *in_bandp = NULL;
-    error = netdev_open(local_name, "system", &local_netdev);
+    error = netdev_open(local_name, "internal", &local_netdev);
     if (error) {
         VLOG_ERR("failed to initialize in-band control: cannot open "
                  "datapath local port %s (%s)", local_name, strerror(error));
index efd47b3..a4d7e59 100644 (file)
@@ -20,7 +20,6 @@
 
 #include <errno.h>
 
-#include "autopath.h"
 #include "bond.h"
 #include "bundle.h"
 #include "byte-order.h"
@@ -284,7 +283,6 @@ struct action_xlate_ctx {
     uint32_t sflow_odp_port;    /* Output port for composing sFlow action. */
     uint16_t user_cookie_offset;/* Used for user_action_cookie fixup. */
     bool exit;                  /* No further actions should be processed. */
-    struct flow orig_flow;      /* Copy of original flow. */
 };
 
 static void action_xlate_ctx_init(struct action_xlate_ctx *,
@@ -510,7 +508,6 @@ struct ofport_dpif {
     struct list bundle_node;    /* In struct ofbundle's "ports" list. */
     struct cfm *cfm;            /* Connectivity Fault Management, if any. */
     tag_type tag;               /* Tag associated with this port. */
-    uint32_t bond_stable_id;    /* stable_id to use as bond slave, or 0. */
     bool may_enable;            /* May be enabled in bonds. */
     long long int carrier_seq;  /* Carrier status changes. */
     struct tnl_port *tnl_port;  /* Tunnel handle, or null. */
@@ -634,7 +631,7 @@ struct dpif_backer {
     struct timer next_expiration;
     struct hmap odp_to_ofport_map; /* ODP port to ofport mapping. */
 
-    struct sset tnl_backers;       /* Set of dpif ports backing tunnels. */
+    struct simap tnl_backers;      /* Set of dpif ports backing tunnels. */
 
     /* Facet revalidation flags applying to facets which use this backer. */
     enum revalidate_reason need_revalidate; /* Revalidate every facet. */
@@ -724,7 +721,6 @@ static struct ofport_dpif *get_odp_port(const struct ofproto_dpif *,
 static void ofproto_trace(struct ofproto_dpif *, const struct flow *,
                           const struct ofpbuf *, ovs_be16 initial_tci,
                           struct ds *);
-static bool may_dpif_port_del(struct ofport_dpif *);
 
 /* Packet processing. */
 static void update_learning_table(struct ofproto_dpif *,
@@ -852,6 +848,58 @@ type_run(const char *type)
         struct tag_set revalidate_set = backer->revalidate_set;
         bool need_revalidate = backer->need_revalidate;
         struct ofproto_dpif *ofproto;
+        struct simap_node *node;
+        struct simap tmp_backers;
+
+        /* Handle tunnel garbage collection. */
+        simap_init(&tmp_backers);
+        simap_swap(&backer->tnl_backers, &tmp_backers);
+
+        HMAP_FOR_EACH (ofproto, all_ofproto_dpifs_node, &all_ofproto_dpifs) {
+            struct ofport_dpif *iter;
+
+            if (backer != ofproto->backer) {
+                continue;
+            }
+
+            HMAP_FOR_EACH (iter, up.hmap_node, &ofproto->up.ports) {
+                const char *dp_port;
+
+                if (!iter->tnl_port) {
+                    continue;
+                }
+
+                dp_port = netdev_vport_get_dpif_port(iter->up.netdev);
+                node = simap_find(&tmp_backers, dp_port);
+                if (node) {
+                    simap_put(&backer->tnl_backers, dp_port, node->data);
+                    simap_delete(&tmp_backers, node);
+                    node = simap_find(&backer->tnl_backers, dp_port);
+                } else {
+                    node = simap_find(&backer->tnl_backers, dp_port);
+                    if (!node) {
+                        uint32_t odp_port = UINT32_MAX;
+
+                        if (!dpif_port_add(backer->dpif, iter->up.netdev,
+                                           &odp_port)) {
+                            simap_put(&backer->tnl_backers, dp_port, odp_port);
+                            node = simap_find(&backer->tnl_backers, dp_port);
+                        }
+                    }
+                }
+
+                iter->odp_port = node ? node->data : OVSP_NONE;
+                if (tnl_port_reconfigure(&iter->up, iter->odp_port,
+                                         &iter->tnl_port)) {
+                    backer->need_revalidate = REV_RECONFIGURE;
+                }
+            }
+        }
+
+        SIMAP_FOR_EACH (node, &tmp_backers) {
+            dpif_port_del(backer->dpif, node->data);
+        }
+        simap_destroy(&tmp_backers);
 
         switch (backer->need_revalidate) {
         case REV_RECONFIGURE:   COVERAGE_INC(rev_reconfigure);   break;
@@ -867,6 +915,10 @@ type_run(const char *type)
             drop_key_clear(backer);
         }
 
+        /* Clear the revalidation flags. */
+        tag_set_init(&backer->revalidate_set);
+        backer->need_revalidate = 0;
+
         HMAP_FOR_EACH (ofproto, all_ofproto_dpifs_node, &all_ofproto_dpifs) {
             struct facet *facet;
 
@@ -874,10 +926,6 @@ type_run(const char *type)
                 continue;
             }
 
-            /* Clear the revalidation flags. */
-            tag_set_init(&backer->revalidate_set);
-            backer->need_revalidate = 0;
-
             HMAP_FOR_EACH (facet, hmap_node, &ofproto->facets) {
                 if (need_revalidate
                     || tag_set_intersects(&revalidate_set, facet->tags)) {
@@ -904,7 +952,7 @@ type_run(const char *type)
 
         HMAP_FOR_EACH (ofproto, all_ofproto_dpifs_node,
                        &all_ofproto_dpifs) {
-            if (sset_contains(&ofproto->backer->tnl_backers, devname)) {
+            if (simap_contains(&ofproto->backer->tnl_backers, devname)) {
                 goto next;
             }
         }
@@ -1029,7 +1077,7 @@ close_dpif_backer(struct dpif_backer *backer)
     drop_key_clear(backer);
     hmap_destroy(&backer->drop_keys);
 
-    sset_destroy(&backer->tnl_backers);
+    simap_destroy(&backer->tnl_backers);
     hmap_destroy(&backer->odp_to_ofport_map);
     node = shash_find(&all_dpif_backers, backer->type);
     free(backer->type);
@@ -1106,7 +1154,7 @@ open_dpif_backer(const char *type, struct dpif_backer **backerp)
     hmap_init(&backer->drop_keys);
     timer_set_duration(&backer->next_expiration, 1000);
     backer->need_revalidate = 0;
-    sset_init(&backer->tnl_backers);
+    simap_init(&backer->tnl_backers);
     tag_set_init(&backer->revalidate_set);
     *backerp = backer;
 
@@ -1601,12 +1649,14 @@ port_construct(struct ofport *port_)
         if (odp_port_to_ofp_port(ofproto, port->odp_port) != OFPP_NONE) {
             VLOG_ERR("port %s already has an OpenFlow port number",
                      dpif_port.name);
+            dpif_port_destroy(&dpif_port);
             return EBUSY;
         }
 
         hmap_insert(&ofproto->backer->odp_to_ofport_map, &port->odp_port_node,
                     hash_int(port->odp_port, 0));
     }
+    dpif_port_destroy(&dpif_port);
 
     if (ofproto->sflow) {
         dpif_sflow_add_port(ofproto->sflow, port_, port->odp_port);
@@ -1623,14 +1673,15 @@ port_destruct(struct ofport *port_)
     const char *dp_port_name = netdev_vport_get_dpif_port(port->up.netdev);
     const char *devname = netdev_get_name(port->up.netdev);
 
-    if (dpif_port_exists(ofproto->backer->dpif, dp_port_name)
-        && may_dpif_port_del(port)) {
+    if (dpif_port_exists(ofproto->backer->dpif, dp_port_name)) {
         /* The underlying device is still there, so delete it.  This
          * happens when the ofproto is being destroyed, since the caller
          * assumes that removal of attached ports will happen as part of
          * destruction. */
-        dpif_port_del(ofproto->backer->dpif, port->odp_port);
-        sset_find_and_delete(&ofproto->backer->tnl_backers, dp_port_name);
+        if (!port->tnl_port) {
+            dpif_port_del(ofproto->backer->dpif, port->odp_port);
+        }
+        ofproto->backer->need_revalidate = REV_RECONFIGURE;
     }
 
     if (port->odp_port != OVSP_NONE && !port->tnl_port) {
@@ -2213,8 +2264,7 @@ bundle_del_port(struct ofport_dpif *port)
 
 static bool
 bundle_add_port(struct ofbundle *bundle, uint32_t ofp_port,
-                struct lacp_slave_settings *lacp,
-                uint32_t bond_stable_id)
+                struct lacp_slave_settings *lacp)
 {
     struct ofport_dpif *port;
 
@@ -2241,8 +2291,6 @@ bundle_add_port(struct ofbundle *bundle, uint32_t ofp_port,
         lacp_slave_register(bundle->lacp, port, lacp);
     }
 
-    port->bond_stable_id = bond_stable_id;
-
     return true;
 }
 
@@ -2350,8 +2398,7 @@ bundle_set(struct ofproto *ofproto_, void *aux,
     ok = true;
     for (i = 0; i < s->n_slaves; i++) {
         if (!bundle_add_port(bundle, s->slaves[i],
-                             s->lacp ? &s->lacp_slaves[i] : NULL,
-                             s->bond_stable_ids ? s->bond_stable_ids[i] : 0)) {
+                             s->lacp ? &s->lacp_slaves[i] : NULL)) {
             ok = false;
         }
     }
@@ -2451,8 +2498,7 @@ bundle_set(struct ofproto *ofproto_, void *aux,
         }
 
         LIST_FOR_EACH (port, bundle_node, &bundle->ports) {
-            bond_slave_register(bundle->bond, port, port->bond_stable_id,
-                                port->up.netdev);
+            bond_slave_register(bundle->bond, port, port->up.netdev);
         }
     } else {
         bond_destroy(bundle->bond);
@@ -3020,58 +3066,26 @@ port_add(struct ofproto *ofproto_, struct netdev *netdev)
     }
 
     if (!dpif_port_exists(ofproto->backer->dpif, dp_port_name)) {
-        int error = dpif_port_add(ofproto->backer->dpif, netdev, NULL);
+        uint32_t port_no = UINT32_MAX;
+        int error;
+
+        error = dpif_port_add(ofproto->backer->dpif, netdev, &port_no);
         if (error) {
             return error;
         }
+        if (netdev_get_tunnel_config(netdev)) {
+            simap_put(&ofproto->backer->tnl_backers, dp_port_name, port_no);
+        }
     }
 
     if (netdev_get_tunnel_config(netdev)) {
         sset_add(&ofproto->ghost_ports, devname);
-        sset_add(&ofproto->backer->tnl_backers, dp_port_name);
     } else {
         sset_add(&ofproto->ports, devname);
     }
     return 0;
 }
 
-/* Returns true if the odp_port backing 'ofport' may be deleted from the
- * datapath. In most cases, this function simply returns true. However, for
- * tunnels it's possible that multiple ofports use the same odp_port, in which
- * case we need to keep the odp_port backer around until the last ofport is
- * deleted. */
-static bool
-may_dpif_port_del(struct ofport_dpif *ofport)
-{
-    struct dpif_backer *backer = ofproto_dpif_cast(ofport->up.ofproto)->backer;
-    struct ofproto_dpif *ofproto_iter;
-
-    if (!ofport->tnl_port) {
-        return true;
-    }
-
-    HMAP_FOR_EACH (ofproto_iter, all_ofproto_dpifs_node, &all_ofproto_dpifs) {
-        struct ofport_dpif *iter;
-
-        if (backer != ofproto_iter->backer) {
-            continue;
-        }
-
-        HMAP_FOR_EACH (iter, up.hmap_node, &ofproto_iter->up.ports) {
-            if (ofport == iter) {
-                continue;
-            }
-
-            if (!strcmp(netdev_vport_get_dpif_port(ofport->up.netdev),
-                        netdev_vport_get_dpif_port(iter->up.netdev))) {
-                return false;
-            }
-        }
-    }
-
-    return true;
-}
-
 static int
 port_del(struct ofproto *ofproto_, uint16_t ofp_port)
 {
@@ -3085,17 +3099,14 @@ port_del(struct ofproto *ofproto_, uint16_t ofp_port)
 
     sset_find_and_delete(&ofproto->ghost_ports,
                          netdev_get_name(ofport->up.netdev));
-    if (may_dpif_port_del(ofport)) {
+    ofproto->backer->need_revalidate = REV_RECONFIGURE;
+    if (!ofport->tnl_port) {
         error = dpif_port_del(ofproto->backer->dpif, ofport->odp_port);
         if (!error) {
-            const char *dpif_port;
-
             /* The caller is going to close ofport->up.netdev.  If this is a
              * bonded port, then the bond is using that netdev, so remove it
              * from the bond.  The client will need to reconfigure everything
              * after deleting ports, so then the slave will get re-added. */
-            dpif_port = netdev_vport_get_dpif_port(ofport->up.netdev);
-            sset_find_and_delete(&ofproto->backer->tnl_backers, dpif_port);
             bundle_remove(&ofport->up);
         }
     }
@@ -3163,6 +3174,9 @@ struct port_dump_state {
     uint32_t bucket;
     uint32_t offset;
     bool ghost;
+
+    struct ofproto_port port;
+    bool has_port;
 };
 
 static int
@@ -3181,12 +3195,20 @@ port_dump_next(const struct ofproto *ofproto_, void *state_,
     const struct sset *sset;
     struct sset_node *node;
 
+    if (state->has_port) {
+        ofproto_port_destroy(&state->port);
+        state->has_port = false;
+    }
     sset = state->ghost ? &ofproto->ghost_ports : &ofproto->ports;
     while ((node = sset_at_position(sset, &state->bucket, &state->offset))) {
         int error;
 
-        error = port_query_by_name(ofproto_, node->name, port);
-        if (error != ENODEV) {
+        error = port_query_by_name(ofproto_, node->name, &state->port);
+        if (!error) {
+            *port = state->port;
+            state->has_port = true;
+            return 0;
+        } else if (error != ENODEV) {
             return error;
         }
     }
@@ -3206,6 +3228,9 @@ port_dump_done(const struct ofproto *ofproto_ OVS_UNUSED, void *state_)
 {
     struct port_dump_state *state = state_;
 
+    if (state->has_port) {
+        ofproto_port_destroy(&state->port);
+    }
     free(state);
     return 0;
 }
@@ -3302,15 +3327,11 @@ send_packet_in_miss(struct ofproto_dpif *ofproto, const struct ofpbuf *packet,
 
 static enum slow_path_reason
 process_special(struct ofproto_dpif *ofproto, const struct flow *flow,
-                const struct ofpbuf *packet)
+                const struct ofport_dpif *ofport, const struct ofpbuf *packet)
 {
-    struct ofport_dpif *ofport = get_ofp_port(ofproto, flow->in_port);
-
     if (!ofport) {
         return 0;
-    }
-
-    if (ofport->cfm && cfm_should_process_flow(ofport->cfm, flow)) {
+    } else if (ofport->cfm && cfm_should_process_flow(ofport->cfm, flow)) {
         if (packet) {
             cfm_process_heartbeat(ofport->cfm, packet);
         }
@@ -3326,17 +3347,19 @@ process_special(struct ofproto_dpif *ofproto, const struct flow *flow,
             stp_process_packet(ofport, packet);
         }
         return SLOW_STP;
+    } else {
+        return 0;
     }
-    return 0;
 }
 
 static struct flow_miss *
-flow_miss_find(struct hmap *todo, const struct flow *flow, uint32_t hash)
+flow_miss_find(struct hmap *todo, const struct ofproto_dpif *ofproto,
+               const struct flow *flow, uint32_t hash)
 {
     struct flow_miss *miss;
 
     HMAP_FOR_EACH_WITH_HASH (miss, hmap_node, hash, todo) {
-        if (flow_equal(&miss->flow, flow)) {
+        if (miss->ofproto == ofproto && flow_equal(&miss->flow, flow)) {
             return miss;
         }
     }
@@ -3804,7 +3827,7 @@ handle_miss_upcalls(struct dpif_backer *backer, struct dpif_upcall *upcalls,
 
         /* Add other packets to a to-do list. */
         hash = flow_hash(&miss->flow, 0);
-        existing_miss = flow_miss_find(&todo, &miss->flow, hash);
+        existing_miss = flow_miss_find(&todo, ofproto, &miss->flow, hash);
         if (!existing_miss) {
             hmap_insert(&todo, &miss->hmap_node, hash);
             miss->ofproto = ofproto;
@@ -3878,7 +3901,16 @@ classify_upcall(const struct dpif_upcall *upcall)
     }
 
     /* "action" upcalls need a closer look. */
-    memcpy(&cookie, &upcall->userdata, sizeof(cookie));
+    if (!upcall->userdata) {
+        VLOG_WARN_RL(&rl, "action upcall missing cookie");
+        return BAD_UPCALL;
+    }
+    if (nl_attr_get_size(upcall->userdata) != sizeof(cookie)) {
+        VLOG_WARN_RL(&rl, "action upcall cookie has unexpected size %zu",
+                     nl_attr_get_size(upcall->userdata));
+        return BAD_UPCALL;
+    }
+    memcpy(&cookie, nl_attr_get(upcall->userdata), sizeof(cookie));
     switch (cookie.type) {
     case USER_ACTION_COOKIE_SFLOW:
         return SFLOW_UPCALL;
@@ -3888,7 +3920,8 @@ classify_upcall(const struct dpif_upcall *upcall)
 
     case USER_ACTION_COOKIE_UNSPEC:
     default:
-        VLOG_WARN_RL(&rl, "invalid user cookie : 0x%"PRIx64, upcall->userdata);
+        VLOG_WARN_RL(&rl, "invalid user cookie : 0x%"PRIx64,
+                     nl_attr_get_u64(upcall->userdata));
         return BAD_UPCALL;
     }
 }
@@ -3908,7 +3941,7 @@ handle_sflow_upcall(struct dpif_backer *backer,
         return;
     }
 
-    memcpy(&cookie, &upcall->userdata, sizeof(cookie));
+    memcpy(&cookie, nl_attr_get(upcall->userdata), sizeof(cookie));
     dpif_sflow_received(ofproto->sflow, upcall->packet, &flow,
                         odp_in_port, &cookie);
 }
@@ -5505,6 +5538,7 @@ send_packet(const struct ofport_dpif *ofport, struct ofpbuf *packet)
         dpif_flow_stats_extract(&flow, packet, time_msec(), &stats);
         netdev_vport_inc_tx(ofport->up.netdev, &stats);
         odp_put_tunnel_action(&flow.tunnel, &odp_actions);
+        odp_put_skb_mark_action(flow.skb_mark, &odp_actions);
     } else {
         odp_port = vsp_realdev_to_vlandev(ofproto, ofport->odp_port,
                                           flow.vlan_tci);
@@ -5537,6 +5571,7 @@ send_packet(const struct ofport_dpif *ofport, struct ofpbuf *packet)
 \f
 /* OpenFlow to datapath action translation. */
 
+static bool may_receive(const struct ofport_dpif *, struct action_xlate_ctx *);
 static void do_xlate_actions(const struct ofpact *, size_t ofpacts_len,
                              struct action_xlate_ctx *);
 static void xlate_normal(struct action_xlate_ctx *);
@@ -5567,7 +5602,7 @@ compose_slow_path(const struct ofproto_dpif *ofproto, const struct flow *flow,
     ofpbuf_use_stack(&buf, stub, stub_size);
     if (slow & (SLOW_CFM | SLOW_LACP | SLOW_STP)) {
         uint32_t pid = dpif_port_get_pid(ofproto->backer->dpif, UINT32_MAX);
-        odp_put_userspace_action(pid, &cookie, &buf);
+        odp_put_userspace_action(pid, &cookie, sizeof cookie, &buf);
     } else {
         put_userspace_action(ofproto, &buf, flow, &cookie);
     }
@@ -5586,7 +5621,7 @@ put_userspace_action(const struct ofproto_dpif *ofproto,
     pid = dpif_port_get_pid(ofproto->backer->dpif,
                             ofp_port_to_odp_port(ofproto, flow->in_port));
 
-    return odp_put_userspace_action(pid, cookie, odp_actions);
+    return odp_put_userspace_action(pid, cookie, sizeof *cookie, odp_actions);
 }
 
 static void
@@ -5700,7 +5735,7 @@ compose_output_action__(struct action_xlate_ctx *ctx, uint16_t ofp_port,
 
     /* If 'struct flow' gets additional metadata, we'll need to zero it out
      * before traversing a patch port. */
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 18);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 19);
 
     if (!ofport) {
         xlate_report(ctx, "Nonexistent output port");
@@ -5717,6 +5752,8 @@ compose_output_action__(struct action_xlate_ctx *ctx, uint16_t ofp_port,
         struct ofport_dpif *peer = ofport_get_peer(ofport);
         struct flow old_flow = ctx->flow;
         const struct ofproto_dpif *peer_ofproto;
+        enum slow_path_reason special;
+        struct ofport_dpif *in_port;
 
         if (!peer) {
             xlate_report(ctx, "Nonexistent patch port peer");
@@ -5734,7 +5771,26 @@ compose_output_action__(struct action_xlate_ctx *ctx, uint16_t ofp_port,
         ctx->flow.metadata = htonll(0);
         memset(&ctx->flow.tunnel, 0, sizeof ctx->flow.tunnel);
         memset(ctx->flow.regs, 0, sizeof ctx->flow.regs);
-        xlate_table_action(ctx, ctx->flow.in_port, 0, true);
+
+        in_port = get_ofp_port(ctx->ofproto, ctx->flow.in_port);
+        special = process_special(ctx->ofproto, &ctx->flow, in_port,
+                                  ctx->packet);
+        if (special) {
+            ctx->slow |= special;
+        } else if (!in_port || may_receive(in_port, ctx)) {
+            if (!in_port || stp_forward_in_state(in_port->stp_state)) {
+                xlate_table_action(ctx, ctx->flow.in_port, 0, true);
+            } else {
+                /* Forwarding is disabled by STP.  Let OFPP_NORMAL and the
+                 * learning action look at the packet, then drop it. */
+                struct flow old_base_flow = ctx->base_flow;
+                size_t old_size = ctx->odp_actions->size;
+                xlate_table_action(ctx, ctx->flow.in_port, 0, true);
+                ctx->base_flow = old_base_flow;
+                ctx->odp_actions->size = old_size;
+            }
+        }
+
         ctx->flow = old_flow;
         ctx->ofproto = ofproto_dpif_cast(ofport->up.ofproto);
 
@@ -5922,16 +5978,11 @@ execute_controller_action(struct action_xlate_ctx *ctx, int len,
 
     if (packet->l2 && packet->l3) {
         struct eth_header *eh;
+        uint16_t mpls_depth;
 
         eth_pop_vlan(packet);
         eh = packet->l2;
 
-        /* If the Ethernet type is less than ETH_TYPE_MIN, it's likely an 802.2
-         * LLC frame.  Calculating the Ethernet type of these frames is more
-         * trouble than seems appropriate for a simple assertion. */
-        ovs_assert(ntohs(eh->eth_type) < ETH_TYPE_MIN
-                   || eh->eth_type == ctx->flow.dl_type);
-
         memcpy(eh->eth_src, ctx->flow.dl_src, sizeof eh->eth_src);
         memcpy(eh->eth_dst, ctx->flow.dl_dst, sizeof eh->eth_dst);
 
@@ -5939,6 +5990,16 @@ execute_controller_action(struct action_xlate_ctx *ctx, int len,
             eth_push_vlan(packet, ctx->flow.vlan_tci);
         }
 
+        mpls_depth = eth_mpls_depth(packet);
+
+        if (mpls_depth < ctx->flow.mpls_depth) {
+            push_mpls(packet, ctx->flow.dl_type, ctx->flow.mpls_lse);
+        } else if (mpls_depth > ctx->flow.mpls_depth) {
+            pop_mpls(packet, ctx->flow.dl_type);
+        } else if (mpls_depth) {
+            set_mpls_lse(packet, ctx->flow.mpls_lse);
+        }
+
         if (packet->l4) {
             if (ctx->flow.dl_type == htons(ETH_TYPE_IP)) {
                 packet_set_ipv4(packet, ctx->flow.nw_src, ctx->flow.nw_dst,
@@ -5971,6 +6032,48 @@ execute_controller_action(struct action_xlate_ctx *ctx, int len,
     ofpbuf_delete(packet);
 }
 
+static void
+execute_mpls_push_action(struct action_xlate_ctx *ctx, ovs_be16 eth_type)
+{
+    ovs_assert(eth_type_mpls(eth_type));
+
+    if (ctx->base_flow.mpls_depth) {
+        ctx->flow.mpls_lse &= ~htonl(MPLS_BOS_MASK);
+        ctx->flow.mpls_depth++;
+    } else {
+        ovs_be32 label;
+        uint8_t tc, ttl;
+
+        if (ctx->flow.dl_type == htons(ETH_TYPE_IPV6)) {
+            label = htonl(0x2); /* IPV6 Explicit Null. */
+        } else {
+            label = htonl(0x0); /* IPV4 Explicit Null. */
+        }
+        tc = (ctx->flow.nw_tos & IP_DSCP_MASK) >> 2;
+        ttl = ctx->flow.nw_ttl ? ctx->flow.nw_ttl : 0x40;
+        ctx->flow.mpls_lse = set_mpls_lse_values(ttl, tc, 1, label);
+        ctx->flow.encap_dl_type = ctx->flow.dl_type;
+        ctx->flow.mpls_depth = 1;
+    }
+    ctx->flow.dl_type = eth_type;
+}
+
+static void
+execute_mpls_pop_action(struct action_xlate_ctx *ctx, ovs_be16 eth_type)
+{
+    ovs_assert(eth_type_mpls(ctx->flow.dl_type));
+    ovs_assert(!eth_type_mpls(eth_type));
+
+    if (ctx->flow.mpls_depth) {
+        ctx->flow.mpls_depth--;
+        ctx->flow.mpls_lse = htonl(0);
+        if (!ctx->flow.mpls_depth) {
+            ctx->flow.dl_type = eth_type;
+            ctx->flow.encap_dl_type = htons(0);
+        }
+    }
+}
+
 static bool
 compose_dec_ttl(struct action_xlate_ctx *ctx, struct ofpact_cnt_ids *ids)
 {
@@ -6112,26 +6215,6 @@ struct xlate_reg_state {
     ovs_be64 tun_id;
 };
 
-static void
-xlate_autopath(struct action_xlate_ctx *ctx,
-               const struct ofpact_autopath *ap)
-{
-    uint16_t ofp_port = ap->port;
-    struct ofport_dpif *port = get_ofp_port(ctx->ofproto, ofp_port);
-
-    if (!port || !port->bundle) {
-        ofp_port = OFPP_NONE;
-    } else if (port->bundle->bond) {
-        /* Autopath does not support VLAN hashing. */
-        struct ofport_dpif *slave = bond_choose_output_slave(
-            port->bundle->bond, &ctx->flow, 0, &ctx->tags);
-        if (slave) {
-            ofp_port = slave->up.ofp_port;
-        }
-    }
-    nxm_reg_load(&ap->dst, ofp_port, &ctx->flow);
-}
-
 static bool
 slave_enabled_cb(uint16_t ofp_port, void *ofproto_)
 {
@@ -6237,16 +6320,9 @@ static void
 do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
                  struct action_xlate_ctx *ctx)
 {
-    const struct ofport_dpif *port;
     bool was_evictable = true;
     const struct ofpact *a;
 
-    port = get_ofp_port(ctx->ofproto, ctx->flow.in_port);
-    if (port && !may_receive(port, ctx)) {
-        /* Drop this flow. */
-        return;
-    }
-
     if (ctx->rule) {
         /* Don't let the rule we're working on get evicted underneath us. */
         was_evictable = ctx->rule->up.evictable;
@@ -6357,6 +6433,14 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
             nxm_execute_reg_load(ofpact_get_REG_LOAD(a), &ctx->flow);
             break;
 
+        case OFPACT_PUSH_MPLS:
+            execute_mpls_push_action(ctx, ofpact_get_PUSH_MPLS(a)->ethertype);
+            break;
+
+        case OFPACT_POP_MPLS:
+            execute_mpls_pop_action(ctx, ofpact_get_POP_MPLS(a)->ethertype);
+            break;
+
         case OFPACT_DEC_TTL:
             if (compose_dec_ttl(ctx, ofpact_get_DEC_TTL(a))) {
                 goto out;
@@ -6371,10 +6455,6 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
             multipath_execute(ofpact_get_MULTIPATH(a), &ctx->flow);
             break;
 
-        case OFPACT_AUTOPATH:
-            xlate_autopath(ctx, ofpact_get_AUTOPATH(a));
-            break;
-
         case OFPACT_BUNDLE:
             ctx->ofproto->has_bundle_action = true;
             xlate_bundle_action(ctx, ofpact_get_BUNDLE(a));
@@ -6426,12 +6506,6 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
     }
 
 out:
-    /* We've let OFPP_NORMAL and the learning action look at the packet,
-     * so drop it now if forwarding is disabled. */
-    if (port && !stp_forward_in_state(port->stp_state)) {
-        ofpbuf_clear(ctx->odp_actions);
-        add_sflow_action(ctx);
-    }
     if (ctx->rule) {
         ctx->rule->up.evictable = was_evictable;
     }
@@ -6494,6 +6568,8 @@ xlate_actions(struct action_xlate_ctx *ctx,
     static bool hit_resubmit_limit;
 
     enum slow_path_reason special;
+    struct ofport_dpif *in_port;
+    struct flow orig_flow;
 
     COVERAGE_INC(ofproto_dpif_xlate);
 
@@ -6516,12 +6592,8 @@ xlate_actions(struct action_xlate_ctx *ctx,
 
     if (ctx->ofproto->has_mirrors || hit_resubmit_limit) {
         /* Do this conditionally because the copy is expensive enough that it
-         * shows up in profiles.
-         *
-         * We keep orig_flow in 'ctx' only because I couldn't make GCC 4.4
-         * believe that I wasn't using it without initializing it if I kept it
-         * in a local variable. */
-        ctx->orig_flow = ctx->flow;
+         * shows up in profiles. */
+        orig_flow = ctx->flow;
     }
 
     if (ctx->flow.nw_frag & FLOW_NW_FRAG_ANY) {
@@ -6547,7 +6619,8 @@ xlate_actions(struct action_xlate_ctx *ctx,
         }
     }
 
-    special = process_special(ctx->ofproto, &ctx->flow, ctx->packet);
+    in_port = get_ofp_port(ctx->ofproto, ctx->flow.in_port);
+    special = process_special(ctx->ofproto, &ctx->flow, in_port, ctx->packet);
     if (special) {
         ctx->slow |= special;
     } else {
@@ -6556,7 +6629,17 @@ xlate_actions(struct action_xlate_ctx *ctx,
         uint32_t local_odp_port;
 
         add_sflow_action(ctx);
-        do_xlate_actions(ofpacts, ofpacts_len, ctx);
+
+        if (!in_port || may_receive(in_port, ctx)) {
+            do_xlate_actions(ofpacts, ofpacts_len, ctx);
+
+            /* We've let OFPP_NORMAL and the learning action look at the
+             * packet, so drop it now if forwarding is disabled. */
+            if (in_port && !stp_forward_in_state(in_port->stp_state)) {
+                ofpbuf_clear(ctx->odp_actions);
+                add_sflow_action(ctx);
+            }
+        }
 
         if (ctx->max_resubmit_trigger && !ctx->resubmit_hook) {
             if (!hit_resubmit_limit) {
@@ -6566,7 +6649,7 @@ xlate_actions(struct action_xlate_ctx *ctx,
             } else if (!VLOG_DROP_ERR(&trace_rl)) {
                 struct ds ds = DS_EMPTY_INITIALIZER;
 
-                ofproto_trace(ctx->ofproto, &ctx->orig_flow, ctx->packet,
+                ofproto_trace(ctx->ofproto, &orig_flow, ctx->packet,
                               initial_tci, &ds);
                 VLOG_ERR("Trace triggered by excessive resubmit "
                          "recursion:\n%s", ds_cstr(&ds));
@@ -6587,7 +6670,7 @@ xlate_actions(struct action_xlate_ctx *ctx,
             }
         }
         if (ctx->ofproto->has_mirrors) {
-            add_mirror_actions(ctx, &ctx->orig_flow);
+            add_mirror_actions(ctx, &orig_flow);
         }
         fix_sflow_action(ctx);
     }
index c0d94f7..a9c7e76 100644 (file)
@@ -2238,7 +2238,7 @@ handle_set_config(struct ofconn *ofconn, const struct ofp_header *oh)
     uint16_t flags = ntohs(osc->flags);
 
     if (ofconn_get_type(ofconn) != OFCONN_PRIMARY
-        || ofconn_get_role(ofconn) != NX_ROLE_SLAVE) {
+        || ofconn_get_role(ofconn) != OFPCR12_ROLE_SLAVE) {
         enum ofp_config_flags cur = ofproto->frag_handling;
         enum ofp_config_flags next = flags & OFPC_FRAG_MASK;
 
@@ -2272,7 +2272,7 @@ static enum ofperr
 reject_slave_controller(struct ofconn *ofconn)
 {
     if (ofconn_get_type(ofconn) == OFCONN_PRIMARY
-        && ofconn_get_role(ofconn) == NX_ROLE_SLAVE) {
+        && ofconn_get_role(ofconn) == OFPCR12_ROLE_SLAVE) {
         return OFPERR_OFPBRC_EPERM;
     } else {
         return 0;
@@ -3576,38 +3576,34 @@ handle_flow_mod__(struct ofproto *ofproto, struct ofconn *ofconn,
 static enum ofperr
 handle_role_request(struct ofconn *ofconn, const struct ofp_header *oh)
 {
-    struct ofputil_role_request rr;
+    struct ofputil_role_request request;
+    struct ofputil_role_request reply;
     struct ofpbuf *buf;
-    uint32_t role;
     enum ofperr error;
 
-    error = ofputil_decode_role_message(oh, &rr);
+    error = ofputil_decode_role_message(oh, &request);
     if (error) {
         return error;
     }
 
-    if (rr.request_current_role_only) {
-        role = ofconn_get_role(ofconn); /* NX_ROLE_* */
-        goto reply;
-    }
-
-    role = rr.role;
-
-    if (ofconn_get_role(ofconn) != role
-        && ofconn_has_pending_opgroups(ofconn)) {
-        return OFPROTO_POSTPONE;
-    }
+    if (request.role != OFPCR12_ROLE_NOCHANGE) {
+        if (ofconn_get_role(ofconn) != request.role
+            && ofconn_has_pending_opgroups(ofconn)) {
+            return OFPROTO_POSTPONE;
+        }
 
-    if (rr.have_generation_id) {
-        if (!ofconn_set_master_election_id(ofconn, rr.generation_id)) {
-            return OFPERR_OFPRRFC_STALE;
+        if (request.have_generation_id
+            && !ofconn_set_master_election_id(ofconn, request.generation_id)) {
+                return OFPERR_OFPRRFC_STALE;
         }
-    }
 
-    ofconn_set_role(ofconn, role);
+        ofconn_set_role(ofconn, request.role);
+    }
 
-reply:
-    buf = ofputil_encode_role_reply(oh, role);
+    reply.role = ofconn_get_role(ofconn);
+    reply.have_generation_id = ofconn_get_master_election_id(
+        ofconn, &reply.generation_id);
+    buf = ofputil_encode_role_reply(oh, &reply);
     ofconn_send_reply(ofconn, buf);
 
     return 0;
index 413472a..3a66d1b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 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.
@@ -44,7 +44,7 @@ struct netdev_stats;
 
 struct ofproto_controller_info {
     bool is_connected;
-    enum nx_role role;
+    enum ofp12_controller_role role;
     struct {
         const char *keys[4];
         const char *values[4];
@@ -282,7 +282,6 @@ struct ofproto_bundle_settings {
     bool use_priority_tags;     /* Use 802.1p tag for frames in VLAN 0? */
 
     struct bond_settings *bond; /* Must be nonnull iff if n_slaves > 1. */
-    uint32_t *bond_stable_ids;  /* Array of n_slaves elements. */
 
     struct lacp_settings *lacp;              /* Nonnull to enable LACP. */
     struct lacp_slave_settings *lacp_slaves; /* Array of n_slaves elements. */
index ddfeeda..7d45930 100644 (file)
  *
  * Ability to generate actions on input for ECN
  * Ability to generate metadata for packet-outs
- * IPsec using skb mark.
  * VXLAN.
  * Multicast group management (possibly).
  * Disallow netdevs with names like "gre64_system" to prevent collisions. */
 
 VLOG_DEFINE_THIS_MODULE(tunnel);
 
+/* skb mark used for IPsec tunnel packets */
+#define IPSEC_MARK 1
+
 struct tnl_match {
     ovs_be64 in_key;
     ovs_be32 ip_src;
     ovs_be32 ip_dst;
     uint32_t odp_port;
-    bool in_key_present;
+    uint32_t skb_mark;
     bool in_key_flow;
 };
 
@@ -95,7 +97,7 @@ tnl_port_add__(const struct ofport *ofport, uint32_t odp_port,
     tnl_port->match.in_key = cfg->in_key;
     tnl_port->match.ip_src = cfg->ip_src;
     tnl_port->match.ip_dst = cfg->ip_dst;
-    tnl_port->match.in_key_present = cfg->in_key_present;
+    tnl_port->match.skb_mark = cfg->ipsec ? IPSEC_MARK : 0;
     tnl_port->match.in_key_flow = cfg->in_key_flow;
     tnl_port->match.odp_port = odp_port;
 
@@ -185,7 +187,7 @@ tnl_port_receive(struct flow *flow)
     match.ip_src = flow->tunnel.ip_dst;
     match.ip_dst = flow->tunnel.ip_src;
     match.in_key = flow->tunnel.tun_id;
-    match.in_key_present = flow->tunnel.flags & FLOW_TNL_F_KEY;
+    match.skb_mark = flow->skb_mark;
 
     tnl_port = tnl_find(&match);
     if (!tnl_port) {
@@ -251,6 +253,7 @@ tnl_port_send(const struct tnl_port *tnl_port, struct flow *flow)
 
     flow->tunnel.ip_src = tnl_port->match.ip_src;
     flow->tunnel.ip_dst = tnl_port->match.ip_dst;
+    flow->skb_mark = tnl_port->match.skb_mark;
 
     if (!cfg->out_key_flow) {
         flow->tunnel.tun_id = cfg->out_key;
@@ -389,15 +392,14 @@ tnl_match_fmt(const struct tnl_match *match, struct ds *ds)
     ds_put_format(ds, IP_FMT"->"IP_FMT, IP_ARGS(match->ip_src),
                   IP_ARGS(match->ip_dst));
 
-    if (match->in_key_present) {
-        if (match->in_key_flow) {
-            ds_put_cstr(ds, ", key=flow");
-        } else {
-            ds_put_format(ds, ", key=%#"PRIx64, ntohll(match->in_key));
-        }
+    if (match->in_key_flow) {
+        ds_put_cstr(ds, ", key=flow");
+    } else {
+        ds_put_format(ds, ", key=%#"PRIx64, ntohll(match->in_key));
     }
 
     ds_put_format(ds, ", dp port=%"PRIu32, match->odp_port);
+    ds_put_format(ds, ", skb mark=%"PRIu32, match->skb_mark);
 }
 
 static void
@@ -407,8 +409,8 @@ tnl_port_mod_log(const struct tnl_port *tnl_port, const char *action)
         struct ds ds = DS_EMPTY_INITIALIZER;
 
         tnl_match_fmt(&tnl_port->match, &ds);
-        VLOG_DBG("%s tunnel port %s (%s)", action, tnl_port_get_name(tnl_port),
-                 ds_cstr(&ds));
+        VLOG_INFO("%s tunnel port %s (%s)", action,
+                  tnl_port_get_name(tnl_port), ds_cstr(&ds));
         ds_destroy(&ds);
     }
 }
index fd646f0..b02d5a3 100644 (file)
@@ -598,8 +598,8 @@ ovsdb_file_commit(struct ovsdb_replica *replica,
     }
     file->n_transactions++;
 
-    /* If it has been at least COMPACT_MIN_MSEC millseconds since the last time
-     * we compacted (or at least COMPACT_RETRY_MSEC since the last time we
+    /* If it has been at least COMPACT_MIN_MSEC ms since the last time we
+     * compacted (or at least COMPACT_RETRY_MSEC ms since the last time we
      * tried), and if there are at least 100 transactions in the database, and
      * if the database is at least 10 MB, then compact the database. */
     if (time_msec() >= file->next_compact
index 6b75f49..b50b39b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 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.
@@ -435,8 +435,8 @@ print_db_changes(struct shash *tables, struct shash *names,
                              ? shash_find_data(&table_schema->columns, column)
                              : NULL);
                         if (column_schema) {
-                            const struct ovsdb_error *error;
                             const struct ovsdb_type *type;
+                            struct ovsdb_error *error;
                             struct ovsdb_datum datum;
 
                             type = &column_schema->type;
@@ -448,6 +448,8 @@ print_db_changes(struct shash *tables, struct shash *names,
                                 ds_init(&s);
                                 ovsdb_datum_to_string(&datum, type, &s);
                                 value_string = ds_steal_cstr(&s);
+                            } else {
+                                ovsdb_error_destroy(error);
                             }
                         }
                         if (!value_string) {
index 5865acd..bd1c259 100644 (file)
@@ -287,7 +287,9 @@ class BaseType(object):
         if self.enum:
             literals = [value.toEnglish(escapeLiteral)
                         for value in self.enum.values]
-            if len(literals) == 2:
+            if len(literals) == 1:
+                english = 'must be %s' % (literals[0])
+            elif len(literals) == 2:
                 english = 'either %s or %s' % (literals[0], literals[1])
             else:
                 english = 'one of %s, %s, or %s' % (literals[0],
index c640ebf..fb083ee 100644 (file)
@@ -107,6 +107,8 @@ class Stream(object):
             return errno.EAFNOSUPPORT, None
 
         suffix = name.split(":", 1)[1]
+        if name.startswith("unix:"):
+            suffix = ovs.util.abs_file_name(ovs.dirs.RUNDIR, suffix)
         error, sock = cls._open(suffix, dscp)
         if error:
             return error, None
@@ -282,6 +284,8 @@ class PassiveStream(object):
             return errno.EAFNOSUPPORT, None
 
         bind_path = name[6:]
+        if name.startswith("punix:"):
+            bind_path = ovs.util.abs_file_name(ovs.dirs.RUNDIR, bind_path)
         error, sock = ovs.socket_util.make_unix_socket(socket.SOCK_STREAM,
                                                        True, bind_path, None)
         if error:
index 46b94b9..73751d4 100644 (file)
@@ -6,6 +6,8 @@
 # without warranty of any kind.
 
 /var/log/openvswitch/*.log {
+       daily
+       compress
        sharedscripts
        missingok
        postrotate
index 1ebdf85..b11e0a2 100644 (file)
@@ -21,7 +21,6 @@ TESTSUITE_AT = \
        tests/ovs-ofctl.at \
        tests/odp.at \
        tests/multipath.at \
-       tests/autopath.at \
        tests/lacp.at \
        tests/learn.at \
        tests/vconn.at \
@@ -308,6 +307,7 @@ CHECK_PYFILES = \
        tests/test-ovsdb.py \
        tests/test-reconnect.py \
        tests/MockXenAPI.py \
+       tests/test-unix-socket.py \
        tests/test-unixctl.py \
        tests/test-vlog.py
 EXTRA_DIST += $(CHECK_PYFILES)
diff --git a/tests/autopath.at b/tests/autopath.at
deleted file mode 100644 (file)
index 557c92c..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-AT_BANNER([autopath link selection])
-
-AT_SETUP([autopath basic])
-AT_CHECK([ovs-ofctl parse-flow 'actions=autopath(1, NXM_NX_REG0[[]])'], [0],
-  [usable protocols: any
-chosen protocol: OpenFlow10-table_id
-OFPT_FLOW_MOD (xid=0x1): ADD actions=autopath(1,NXM_NX_REG0[[]])
-], [stderr])
-AT_CHECK([ovs-ofctl parse-flow 'actions=autopath(2, NXM_NX_REG0[[2..30]])'], [0],
-  [usable protocols: any
-chosen protocol: OpenFlow10-table_id
-OFPT_FLOW_MOD (xid=0x1): ADD actions=autopath(2,NXM_NX_REG0[[2..30]])
-], [stderr])
-AT_CHECK([[sed 's/^[^|]*|[^|]*|//' stderr]], [0], [dnl
-autopath|WARN|The autopath action is deprecated and may be removed in February 2013.  Please email dev@openvswitch.org with concerns.
-])
-AT_CLEANUP
-
-AT_SETUP([autopath action missing argument])
-AT_CHECK([ovs-ofctl parse-flow actions=autopath], [1], [],
-  [ovs-ofctl: : not enough arguments to autopath action
-])
-AT_CLEANUP
-
-AT_SETUP([autopath action bad port])
-AT_CHECK([ovs-ofctl parse-flow 'actions=autopath(bad, NXM_NX_REG0[[]])'], [1], [],
-  [ovs-ofctl: bad, NXM_NX_REG0[[]]: bad port number
-])
-AT_CLEANUP
-
-AT_SETUP([autopath action destination too narrow])
-AT_CHECK([ovs-ofctl parse-flow 'actions=autopath(1,NXM_NX_REG0[[0..7]])'], [1], [],
-  [ovs-ofctl: 1,NXM_NX_REG0[[0..7]]: 8-bit destination field has 256 possible values, less than required 65536
-])
-AT_CLEANUP
-
index 3d3bd3b..026d49a 100644 (file)
@@ -2,6 +2,7 @@ AT_BANNER([JSON-RPC - Python])
 
 AT_SETUP([JSON-RPC request and successful reply - Python])
 AT_SKIP_IF([test $HAVE_PYTHON = no])
+OVS_RUNDIR=`pwd`; export OVS_RUNDIR
 AT_CHECK([$PYTHON $srcdir/test-jsonrpc.py --detach --pidfile=`pwd`/pid listen punix:socket])
 AT_CHECK([test -s pid])
 AT_CHECK([kill -0 `cat pid`])
@@ -14,6 +15,7 @@ AT_CLEANUP
 
 AT_SETUP([JSON-RPC request and error reply - Python])
 AT_SKIP_IF([test $HAVE_PYTHON = no])
+OVS_RUNDIR=`pwd`; export OVS_RUNDIR
 AT_CHECK([$PYTHON $srcdir/test-jsonrpc.py --detach --pidfile=`pwd`/pid listen punix:socket])
 AT_CHECK([test -s pid])
 AT_CHECK([kill -0 `cat pid`])
@@ -26,6 +28,7 @@ AT_CLEANUP
 
 AT_SETUP([JSON-RPC notification - Python])
 AT_SKIP_IF([test $HAVE_PYTHON = no])
+OVS_RUNDIR=`pwd`; export OVS_RUNDIR
 AT_CHECK([$PYTHON $srcdir/test-jsonrpc.py --detach --pidfile=`pwd`/pid listen punix:socket])
 AT_CHECK([test -s pid])
 # When a daemon dies it deletes its pidfile, so make a copy.
index 2a7f91b..664debe 100644 (file)
@@ -1,6 +1,7 @@
 AT_BANNER([JSON-RPC - C])
 
 AT_SETUP([JSON-RPC request and successful reply])
+OVS_RUNDIR=`pwd`; export OVS_RUNDIR
 AT_CHECK([test-jsonrpc --detach --no-chdir --pidfile="`pwd`"/pid listen punix:socket])
 AT_CHECK([test -s pid])
 AT_CHECK([kill -0 `cat pid`])
@@ -12,6 +13,7 @@ AT_CHECK([kill `cat pid`])
 AT_CLEANUP
 
 AT_SETUP([JSON-RPC request and error reply])
+OVS_RUNDIR=`pwd`; export OVS_RUNDIR
 AT_CHECK([test-jsonrpc --detach --no-chdir --pidfile="`pwd`"/pid listen punix:socket])
 AT_CHECK([test -s pid])
 AT_CHECK([kill -0 `cat pid`])
@@ -23,6 +25,7 @@ AT_CHECK([kill `cat pid`])
 AT_CLEANUP
 
 AT_SETUP([JSON-RPC notification])
+OVS_RUNDIR=`pwd`; export OVS_RUNDIR
 AT_CHECK([test-jsonrpc --detach --no-chdir --pidfile="`pwd`"/pid listen punix:socket])
 AT_CHECK([test -s pid])
 # When a daemon dies it deletes its pidfile, so make a copy.
index 408b1ec..49f3bb1 100644 (file)
@@ -40,7 +40,7 @@ AT_CLEANUP
 AT_SETUP([lacp - multi port config])
 OVS_VSWITCHD_START([dnl
         add-bond br0 bond p1 p2 --\
-        set Port bond lacp=active \
+        set Port bond lacp=active bond-mode=active-backup \
             other_config:lacp-time="fast" \
             other_config:lacp-system-id=11:22:33:44:55:66 \
             other_config:lacp-system-priority=54321 --\
index 800dc14..8f59b63 100644 (file)
@@ -252,6 +252,41 @@ NXST_FLOW reply:
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
+# In this use of a learn action, the first packet in the flow creates
+# a new flow that changes the behavior of subsequent packets in the
+# flow.
+AT_SETUP([learning action - self-modifying flow])
+OVS_VSWITCHD_START
+ADD_OF_PORTS([br0], 1, 2, 3)
+
+# 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']])
+
+# Trace some packets arriving.  The particular packets don't matter.
+for i in 1 2 3 4 5 6 7 8 9 10; do
+    ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'
+done
+
+# Check for the learning entry.
+AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0],
+[[ n_packets=1, n_bytes=60, actions=load:0x3->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
+ priority=65535,vlan_tci=0x0000/0x0fff,dl_src=50:54:00:00:00:05 actions=output:3
+NXST_FLOW reply:
+]])
+
+# Check that the first packet went out port 2 and the rest out port 3.
+AT_CHECK(
+  [(ovs-ofctl dump-ports br0 2; ovs-ofctl dump-ports br0 3) | STRIP_XIDS], [0],
+  [OFPST_PORT reply: 1 ports
+  port  2: rx pkts=0, bytes=0, drop=0, errs=0, frame=0, over=0, crc=0
+           tx pkts=1, bytes=60, drop=0, errs=0, coll=0
+OFPST_PORT reply: 1 ports
+  port  3: rx pkts=0, bytes=0, drop=0, errs=0, frame=0, over=0, crc=0
+           tx pkts=9, bytes=540, drop=0, errs=0, coll=0
+])
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
 AT_SETUP([learning action - fin_timeout feature])
 # This is a totally artificial use of the "learn" action.  The only purpose
 # is to check that specifying fin_idle_timeout or fin_hard_timeout causes
index 55adcfb..650fef3 100644 (file)
@@ -114,7 +114,7 @@ m4_foreach(
    AT_CHECK([test-util testname], [0], [], [])
    AT_CLEANUP])
 
-AT_SETUP([test unix socket -- short pathname])
+AT_SETUP([test unix socket, short pathname - C])
 AT_CHECK([test-unix-socket x])
 AT_CLEANUP
 
@@ -123,22 +123,33 @@ dnl go in a fixed-length field in struct sockaddr_un.  Generally the limit
 dnl is about 100 bytes.  On Linux, we work around this by indirecting through
 dnl a directory fd using /proc/self/fd/<dirfd>.  We do not have a workaround
 dnl for other platforms, so we skip the test there.
-AT_SETUP([test unix socket -- long pathname])
-AT_CHECK([dnl
-    case `uname` in dnl (
-      *[[lL]]inux*)
-        exit 0
-        ;; dnl (
-      *)
-        dnl Magic exit code to tell Autotest to skip this test.
-        exit 77
-        ;;
-    esac
-])
+AT_SETUP([test unix socket, long pathname - C])
+AT_SKIP_IF([test ! -d /proc/self/fd])
+dnl Linux has a 108 byte limit; this is 150 bytes long.
+longname=012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
+mkdir $longname
+cd $longname
+AT_CHECK([test-unix-socket ../$longname/socket socket])
+AT_CLEANUP
+
+AT_SETUP([test unix socket, short pathname - Python])
+AT_SKIP_IF([test $HAVE_PYTHON = no])
+AT_CHECK([$PYTHON $srcdir/test-unix-socket.py x])
+AT_CLEANUP
+
+dnl Unix sockets with long names are problematic because the name has to
+dnl go in a fixed-length field in struct sockaddr_un.  Generally the limit
+dnl is about 100 bytes.  On Linux, we work around this by indirecting through
+dnl a directory fd using /proc/self/fd/<dirfd>.  We do not have a workaround
+dnl for other platforms, so we skip the test there.
+AT_SETUP([test unix socket, long pathname - Python])
+AT_SKIP_IF([test $HAVE_PYTHON = no])
+AT_SKIP_IF([test ! -d /proc/self/fd])
 dnl Linux has a 108 byte limit; this is 150 bytes long.
-mkdir 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
-cd 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
-AT_CHECK([test-unix-socket ../012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789/socket socket])
+longname=012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
+mkdir $longname
+cd $longname
+AT_CHECK([$PYTHON $abs_srcdir/test-unix-socket.py ../$longname/socket socket])
 AT_CLEANUP
 
 AT_SETUP([ovs_assert])
index 687f9c9..dcf7465 100644 (file)
@@ -25,6 +25,11 @@ in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv
 in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=58,tclass=0,hlimit=128,frag=no),icmpv6(type=136,code=0),nd(target=::3,sll=00:05:06:07:08:09,tll=00:0a:0b:0c:0d:0e)
 in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0806),arp(sip=1.2.3.4,tip=5.6.7.8,op=1,sha=00:0f:10:11:12:13,tha=00:14:15:16:17:18)
 skb_mark(0x1234),in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=58,tclass=0,hlimit=128,frag=no),icmpv6(type=136,code=0),nd(target=::3,sll=00:05:06:07:08:09,tll=00:0a:0b:0c:0d:0e)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x8847),mpls(label=100,tc=3,ttl=64,bos=1)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x8847),mpls(label=100,tc=7,ttl=100,bos=1)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x8847),mpls(label=100,tc=7,ttl=100,bos=0)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x8848),mpls(label=1000,tc=4,ttl=200,bos=1)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x8848),mpls(label=1000,tc=4,ttl=200,bos=0)
 ])
 
 (echo '# Valid forms without tun_id or VLAN header.'
@@ -39,6 +44,14 @@ skb_mark(0x1234),in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth
  sed 's/\(eth([[^)]]*)\),*/\1,eth_type(0x8100),vlan(vid=99,pcp=7),encap(/
 s/$/)/' odp-base.txt
 
+ echo
+ echo '# Valid forms with MPLS header.'
+ sed 's/\(eth([[^)]]*),?\)/\1,eth_type(0x8847),mpls(label=100,tc=7,ttl=64,bos=1)/' odp-base.txt
+
+ echo
+ echo '# Valid forms with MPLS multicast header.'
+ sed 's/\(eth([[^)]]*),?\)/\1,eth_type(0x8848),mpls(label=100,tc=7,ttl=64,bos=1)/' odp-base.txt
+
  echo
  echo '# Valid forms with QoS priority.'
  sed 's/^/skb_priority(0x1234),/' odp-base.txt
@@ -76,6 +89,7 @@ userspace(pid=9765,slow_path())
 userspace(pid=9765,slow_path(cfm))
 userspace(pid=9765,slow_path(cfm,match))
 userspace(pid=9123,userdata=0x815309)
+userspace(pid=1234567,userdata(0102030405060708090a0b0c0d0e0f))
 set(tun_id(0x7f10354))
 set(in_port(2))
 set(eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15))
index aa51e08..8a40eb4 100644 (file)
@@ -78,10 +78,6 @@ ffff 0020 00002320 0016 000000000000 fedcba9876543210 ffff0000ffff0000
 # actions=multipath(eth_src,50,modulo_n,1,0,NXM_NX_REG0[])
 ffff 0020 00002320 000a 0000 0032 0000 0000 0000 0000 0000 0000 001f 00010004
 
-# actions=autopath(2,NXM_NX_REG0[2..30])
-& autopath|WARN|The autopath action is deprecated and may be removed in February 2013.  Please email dev@openvswitch.org with concerns.
-ffff 0018 00002320 000b 009c 00010004 00000002 00000000
-
 # actions=bundle(eth_src,0,hrw,ofport,slaves:4,8)
 ffff 0028 00002320 000c 0001 0000 0000 00000002 0002 0000 00000000 00000000 dnl
 0004 0008 00000000
@@ -252,10 +248,6 @@ ffff 0020 00002320 0016 000000000000 fedcba9876543210 ffffffffffffffff ffff 0010
 # actions=multipath(eth_src,50,modulo_n,1,0,NXM_NX_REG0[])
 ffff 0020 00002320 000a 0000 0032 0000 0000 0000 0000 0000 0000 001f 00010004
 
-# actions=autopath(2,NXM_NX_REG0[2..30])
-& autopath|WARN|The autopath action is deprecated and may be removed in February 2013.  Please email dev@openvswitch.org with concerns.
-ffff 0018 00002320 000b 009c 00010004 00000002 00000000
-
 # actions=bundle(eth_src,0,hrw,ofport,slaves:4,8)
 ffff 0028 00002320 000c 0001 0000 0000 00000002 0002 0000 00000000 00000000 dnl
 0004 0008 00000000
index 4021291..2939125 100644 (file)
@@ -1549,9 +1549,9 @@ AT_SETUP([OFPT_ROLE_REPLY - OF1.2])
 AT_KEYWORDS([ofp-print])
 AT_CHECK([ovs-ofctl ofp-print "\
 03 19 00 18 00 00 00 02 00 00 00 03 00 00 00 00 \
-00 00 00 00 00 00 00 00 \
+12 34 56 78 ab cd ef 90 \
 "], [0], [dnl
-OFPT_ROLE_REPLY (OF1.2) (xid=0x2): role=slave
+OFPT_ROLE_REPLY (OF1.2) (xid=0x2): role=slave generation_id=1311768467750121360
 ])
 AT_CLEANUP
 
index 3eec947..8f11b82 100644 (file)
@@ -230,6 +230,12 @@ cookie=0x6 table=4 in_port=83 actions=load:4->NXM_NX_REG3[[]],mod_nw_src:83.83.8
 cookie=0x7 table=5 in_port=84 actions=load:5->NXM_NX_REG4[[]],load:6->NXM_NX_TUN_ID[[]],mod_nw_dst:84.84.84.84,controller,resubmit(85,6)
 cookie=0x8 table=6 in_port=85 actions=mod_tp_src:85,controller,resubmit(86,7)
 cookie=0x9 table=7 in_port=86 actions=mod_tp_dst:86,controller,controller
+cookie=0xa dl_src=40:44:44:44:44:42 actions=push_mpls:0x8847,load:10->OXM_OF_MPLS_LABEL[[]],load:3->OXM_OF_MPLS_TC[[]],controller
+cookie=0xa dl_src=40:44:44:44:44:43 actions=push_mpls:0x8847,load:10->OXM_OF_MPLS_LABEL[[]],load:3->OXM_OF_MPLS_TC[[]],controller
+cookie=0xa dl_src=40:44:44:44:44:44 actions=push_mpls:0x8847,load:10->OXM_OF_MPLS_LABEL[[]],load:3->OXM_OF_MPLS_TC[[]],controller
+cookie=0xb dl_src=50:55:55:55:55:55 dl_type=0x8847 actions=load:1000->OXM_OF_MPLS_LABEL[[]],controller
+cookie=0xd dl_src=60:66:66:66:66:66 actions=pop_mpls:0x0800,controller
+cookie=0xc dl_src=70:77:77:77:77:77 actions=push_mpls:0x8848,load:1000->OXM_OF_MPLS_LABEL[[]],load:7->OXM_OF_MPLS_TC[[]],controller
 ])
 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
 
@@ -290,6 +296,123 @@ OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuf
 tcp,metadata=0,in_port=0,dl_vlan=15,dl_vlan_pcp=0,dl_src=30:33:33:33:33:33,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10 tcp_csum:0
 ])
 
+dnl Modified MPLS controller action.
+AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log])
+
+for i in 1 2 3; do
+    ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:44:42,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no)'
+done
+
+OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+AT_CHECK([cat ofctl_monitor.log], [0], [dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls(label:10,tc:3,ttl:64,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:42,dl_dst=50:54:00:00:00:07
+dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls(label:10,tc:3,ttl:64,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:42,dl_dst=50:54:00:00:00:07
+dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls(label:10,tc:3,ttl:64,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:42,dl_dst=50:54:00:00:00:07
+])
+
+dnl Modified MPLS controller action.
+AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log])
+
+dnl in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x8847),mpls(label=100,tc=3,ttl=64,bos=1)
+
+for i in 1 2 3; do
+    ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:44:43,dst=50:54:00:00:00:07),eth_type(0x8847),mpls(label=11,tc=3,ttl=64,bos=1)'
+done
+
+OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+AT_CHECK([cat ofctl_monitor.log], [0], [dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls(label:10,tc:3,ttl:64,bos:0),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:43,dl_dst=50:54:00:00:00:07
+dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls(label:10,tc:3,ttl:64,bos:0),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:43,dl_dst=50:54:00:00:00:07
+dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls(label:10,tc:3,ttl:64,bos:0),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:43,dl_dst=50:54:00:00:00:07
+])
+
+dnl Modified MPLS controller action.
+AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log])
+
+for i in 1 2 3; do
+    ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:44:44,dst=50:54:00:00:00:07),eth_type(0x8100),vlan(vid=99,pcp=7),encap(eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no))'
+done
+
+OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+AT_CHECK([cat ofctl_monitor.log], [0], [dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls(label:10,tc:3,ttl:64,bos:1),metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=7,dl_src=40:44:44:44:44:44,dl_dst=50:54:00:00:00:07
+dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls(label:10,tc:3,ttl:64,bos:1),metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=7,dl_src=40:44:44:44:44:44,dl_dst=50:54:00:00:00:07
+dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls(label:10,tc:3,ttl:64,bos:1),metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=7,dl_src=40:44:44:44:44:44,dl_dst=50:54:00:00:00:07
+])
+
+dnl Modified MPLS actions.
+AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log])
+
+for i in 1 2 3; do
+    ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:55:55:55:55:55,dst=50:54:00:00:00:07),eth_type(0x8847),mpls(label=100,tc=7,ttl=64,bos=1),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no)'
+done
+
+OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+AT_CHECK([cat ofctl_monitor.log], [0], [dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xb total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
+mpls(label:1000,tc:7,ttl:64,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:55:55:55:55:55,dl_dst=50:54:00:00:00:07
+dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xb total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
+mpls(label:1000,tc:7,ttl:64,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:55:55:55:55:55,dl_dst=50:54:00:00:00:07
+dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xb total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
+mpls(label:1000,tc:7,ttl:64,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:55:55:55:55:55,dl_dst=50:54:00:00:00:07
+])
+
+dnl Modified MPLS ipv6 controller action.
+AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log])
+
+for i in 1 2 3; do
+    ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=70:77:77:77:77:77,dst=50:54:00:00:00:07),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=10,tclass=0x70,hlimit=128,frag=no)'
+done
+
+OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+AT_CHECK([cat ofctl_monitor.log], [0], [dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xc total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mplsm(label:1000,tc:7,ttl:64,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=70:77:77:77:77:77,dl_dst=50:54:00:00:00:07
+dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xc total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mplsm(label:1000,tc:7,ttl:64,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=70:77:77:77:77:77,dl_dst=50:54:00:00:00:07
+dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xc total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mplsm(label:1000,tc:7,ttl:64,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=70:77:77:77:77:77,dl_dst=50:54:00:00:00:07
+])
+
+
+dnl Modified MPLS pop action.
+AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log])
+
+for i in 1 2 3; do
+    ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=60:66:66:66:66:66,dst=50:54:00:00:00:07),eth_type(0x8847),mpls(label=10,tc=3,ttl=100,bos=1),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no)'
+done
+
+OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+AT_CHECK([cat ofctl_monitor.log], [0], [dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=56 in_port=1 (via action) data_len=56 (unbuffered)
+tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:66:66,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64 tcp_csum:0
+dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=56 in_port=1 (via action) data_len=56 (unbuffered)
+tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:66:66,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64 tcp_csum:0
+dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=56 in_port=1 (via action) data_len=56 (unbuffered)
+tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:66:66,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64 tcp_csum:0
+])
+
 dnl Checksum TCP.
 AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --no-chdir --pidfile 2> ofctl_monitor.log])
 
@@ -374,6 +497,12 @@ AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
  cookie=0x7, table=5, n_packets=2, n_bytes=120, in_port=84 actions=load:0x5->NXM_NX_REG4[[]],load:0x6->NXM_NX_TUN_ID[[]],mod_nw_dst:84.84.84.84,CONTROLLER:65535,resubmit(85,6)
  cookie=0x8, table=6, n_packets=2, n_bytes=120, in_port=85 actions=mod_tp_src:85,CONTROLLER:65535,resubmit(86,7)
  cookie=0x9, table=7, n_packets=2, n_bytes=120, in_port=86 actions=mod_tp_dst:86,CONTROLLER:65535,CONTROLLER:65535
+ cookie=0xa, n_packets=3, n_bytes=180, dl_src=40:44:44:44:44:42 actions=push_mpls:0x8847,load:0xa->OXM_OF_MPLS_LABEL[[]],load:0x3->OXM_OF_MPLS_TC[[]],CONTROLLER:65535
+ cookie=0xa, n_packets=3, n_bytes=180, dl_src=40:44:44:44:44:43 actions=push_mpls:0x8847,load:0xa->OXM_OF_MPLS_LABEL[[]],load:0x3->OXM_OF_MPLS_TC[[]],CONTROLLER:65535
+ cookie=0xa, n_packets=3, n_bytes=180, dl_src=40:44:44:44:44:44 actions=push_mpls:0x8847,load:0xa->OXM_OF_MPLS_LABEL[[]],load:0x3->OXM_OF_MPLS_TC[[]],CONTROLLER:65535
+ cookie=0xb, n_packets=3, n_bytes=180, dl_src=50:55:55:55:55:55,dl_type=0x8847 actions=load:0x3e8->OXM_OF_MPLS_LABEL[[]],CONTROLLER:65535
+ cookie=0xc, n_packets=3, n_bytes=180, dl_src=70:77:77:77:77:77 actions=push_mpls:0x8848,load:0x3e8->OXM_OF_MPLS_LABEL[[]],load:0x7->OXM_OF_MPLS_TC[[]],CONTROLLER:65535
+ cookie=0xd, n_packets=3, n_bytes=180, dl_src=60:66:66:66:66:66 actions=pop_mpls:0x0800,CONTROLLER:65535
  n_packets=3, n_bytes=180, dl_src=10:11:11:11:11:11 actions=CONTROLLER:65535
 NXST_FLOW reply:
 ])
@@ -1010,7 +1139,7 @@ ovs-vsctl \
    --id=@nf create NetFlow targets=\"127.0.0.1:$NETFLOW_PORT\" \
      engine_id=1 engine_type=2 active_timeout=10 add-id-to-interface=false
 
-ON_EXIT([kill `test-netflow.pid`])
+ON_EXIT([kill `cat test-netflow.pid`])
 AT_CHECK([test-netflow --detach --no-chdir --pidfile $NETFLOW_PORT:127.0.0.1 > netflow.log])AT_CAPTURE_FILE([netflow.log])
 
 AT_CHECK([ovs-appctl time/stop])
index b9356d3..9a6d5ab 100644 (file)
@@ -64,8 +64,26 @@ m4_define([OVS_VSWITCHD_START],
    AT_CHECK([ovs-vsctl -- add-br br0 -- set bridge br0 datapath-type=dummy other-config:datapath-id=fedcba9876543210 other-config:hwaddr=aa:55:aa:55:00:00 protocols=[[OpenFlow10,OpenFlow12,OpenFlow13]] fail-mode=secure -- $1 m4_if([$2], [], [], [| perl $srcdir/uuidfilt.pl])], [0], [$2])
 ])
 
+m4_divert_push([PREPARE_TESTS])
+check_logs () {
+    sed -n "$1
+/|WARN|/p
+/|ERR|/p
+/|EMER|/p" ovs-vswitchd.log ovsdb-server.log
+}
+m4_divert_pop([PREPARE_TESTS])
+
+# OVS_VSWITCHD_STOP([WHITELIST])
+#
+# Gracefully stops ovs-vswitchd and ovsdb-server, checking their log files
+# for messages with severity WARN or higher and signaling an error if any
+# is present.  The optional WHITELIST may contain shell-quoted "sed"
+# commands to delete any warnings that are actually expected, e.g.:
+#
+#   OVS_VSWITCHD_STOP(["/expected error/d"])
 m4_define([OVS_VSWITCHD_STOP],
-  [AT_CHECK([ovs-appctl -t ovs-vswitchd exit])
+  [AT_CHECK([check_logs $1])
+   AT_CHECK([ovs-appctl -t ovs-vswitchd exit])
    AT_CHECK([ovs-appctl -t ovsdb-server exit])])
 
 # ADD_OF_PORTS(BRIDGE, OF_PORT[, OF_PORT...])
index 45aa549..f41bfc3 100644 (file)
@@ -1332,7 +1332,7 @@ echo >>expout "OFPT_ROLE_REPLY (OF1.2) (xid=0x2): role=equal"
 # Become slave (generation_id is initially undefined, so 2^63+2 should not be stale)
 ovs-appctl -t ovs-ofctl ofctl/send 031800180000000300000003000000008000000000000002
 echo >>expout "send: OFPT_ROLE_REQUEST (OF1.2) (xid=0x3): role=slave generation_id=9223372036854775810"
-echo >>expout "OFPT_ROLE_REPLY (OF1.2) (xid=0x3): role=slave"
+echo >>expout "OFPT_ROLE_REPLY (OF1.2) (xid=0x3): role=slave generation_id=9223372036854775810"
 
 # Try to become the master using a stale generation ID
 ovs-appctl -t ovs-ofctl ofctl/send 031800180000000400000002000000000000000000000002
@@ -1343,7 +1343,7 @@ echo >>expout "OFPT_ROLE_REQUEST (OF1.2) (xid=0x4): role=master generation_id=2"
 # Become master using a valid generation ID
 ovs-appctl -t ovs-ofctl ofctl/send 031800180000000500000002000000000000000000000001
 echo >>expout "send: OFPT_ROLE_REQUEST (OF1.2) (xid=0x5): role=master generation_id=1"
-echo >>expout "OFPT_ROLE_REPLY (OF1.2) (xid=0x5): role=master"
+echo >>expout "OFPT_ROLE_REPLY (OF1.2) (xid=0x5): role=master generation_id=1"
 ovs-appctl -t ovs-ofctl ofctl/barrier
 echo >>expout "OFPT_BARRIER_REPLY (OF1.2) (xid=0x3):"
 
index ca68226..7395fd1 100644 (file)
@@ -243,7 +243,6 @@ tun_id=0x1234,cookie=0x5678,actions=flood
 actions=drop
 reg0=123,actions=move:NXM_NX_REG0[0..5]->NXM_NX_REG1[26..31],load:55->NXM_NX_REG2[0..31],move:NXM_NX_REG0[0..31]->NXM_NX_TUN_ID[0..31],move:NXM_NX_REG0[0..15]->NXM_OF_VLAN_TCI[]
 actions=move:OXM_OF_ETH_DST[]->OXM_OF_ETH_SRC[]
-actions=autopath(5,NXM_NX_REG0[])
 vlan_tci=0x1123/0x1fff,actions=drop
 ]])
 AT_CHECK([ovs-ofctl -F nxm -mmm parse-flows flows.txt], [0], [stdout], [stderr])
@@ -272,12 +271,8 @@ NXT_FLOW_MOD: ADD NXM_NX_TUN_ID(0000000000001234) cookie:0x5678 actions=FLOOD
 NXT_FLOW_MOD: ADD <any> actions=drop
 NXT_FLOW_MOD: ADD NXM_NX_REG0(0000007b) actions=move:NXM_NX_REG0[0..5]->NXM_NX_REG1[26..31],load:0x37->NXM_NX_REG2[],move:NXM_NX_REG0[]->NXM_NX_TUN_ID[0..31],move:NXM_NX_REG0[0..15]->NXM_OF_VLAN_TCI[]
 NXT_FLOW_MOD: ADD <any> actions=move:NXM_OF_ETH_DST[]->NXM_OF_ETH_SRC[]
-NXT_FLOW_MOD: ADD <any> actions=autopath(5,NXM_NX_REG0[])
 NXT_FLOW_MOD: ADD NXM_OF_VLAN_TCI_W(1123/1fff) actions=drop
 ]])
-AT_CHECK([[sed 's/^[^|]*|[^|]*|//' stderr]], [0], [dnl
-autopath|WARN|The autopath action is deprecated and may be removed in February 2013.  Please email dev@openvswitch.org with concerns.
-])
 AT_CLEANUP
 
 AT_SETUP([ovs-ofctl parse-nx-match])
index 6a3b5d1..eec2a04 100644 (file)
@@ -138,6 +138,7 @@ m4_divert_pop([PREPARE_TESTS])
 m4_define([OVSDB_CHECK_EXECUTION],
   [AT_SETUP([$1])
    AT_KEYWORDS([ovsdb execute execution positive $5])
+   OVS_RUNDIR=`pwd`; export OVS_RUNDIR
    AT_CHECK([test-ovsdb execute "`$2`" m4_foreach([txn], [$3], [ 'txn'])],
      [0], [stdout], [])
    AT_CHECK([perl $srcdir/uuidfilt.pl stdout], [0], [$4])
index ce22010..3c32e2f 100644 (file)
@@ -1,5 +1,6 @@
 AT_BANNER([OVSDB -- interface description language (IDL)])
 
+OVS_RUNDIR=`pwd`; export OVS_RUNDIR
 # OVSDB_CHECK_IDL_C(TITLE, [PRE-IDL-TXN], TRANSACTIONS, OUTPUT, [KEYWORDS],
 #                   [FILTER])
 #
@@ -19,6 +20,7 @@ AT_BANNER([OVSDB -- interface description language (IDL)])
 m4_define([OVSDB_CHECK_IDL_C],
   [AT_SETUP([$1 - C])
    AT_KEYWORDS([ovsdb server idl positive $5])
+   OVS_RUNDIR=`pwd`; export OVS_RUNDIR
    AT_CHECK([ovsdb-tool create db $abs_srcdir/idltest.ovsschema],
                   [0], [stdout], [ignore])
    AT_CHECK([ovsdb-server '-vPATTERN:console:ovsdb-server|%c|%m' --detach --no-chdir --pidfile="`pwd`"/pid --remote=punix:socket --unixctl="`pwd`"/unixctl db], [0], [ignore], [ignore])
@@ -36,6 +38,7 @@ m4_define([OVSDB_CHECK_IDL_PY],
   [AT_SETUP([$1 - Python])
    AT_SKIP_IF([test $HAVE_PYTHON = no])
    AT_KEYWORDS([ovsdb server idl positive Python $5])
+   OVS_RUNDIR=`pwd`; export OVS_RUNDIR
    AT_CHECK([ovsdb-tool create db $abs_srcdir/idltest.ovsschema],
                   [0], [stdout], [ignore])
    AT_CHECK([ovsdb-server '-vPATTERN:console:ovsdb-server|%c|%m' --detach --no-chdir --pidfile="`pwd`"/pid --remote=punix:socket --unixctl="`pwd`"/unixctl db], [0], [ignore], [ignore])
@@ -53,6 +56,7 @@ m4_define([OVSDB_CHECK_IDL_TCP_PY],
   [AT_SETUP([$1 - Python tcp])
    AT_SKIP_IF([test $HAVE_PYTHON = no])
    AT_KEYWORDS([ovsdb server idl positive Python with tcp socket $5])
+   OVS_RUNDIR=`pwd`; export OVS_RUNDIR
    AT_CHECK([ovsdb-tool create db $abs_srcdir/idltest.ovsschema],
                   [0], [stdout], [ignore])
    AT_CHECK([perl $srcdir/choose-port.pl], [0], [stdout])
index c1aa619..2aa752b 100644 (file)
@@ -2,7 +2,8 @@ dnl OVSDB_INIT([$1])
 dnl
 dnl Creates an empty database named $1.
 m4_define([OVSDB_INIT],
-  [AT_CHECK(
+  [OVS_RUNDIR=`pwd`; export OVS_RUNDIR
+   AT_CHECK(
      [ovsdb-tool create $1 $abs_top_srcdir/vswitchd/vswitch.ovsschema],
      [0], [stdout], [ignore])
    AT_CHECK(
index 167b44c..aff5854 100644 (file)
@@ -19,6 +19,7 @@ AT_BANNER([OVSDB -- ovsdb-server monitors])
 m4_define([OVSDB_CHECK_MONITOR], 
   [AT_SETUP([$1])
    AT_KEYWORDS([ovsdb server monitor positive $9])
+   OVS_RUNDIR=`pwd`; export OVS_RUNDIR
    $2 > schema
    AT_CHECK([ovsdb-tool create db schema], [0], [stdout], [ignore])
    m4_foreach([txn], [$3],
index 6dcf2f5..62eae38 100644 (file)
@@ -21,6 +21,7 @@ m4_define([OVSDB_SERVER_SHUTDOWN],
 # TITLE is provided to AT_SETUP and KEYWORDS to AT_KEYWORDS.
 m4_define([OVSDB_CHECK_EXECUTION], 
   [AT_SETUP([$1])
+  OVS_RUNDIR=`pwd`; export OVS_RUNDIR
    AT_KEYWORDS([ovsdb server positive unix $5])
    $2 > schema
    AT_CHECK([ovsdb-tool create db schema], [0], [stdout], [ignore])
@@ -39,6 +40,7 @@ EXECUTION_EXAMPLES
 \f
 AT_SETUP([truncating corrupted database log])
 AT_KEYWORDS([ovsdb server positive unix])
+OVS_RUNDIR=`pwd`; export OVS_RUNDIR
 ordinal_schema > schema
 AT_CHECK([ovsdb-tool create db schema], [0], [stdout], [ignore])
 dnl Do one transaction and save the output.
@@ -85,6 +87,7 @@ AT_CLEANUP
 
 AT_SETUP([truncating database log with bad transaction])
 AT_KEYWORDS([ovsdb server positive unix])
+OVS_RUNDIR=`pwd`; export OVS_RUNDIR
 ordinal_schema > schema
 AT_CHECK([ovsdb-tool create db schema], [0], [stdout], [ignore])
 dnl Do one transaction and save the output.
@@ -132,6 +135,7 @@ AT_CLEANUP
 
 AT_SETUP([ovsdb-client get-schema-version])
 AT_KEYWORDS([ovsdb server positive])
+OVS_RUNDIR=`pwd`; export OVS_RUNDIR
 ordinal_schema > schema
 AT_CHECK([ovsdb-tool create db schema], [0], [ignore], [ignore])
 AT_CHECK([ovsdb-server --detach --no-chdir --pidfile="`pwd`"/pid --unixctl="`pwd`"/unixctl --remote=punix:socket db], [0], [ignore], [ignore])
@@ -142,6 +146,7 @@ AT_CLEANUP
 
 AT_SETUP([database multiplexing implementation])
 AT_KEYWORDS([ovsdb server positive])
+OVS_RUNDIR=`pwd`; export OVS_RUNDIR
 ordinal_schema > schema1
 constraint_schema > schema2
 AT_CHECK([ovsdb-tool create db1 schema1], [0], [ignore], [ignore])
@@ -280,6 +285,7 @@ AT_CLEANUP
 
 AT_SETUP([compacting online])
 AT_KEYWORDS([ovsdb server compact])
+OVS_RUNDIR=`pwd`; export OVS_RUNDIR
 ordinal_schema > schema
 dnl Make sure that "ovsdb-tool create" works with a dangling symlink for
 dnl the database and the lockfile, creating the target of each symlink rather
@@ -430,6 +436,7 @@ m4_define([OVSDB_CHECK_EXECUTION],
   [AT_SETUP([$1])
    AT_KEYWORDS([ovsdb server positive ssl $5])
    AT_SKIP_IF([test "$HAVE_OPENSSL" = no])
+   OVS_RUNDIR=`pwd`; export OVS_RUNDIR
    $2 > schema
    AT_CHECK([perl $srcdir/choose-port.pl], [0], [stdout])
    SSL_PORT=`cat stdout`
@@ -479,6 +486,7 @@ AT_CLEANUP])
 m4_define([OVSDB_CHECK_EXECUTION],
   [AT_SETUP([$1])
    AT_KEYWORDS([ovsdb server positive tcp $5])
+   OVS_RUNDIR=`pwd`; export OVS_RUNDIR
    $2 > schema
    AT_CHECK([perl $srcdir/choose-port.pl], [0], [stdout])
    TCP_PORT=`cat stdout`
@@ -519,6 +527,7 @@ AT_BANNER([OVSDB -- transactions on transient ovsdb-server])
 m4_define([OVSDB_CHECK_EXECUTION], 
   [AT_SETUP([$1])
    AT_KEYWORDS([ovsdb server positive transient $5])
+   OVS_RUNDIR=`pwd`; export OVS_RUNDIR
    $2 > schema
    AT_CHECK([ovsdb-tool create db schema], [0], [stdout], [ignore])
    m4_foreach([txn], [$3], 
index e4f4a29..286d700 100644 (file)
@@ -16,6 +16,7 @@ AT_BANNER([OVSDB -- ovsdb-tool])
 m4_define([OVSDB_CHECK_EXECUTION], 
   [AT_SETUP([$1])
    AT_KEYWORDS([ovsdb file positive $5])
+   OVS_RUNDIR=`pwd`; export OVS_RUNDIR
    $2 > schema
    touch .db.~lock~
    AT_CHECK([ovsdb-tool create db schema], [0], [stdout], [ignore])
@@ -48,6 +49,7 @@ AT_CLEANUP
 
 AT_SETUP([ovsdb-tool compact])
 AT_KEYWORDS([ovsdb file positive])
+OVS_RUNDIR=`pwd`; export OVS_RUNDIR
 ordinal_schema > schema
 dnl Make sure that "ovsdb-tool create" works with a dangling symlink,
 dnl creating the target of the symlink rather than replacing the symlink
@@ -155,6 +157,7 @@ AT_CLEANUP
 
 AT_SETUP([ovsdb-tool convert -- removing a column])
 AT_KEYWORDS([ovsdb file positive])
+OVS_RUNDIR=`pwd`; export OVS_RUNDIR
 ordinal_schema > schema
 AT_DATA([new-schema], 
   [[{"name": "ordinals",
@@ -218,6 +221,7 @@ AT_CLEANUP
 
 AT_SETUP([ovsdb-tool convert -- adding a column])
 AT_KEYWORDS([ovsdb file positive])
+OVS_RUNDIR=`pwd`; export OVS_RUNDIR
 AT_DATA([schema], 
   [[{"name": "ordinals",
      "tables": {
index aa8b6f0..f5b24b4 100644 (file)
@@ -137,6 +137,7 @@ main(int argc, char *argv[])
     for (i = 0; i < N_FLOWS; i++) {
         random_bytes(&flows[i], sizeof flows[i]);
         memset(flows[i].zeros, 0, sizeof flows[i].zeros);
+        flows[i].mpls_depth = 0;
         flows[i].regs[0] = OFPP_NONE;
     }
 
index b1461ff..18dee86 100644 (file)
@@ -463,6 +463,8 @@ check_tables(const struct classifier *cls,
 
     HMAP_FOR_EACH (table, hmap_node, &cls->tables) {
         const struct cls_rule *head;
+        unsigned int max_priority = 0;
+        unsigned int max_count = 0;
 
         assert(!hmap_is_empty(&table->rules));
 
@@ -471,15 +473,26 @@ check_tables(const struct classifier *cls,
             unsigned int prev_priority = UINT_MAX;
             const struct cls_rule *rule;
 
+            if (head->priority > max_priority) {
+                max_priority = head->priority;
+                max_count = 1;
+            } else if (head->priority == max_priority) {
+                ++max_count;
+            }
+
             found_rules++;
             LIST_FOR_EACH (rule, list, &head->list) {
                 assert(rule->priority < prev_priority);
+                assert(rule->priority <= table->max_priority);
+
                 prev_priority = rule->priority;
                 found_rules++;
                 found_dups++;
                 assert(classifier_find_rule_exactly(cls, rule) == rule);
             }
         }
+        assert(table->max_priority == max_priority);
+        assert(table->max_count == max_count);
     }
 
     assert(found_tables == hmap_count(&cls->tables));
index b990c13..8442bc2 100644 (file)
@@ -61,6 +61,7 @@ main(int argc, char *argv[])
 
             random_bytes(&flow, sizeof flow);
             memset(flow.zeros, 0, sizeof flow.zeros);
+            flow.mpls_depth = 0;
 
             mp.max_link = n - 1;
             multipath_execute(&mp, &flow);
index 5ed31a9..268a105 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2011, 2012, 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.
@@ -32,7 +32,7 @@ parse_keys(void)
     struct ds in;
 
     ds_init(&in);
-    vlog_set_levels_from_string("odp_util:console:dbg");
+    vlog_set_levels_from_string_assert("odp_util:console:dbg");
     while (!ds_get_test_line(&in, stdin)) {
         enum odp_key_fitness fitness;
         struct ofpbuf odp_key;
@@ -98,7 +98,7 @@ parse_actions(void)
     struct ds in;
 
     ds_init(&in);
-    vlog_set_levels_from_string("odp_util:console:dbg");
+    vlog_set_levels_from_string_assert("odp_util:console:dbg");
     while (!ds_get_test_line(&in, stdin)) {
         struct ofpbuf odp_actions;
         struct ds out;
diff --git a/tests/test-unix-socket.py b/tests/test-unix-socket.py
new file mode 100644 (file)
index 0000000..5a3f3c0
--- /dev/null
@@ -0,0 +1,54 @@
+#
+# Copyright (c) 2010, 2012, 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.
+# 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.
+
+import os
+import signal
+import socket
+import sys
+
+import ovs.socket_util
+
+def main(argv):
+    if len(argv) not in (2, 3):
+        sys.stderr.write("usage: %s SOCKETNAME1 [SOCKETNAME2]", argv[0])
+        sys.exit(1)
+
+    sockname1 = argv[1]
+    if len(argv) > 2:
+        sockname2 = argv[2]
+    else:
+        sockname2 = sockname1
+
+    signal.signal(signal.SIGALRM, signal.SIG_DFL)
+    signal.alarm(5)
+
+    # Create a listening socket under name 'sockname1'.
+    error, sock1 = ovs.socket_util.make_unix_socket(socket.SOCK_STREAM, False,
+                                                    sockname1, None)
+    if error:
+        sys.stderr.write("%s: bind failed (%s)" % (sockname1,
+                                                   os.strerror(error)))
+    sock1.listen(1)
+
+    # Connect to 'sockname2' (which should be the same file, perhaps under a
+    # different name).
+    error, sock2 = ovs.socket_util.make_unix_socket(socket.SOCK_STREAM, False,
+                                                    None, sockname2)
+    if error:
+        sys.stderr.write("%s: connect failed (%s)" % (sockname2,
+                                                      os.strerror(error)))
+
+if __name__ == '__main__':
+    main(sys.argv)
index fa80c4d..97bc247 100644 (file)
@@ -82,7 +82,6 @@ m4_include([tests/ofp-errors.at])
 m4_include([tests/ovs-ofctl.at])
 m4_include([tests/odp.at])
 m4_include([tests/multipath.at])
-m4_include([tests/autopath.at])
 m4_include([tests/learn.at])
 m4_include([tests/vconn.at])
 m4_include([tests/file_name.at])
index c708b30..55fd5b3 100644 (file)
@@ -64,7 +64,7 @@ Invalid flow
 ovs-appctl: ovs-vswitchd: server returned an error
 ])
 
-OVS_VSWITCHD_STOP
+OVS_VSWITCHD_STOP(["/receive tunnel port not found/d"])
 AT_CLEANUP
 
 AT_SETUP([tunnel - ECN decapsulation])
@@ -256,7 +256,7 @@ AT_CHECK([ovs-appctl ofproto/trace br0 'tunnel(tun_id=0xf,src=1.1.1.1,dst=2.2.2.
 Invalid flow
 ovs-appctl: ovs-vswitchd: server returned an error
 ])
-OVS_VSWITCHD_STOP
+OVS_VSWITCHD_STOP(["/receive tunnel port not found/d"])
 AT_CLEANUP
 
 AT_SETUP([tunnel - key match])
index ae095b0..359f97a 100644 (file)
@@ -11,6 +11,7 @@ m4_define([TEST_VCONN_CLASS],
       [send-short-hello],
       [send-invalid-version-hello]],
      [AT_SETUP([$1 vconn - m4_bpatsubst(testname, [-], [ ])])
+     OVS_RUNDIR=`pwd`; export OVS_RUNDIR
       m4_if([$1], [ssl], [
         AT_SKIP_IF([test "$HAVE_OPENSSL" = no])
         AT_CHECK([cp $abs_top_builddir/tests/testpki*.pem .])])
index a1e653b..b528dba 100644 (file)
@@ -23,9 +23,6 @@ system and places it in \fB/var/log/ovs-bugtool\fR.
 .IP "\fB\-\-all\fR"
 Use all available capabilities.
 .
-.IP "\fB\-\-ovs\fR"
-Use only Open vSwitch relevant capabilities.
-.
 .IP "\fB\-\-capabilities\fR"
 List \fBovs\-bugtool\fR capabilities.
 .
@@ -35,10 +32,18 @@ Print verbose debugging output.
 .IP "\fB\-\-entries=\fIlist\fR"
 Use the capabilities specified in a comma-separated list.
 .
+.IP "\fB\-\-log\-days=\fIdays\fR"
+Include the logs rotated in the previous \fIdays\fR days in the debug bundle.
+The number of log files included has a big impact on the eventual bundle size.
+The default value is 20 days.
+.
 .IP "\fB\-\-output=\fIfiletype\fR"
 Generate a debug bundle with the specified file type.  Options include
 \fBtar\fR, \fBtar.gz\fR, \fBtar.bz2\fR, and \fBzip\fR.
 .
+.IP "\fB\-\-ovs\fR"
+Use only Open vSwitch relevant capabilities.
+.
 .IP "\fB\-\-silent\fR"
 Suppress output.
 .
index f91a3b3..c5a4366 100755 (executable)
@@ -76,8 +76,6 @@ FSTAB = '/etc/fstab'
 PROC_MOUNTS = '/proc/mounts'
 ISCSI_CONF = '/etc/iscsi/iscsid.conf'
 ISCSI_INITIATOR = '/etc/iscsi/initiatorname.iscsi'
-LVM_CACHE = '/etc/lvm/cache/.cache'
-LVM_CONFIG = '/etc/lvm/lvm.conf'
 PROC_CPUINFO = '/proc/cpuinfo'
 PROC_MEMINFO = '/proc/meminfo'
 PROC_IOPORTS = '/proc/ioports'
@@ -90,7 +88,6 @@ PROC_FILESYSTEMS = '/proc/filesystems'
 PROC_CMDLINE = '/proc/cmdline'
 PROC_CONFIG = '/proc/config.gz'
 PROC_USB_DEV = '/proc/bus/usb/devices'
-PROC_XEN_BALLOON = '/proc/xen/balloon'
 PROC_NET_BONDING_DIR = '/proc/net/bonding'
 IFCFG_RE = re.compile(r'^.*/ifcfg-.*')
 ROUTE_RE = re.compile(r'^.*/route-.*')
@@ -117,17 +114,10 @@ OPENVSWITCH_SYSCONFIG_SWITCH = '/etc/sysconfig/openvswitch'    # RHEL
 OPENVSWITCH_DEFAULT_CONTROLLER = '/etc/default/openvswitch-controller'
 OPENVSWITCH_CONF_DB = '@DBDIR@/conf.db'
 OPENVSWITCH_VSWITCHD_PID = '@RUNDIR@/ovs-vswitchd.pid'
-COLLECTD_LOGS_DIR = '/var/lib/collectd/rrd'
 VAR_LOG_DIR = '/var/log/'
 VAR_LOG_CORE_DIR = '/var/log/core'
-X11_LOGS_DIR = VAR_LOG_DIR
-X11_LOGS_RE = re.compile(r'.*/Xorg\..*$')
-X11_AUTH_DIR = '/root/'
-X11_AUTH_RE = re.compile(r'.*/\.((Xauthority)|(serverauth\.[0-9]*))$')
 YUM_LOG = '/var/log/yum.log'
 YUM_REPOS_DIR = '/etc/yum.repos.d'
-PAM_DIR = '/etc/pam.d'
-KRB5_CONF = '/etc/krb5.conf'
 
 #
 # External programs
@@ -145,15 +135,12 @@ DPKG_QUERY = 'dpkg-query'
 ETHTOOL = 'ethtool'
 FDISK = 'fdisk'
 FIND = 'find'
-HDPARM = 'hdparm'
 IFCONFIG = 'ifconfig'
 IPTABLES = 'iptables'
 ISCSIADM = 'iscsiadm'
 LOSETUP = 'losetup'
 LS = 'ls'
 LSPCI = 'lspci'
-LVDISPLAY = 'lvdisplay'
-LVS = 'lvs'
 MD5SUM = 'md5sum'
 MODINFO = 'modinfo'
 MPPUTIL = 'mppUtil'
@@ -164,15 +151,12 @@ OVS_OFCTL = 'ovs-ofctl'
 OVS_VSCTL = 'ovs-vsctl'
 OVS_APPCTL = 'ovs-appctl'
 PS = 'ps'
-PVS = 'pvs'
 ROUTE = 'route'
 RPM = 'rpm'
 SG_MAP = 'sg_map'
 SYSCTL = 'sysctl'
 TC = 'tc'
 UPTIME = 'uptime'
-VGS = 'vgs'
-VGSCAN = 'vgscan'
 ZCAT = 'zcat'
 
 #
@@ -214,29 +198,18 @@ CAP_XML_ROOT = "system-status-capabilities"
 CAP_XML_ELEMENT = 'capability'
 
 
-CAP_BLOBS                = 'blobs'
 CAP_BOOT_LOADER          = 'boot-loader'
-CAP_COLLECTD_LOGS        = 'collectd-logs'
 CAP_DISK_INFO            = 'disk-info'
-CAP_FIRSTBOOT            = 'firstboot'
 CAP_HARDWARE_INFO        = 'hardware-info'
-CAP_HDPARM_T             = 'hdparm-t'
-CAP_HIGH_AVAILABILITY    = 'high-availability'
 CAP_KERNEL_INFO          = 'kernel-info'
 CAP_LOSETUP_A            = 'loopback-devices'
 CAP_MULTIPATH            = 'multipath'
 CAP_NETWORK_CONFIG       = 'network-config'
 CAP_NETWORK_STATUS       = 'network-status'
-CAP_OEM                  = 'oem'
-CAP_PAM                  = 'pam'
+CAP_OPENVSWITCH_LOGS    = 'ovs-system-logs'
 CAP_PROCESS_LIST         = 'process-list'
-CAP_PERSISTENT_STATS     = 'persistent-stats'
 CAP_SYSTEM_LOGS          = 'system-logs'
 CAP_SYSTEM_SERVICES      = 'system-services'
-CAP_VNCTERM              = 'vncterm'
-CAP_WLB                  = 'wlb'
-CAP_X11_LOGS             = 'X11'
-CAP_X11_AUTH             = 'X11-auth'
 CAP_YUM                  = 'yum'
 
 KB = 1024
@@ -246,6 +219,8 @@ caps = {}
 cap_sizes = {}
 unlimited_data = False
 dbg = False
+# Default value for the number of rotated logs.
+log_days = 20
 
 def cap(key, pii=PII_MAYBE, min_size=-1, max_size=-1, min_time=-1,
         max_time=-1, mime=MIME_TEXT, checked=True, hidden=False):
@@ -254,19 +229,12 @@ def cap(key, pii=PII_MAYBE, min_size=-1, max_size=-1, min_time=-1,
     cap_sizes[key] = 0
 
 
-cap(CAP_BLOBS,               PII_NO,                    max_size=5*MB)
 cap(CAP_BOOT_LOADER,         PII_NO,                    max_size=3*KB,
     max_time=5)
-cap(CAP_COLLECTD_LOGS,       PII_MAYBE,                 max_size=50*MB,
-    max_time=5)
 cap(CAP_DISK_INFO,           PII_MAYBE,                 max_size=50*KB,
     max_time=20)
-cap(CAP_FIRSTBOOT,           PII_YES,   min_size=60*KB, max_size=80*KB)
 cap(CAP_HARDWARE_INFO,       PII_MAYBE,                 max_size=30*KB,
     max_time=20)
-cap(CAP_HDPARM_T,            PII_NO,    min_size=0,     max_size=5*KB,
-    min_time=20, max_time=90, checked=False, hidden=True)
-cap(CAP_HIGH_AVAILABILITY,   PII_MAYBE,                 max_size=5*MB)
 cap(CAP_KERNEL_INFO,         PII_MAYBE,                 max_size=120*KB,
     max_time=5)
 cap(CAP_LOSETUP_A,           PII_MAYBE,                 max_size=KB, max_time=5)
@@ -274,22 +242,16 @@ cap(CAP_MULTIPATH,           PII_MAYBE,                 max_size=20*KB,
     max_time=10)
 cap(CAP_NETWORK_CONFIG,      PII_IF_CUSTOMIZED,
                                         min_size=0,     max_size=40*KB)
-cap(CAP_NETWORK_STATUS,      PII_YES,                   max_size=50*KB,
+cap(CAP_NETWORK_STATUS,      PII_YES,                   max_size=50*MB,
     max_time=30)
-cap(CAP_PAM,                 PII_NO,                    max_size=50*KB)
-cap(CAP_PERSISTENT_STATS,    PII_MAYBE,                 max_size=50*MB,
-    max_time=60)
+cap(CAP_OPENVSWITCH_LOGS,    PII_MAYBE,                 max_size=-1,
+    max_time=5)
 cap(CAP_PROCESS_LIST,        PII_YES,                   max_size=30*KB,
     max_time=20)
-cap(CAP_SYSTEM_LOGS,         PII_MAYBE,                 max_size=50*MB,
+cap(CAP_SYSTEM_LOGS,         PII_MAYBE,                 max_size=200*MB,
     max_time=5)
 cap(CAP_SYSTEM_SERVICES,     PII_NO,                    max_size=5*KB,
     max_time=20)
-cap(CAP_VNCTERM,             PII_MAYBE, checked = False)
-cap(CAP_WLB,                 PII_NO,                    max_size=3*MB,
-    max_time=20)
-cap(CAP_X11_LOGS,            PII_NO,                    max_size=100*KB)
-cap(CAP_X11_AUTH,            PII_NO,                    max_size=100*KB)
 cap(CAP_YUM,                 PII_IF_CUSTOMIZED,         max_size=10*KB,
     max_time=30)
 
@@ -307,7 +269,7 @@ def output(x):
 def output_ts(x):
     output("[%s]  %s" % (time.strftime("%x %X %Z"), x))
 
-def cmd_output(cap, args, label=None, filter=None):
+def cmd_output(cap, args, label=None, filter=None, binary=False):
     if cap in entries:
         if not label:
             if isinstance(args, list):
@@ -316,7 +278,8 @@ def cmd_output(cap, args, label=None, filter=None):
                 label = ' '.join(a)
             else:
                 label = args
-        data[label] = {'cap': cap, 'cmd_args': args, 'filter': filter}
+        data[label] = {'cap': cap, 'cmd_args': args, 'filter': filter,
+                       'binary': binary}
 
 def file_output(cap, path_list, newest_first=False):
     """
@@ -360,6 +323,16 @@ def func_output(cap, label, func):
         t = str(func).split()
         data[label] = {'cap': cap, 'func': func}
 
+def log_output(cap, logs, newest_first=False):
+    global log_days
+    file_output(cap, logs)
+    file_output(cap,
+        ['%s.%d' % (f, n) for n in range(1, log_days+1) for f in logs], \
+        newest_first=newest_first)
+    file_output(cap,
+        ['%s.%d.gz' % (f, n) for n in range(1, log_days+1) for f in logs], \
+        newest_first=newest_first)
+
 def collect_data():
     process_lists = {}
 
@@ -369,7 +342,9 @@ def collect_data():
             v['output'] = StringIOmtime()
             if not process_lists.has_key(cap):
                 process_lists[cap] = []
-            process_lists[cap].append(ProcOutput(v['cmd_args'], caps[cap][MAX_TIME], v['output'], v['filter']))
+            process_lists[cap].append(
+                ProcOutput(v['cmd_args'], caps[cap][MAX_TIME], v['output'],
+                           v['filter'], v['binary']))
         elif v.has_key('filename') and v['filename'].startswith('/proc/'):
             # proc files must be read into memory
             try:
@@ -401,7 +376,7 @@ def collect_data():
 
 def main(argv=None):
     global ANSWER_YES_TO_ALL, SILENT_MODE
-    global entries, data, dbg, unlimited_data
+    global entries, data, dbg, unlimited_data, log_days
 
     # Filter flags
     only_ovs_info = False
@@ -413,7 +388,7 @@ def main(argv=None):
         return 1
 
     output_file = None
-    output_type = 'tar.bz2'
+    output_type = 'tar.gz'
     output_fd = -1
 
     if argv is None:
@@ -423,7 +398,7 @@ def main(argv=None):
         (options, params) = getopt.gnu_getopt(
             argv, 'sy', ['capabilities', 'silent', 'yestoall', 'entries=',
                          'output=', 'outfd=', 'outfile=', 'all', 'unlimited',
-                         'debug', 'ovs'])
+                         'debug', 'ovs', 'log-days='])
     except getopt.GetoptError, opterr:
         print >>sys.stderr, opterr
         return 2
@@ -485,6 +460,9 @@ def main(argv=None):
             only_ovs_info = True
             collect_all_info = False
 
+        if k == '--log-days':
+            log_days = int(v)
+
     if len(params) != 1:
         print >>sys.stderr, "Invalid additional arguments", str(params)
         return 2
@@ -520,27 +498,18 @@ exclude those logs from the archive.
     cmd_output(CAP_BOOT_LOADER, [LS, '-lR', '/boot'])
     cmd_output(CAP_BOOT_LOADER, [MD5SUM, BOOT_KERNEL, BOOT_INITRD], label='vmlinuz-initrd.md5sum')
 
-    tree_output(CAP_COLLECTD_LOGS, COLLECTD_LOGS_DIR)
     cmd_output(CAP_DISK_INFO, [FDISK, '-l'])
     file_output(CAP_DISK_INFO, [PROC_PARTITIONS, PROC_MOUNTS])
     file_output(CAP_DISK_INFO, [FSTAB, ISCSI_CONF, ISCSI_INITIATOR])
     cmd_output(CAP_DISK_INFO, [DF, '-alT'])
     cmd_output(CAP_DISK_INFO, [DF, '-alTi'])
-    for d in disk_list():
-        cmd_output(CAP_DISK_INFO, [HDPARM, '-I', '/dev/%s' % d])
     if len(pidof('iscsid')) != 0:
         cmd_output(CAP_DISK_INFO, [ISCSIADM, '-m', 'node'])
-    cmd_output(CAP_DISK_INFO, [VGSCAN])
-    cmd_output(CAP_DISK_INFO, [PVS])
-    cmd_output(CAP_DISK_INFO, [VGS])
-    cmd_output(CAP_DISK_INFO, [LVS])
-    file_output(CAP_DISK_INFO, [LVM_CACHE, LVM_CONFIG])
     cmd_output(CAP_DISK_INFO, [LS, '-R', '/sys/class/scsi_host'])
     cmd_output(CAP_DISK_INFO, [LS, '-R', '/sys/class/scsi_disk'])
     cmd_output(CAP_DISK_INFO, [LS, '-R', '/sys/class/fc_transport'])
     cmd_output(CAP_DISK_INFO, [SG_MAP, '-x'])
     func_output(CAP_DISK_INFO, 'scsi-hosts', dump_scsi_hosts)
-    cmd_output(CAP_DISK_INFO, [LVDISPLAY, '--map'])
 
     file_output(CAP_HARDWARE_INFO, [PROC_CPUINFO, PROC_MEMINFO, PROC_IOPORTS, PROC_INTERRUPTS])
     cmd_output(CAP_HARDWARE_INFO, [DMIDECODE])
@@ -549,10 +518,7 @@ exclude those logs from the archive.
     file_output(CAP_HARDWARE_INFO, [PROC_USB_DEV, PROC_SCSI])
     file_output(CAP_HARDWARE_INFO, [SYSCONFIG_HWCONF])
     cmd_output(CAP_HARDWARE_INFO, [LS, '-lR', '/dev'])
-    # FIXME IDE?
 
-    for d in disk_list():
-        cmd_output(CAP_HDPARM_T, [HDPARM, '-tT', '/dev/%s' % d])
 
     file_output(CAP_KERNEL_INFO, [PROC_VERSION, PROC_MODULES, PROC_DEVICES,
                                   PROC_FILESYSTEMS, PROC_CMDLINE])
@@ -591,11 +557,12 @@ exclude those logs from the archive.
             f.close()
             if os.path.islink('/sys/class/net/%s/device' % p) and int(t) == 1:
                 # ARPHRD_ETHER
-                cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, p])
                 cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-S', p])
-                cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-k', p])
-                cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-i', p])
-                cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-c', p])
+                if not p.startswith('vif') and not p.startswith('tap'):
+                    cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, p])
+                    cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-k', p])
+                    cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-i', p])
+                    cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-c', p])
             if int(t) == 1:
                 cmd_output(CAP_NETWORK_STATUS,
                            [TC, '-s', '-d', 'class', 'show', 'dev', p])
@@ -622,31 +589,23 @@ exclude those logs from the archive.
         except e:
             pass
 
-    tree_output(CAP_PAM, PAM_DIR)
-    file_output(CAP_PAM, [KRB5_CONF])
-
     cmd_output(CAP_PROCESS_LIST, [PS, 'wwwaxf', '-eo', 'pid,tty,stat,time,nice,psr,pcpu,pmem,nwchan,wchan:25,args'], label='process-tree')
     func_output(CAP_PROCESS_LIST, 'fd_usage', fd_usage)
 
-    logs = ([ VAR_LOG_DIR + x for x in
-             [ 'crit.log', 'kern.log', 'daemon.log', 'user.log',
-             'syslog', 'messages', 'secure', 'debug', 'dmesg', 'boot' ]]
-            + [ OPENVSWITCH_LOG_DIR + x for x in
-                [ 'ovs-vswitchd.log', 'ovsdb-server.log',
-                  'ovs-xapi-sync.log', 'ovs-monitor-ipsec.log' ]])
-    file_output(CAP_SYSTEM_LOGS, logs)
-    file_output(CAP_SYSTEM_LOGS,
-                [ '%s.%d' % (f, n) for n in range(20) for f in logs ])
-    file_output(CAP_SYSTEM_LOGS,
-                [ '%s.%d.gz' % (f, n) for n in range(20) for f in logs ])
+    system_logs = ([ VAR_LOG_DIR + x for x in
+        ['crit.log', 'kern.log', 'daemon.log', 'user.log',
+        'syslog', 'messages', 'secure', 'debug', 'dmesg', 'boot']])
+    ovs_logs = ([ OPENVSWITCH_LOG_DIR + x for x in
+        ['ovs-vswitchd.log', 'ovsdb-server.log',
+        'ovs-xapi-sync.log', 'ovs-monitor-ipsec.log']])
+    log_output(CAP_SYSTEM_LOGS, system_logs)
+    log_output(CAP_OPENVSWITCH_LOGS, ovs_logs)
 
     if not os.path.exists('/var/log/dmesg') and not os.path.exists('/var/log/boot'):
         cmd_output(CAP_SYSTEM_LOGS, [DMESG])
 
     cmd_output(CAP_SYSTEM_SERVICES, [CHKCONFIG, '--list'])
 
-    tree_output(CAP_X11_LOGS, X11_LOGS_DIR, X11_LOGS_RE)
-    tree_output(CAP_X11_AUTH, X11_AUTH_DIR, X11_AUTH_RE)
     tree_output(CAP_SYSTEM_LOGS, VAR_LOG_CORE_DIR)
 
     file_output(CAP_YUM, [YUM_LOG])
@@ -724,8 +683,6 @@ exclude those logs from the archive.
     else:
         make_zip(subdir, output_file)
 
-    clean_tapdisk_logs()
-
     if dbg:
         print >>sys.stderr, "Category sizes (max, actual):\n"
         for c in caps.keys():
@@ -733,39 +690,6 @@ exclude those logs from the archive.
                                                      cap_sizes[c])
     return 0
 
-def find_tapdisk_logs():
-    return glob.glob('/var/log/blktap/*.log*')
-
-def generate_tapdisk_logs():
-    for pid in pidof('tapdisk'):
-       try:
-           os.kill(pid, SIGUSR1)
-            output_ts("Including logs for tapdisk process %d" % pid)
-        except :
-            pass
-    # give processes a second to write their logs
-    time.sleep(1)
-
-def clean_tapdisk_logs():
-    for filename in find_tapdisk_logs():
-        try:
-            os.remove(filename)
-        except :
-            pass
-
-def filter_db_pii(str, state):
-    if 'in_secret_table' not in state:
-        state['in_secret_table'] = False
-
-    if str.startswith('<table ') and 'name="secret"' in str:
-        state['in_secret_table'] = True
-    elif str.startswith('</table>'):
-        state['in_secret_table'] = False
-
-    if state['in_secret_table'] and str.startswith("<row"): # match only on DB rows
-        str = re.sub(r'(value=")[^"]+(")', r'\1REMOVED\2', str)
-    return str
-
 def dump_scsi_hosts(cap):
     output = ''
     l = os.listdir('/sys/class/scsi_host')
@@ -932,8 +856,12 @@ def load_plugins(just_capabilities=False, filter=None):
                     continue
                 if el.tagName == "files":
                     newest_first = getBoolAttr(el, 'newest_first')
-                    file_output(dir, getText(el.childNodes).split(),
-                                newest_first=newest_first)
+                    if el.getAttribute("type") == "logs":
+                        log_output(dir, getText(el.childNodes).split(),
+                                    newest_first=newest_first)
+                    else:
+                        file_output(dir, getText(el.childNodes).split(),
+                                    newest_first=newest_first)
                 elif el.tagName == "directory":
                     pattern = el.getAttribute("pattern")
                     if pattern == '': pattern = None
@@ -945,7 +873,8 @@ def load_plugins(just_capabilities=False, filter=None):
                 elif el.tagName == "command":
                     label = el.getAttribute("label")
                     if label == '': label = None
-                    cmd_output(dir, getText(el.childNodes), label)
+                    binary = getBoolAttr(el, 'binary')
+                    cmd_output(dir, getText(el.childNodes), label, binary=binary)
 
 def make_tar(subdir, suffix, output_fd, output_file):
     global SILENT_MODE, data
@@ -1183,7 +1112,7 @@ def disk_list():
 class ProcOutput:
     debug = False
 
-    def __init__(self, command, max_time, inst=None, filter=None):
+    def __init__(self, command, max_time, inst=None, filter=None, binary=False):
         self.command = command
         self.max_time = max_time
         self.inst = inst
@@ -1194,6 +1123,10 @@ class ProcOutput:
         self.timeout = int(time.time()) + self.max_time
         self.filter = filter
         self.filter_state = {}
+        if binary:
+            self.bufsize = 1048576  # 1MB buffer
+        else:
+            self.bufsize = 1        # line buffered
 
     def __del__(self):
         self.terminate()
@@ -1206,7 +1139,9 @@ class ProcOutput:
         try:
             if ProcOutput.debug:
                 output_ts("Starting '%s'" % self.cmdAsStr())
-            self.proc = Popen(self.command, bufsize=1, stdin=dev_null, stdout=PIPE, stderr=dev_null, shell=isinstance(self.command, str))
+            self.proc = Popen(self.command, bufsize=self.bufsize,
+                              stdin=dev_null, stdout=PIPE, stderr=dev_null,
+                              shell=isinstance(self.command, str))
             old = fcntl.fcntl(self.proc.stdout.fileno(), fcntl.F_GETFD)
             fcntl.fcntl(self.proc.stdout.fileno(), fcntl.F_SETFD, old | fcntl.FD_CLOEXEC)
             self.running = True
@@ -1229,7 +1164,10 @@ class ProcOutput:
 
     def read_line(self):
         assert self.running
-        line = self.proc.stdout.readline()
+        if self.bufsize == 1:
+            line = self.proc.stdout.readline()
+        else:
+            line = self.proc.stdout.read(self.bufsize)
         if line == '':
             # process exited
             self.proc.stdout.close()
index 78f67a3..e186e71 100755 (executable)
@@ -1,5 +1,5 @@
 #! /bin/sh
-# Copyright (C) 2009, 2010, 2011, 2012 Nicira, Inc.
+# Copyright (C) 2009, 2010, 2011, 2012, 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.
@@ -216,8 +216,9 @@ start_forwarding () {
         log_success_msg "ovs-vswitchd is already running"
     else
         # Increase the limit on the number of open file descriptors.
-        # ovs-vswitchd needs 16 per datapath, plus a few extra, so this
-        # should allow for 256 (or more) bridges.
+        # On Linux, ovs-vswitchd needs about one file descriptor per
+        # switch port, so this allows a very large number of switch
+        # ports.
         ulimit -n 5000
 
            # Start ovs-vswitchd.
@@ -286,6 +287,7 @@ save_ofports_if_required () {
                 "${script_ofports}" script_ofports
             ;;
         *)
+            script_ofports=""
             ;;
     esac
 }
index b48b349..363485b 100644 (file)
@@ -939,14 +939,13 @@ dpctl_normalize_actions(int argc, char *argv[])
 
     hmap_init(&actions_per_flow);
     NL_ATTR_FOR_EACH (a, left, odp_actions.data, odp_actions.size) {
-        if (nl_attr_type(a) == OVS_ACTION_ATTR_POP_VLAN) {
+        const struct ovs_action_push_vlan *push;
+        switch(nl_attr_type(a)) {
+        case OVS_ACTION_ATTR_POP_VLAN:
             flow.vlan_tci = htons(0);
             continue;
-        }
-
-        if (nl_attr_type(a) == OVS_ACTION_ATTR_PUSH_VLAN) {
-            const struct ovs_action_push_vlan *push;
 
+        case OVS_ACTION_ATTR_PUSH_VLAN:
             push = nl_attr_get_unspec(a, sizeof *push);
             flow.vlan_tci = push->vlan_tci;
             continue;
@@ -980,6 +979,15 @@ dpctl_normalize_actions(int argc, char *argv[])
             printf("no vlan: ");
         }
 
+        if (af->flow.mpls_depth) {
+            printf("mpls(label=%"PRIu32",tc=%d,ttl=%d): ",
+                   mpls_lse_to_label(af->flow.mpls_lse),
+                   mpls_lse_to_tc(af->flow.mpls_lse),
+                   mpls_lse_to_ttl(af->flow.mpls_lse));
+        } else {
+            printf("no mpls: ");
+        }
+
         ds_clear(&s);
         format_odp_actions(&s, af->actions.data, af->actions.size);
         puts(ds_cstr(&s));
index c48645a..6589eff 100644 (file)
@@ -915,6 +915,34 @@ for the tag. Only ethertype 0x8100 should be used. (0x88a8 which the spec
 allows isn't supported at the moment.)
 A priority of zero and the tag of zero are used for the new tag.
 .
+.IP \fBpush_mpls\fR:\fIethertype\fR
+If the packet does not already contain any MPLS labels, changes the
+packet's Ethertype to \fIethertype\fR, which must be either the MPLS
+unicast Ethertype \fB0x8847\fR or the MPLS multicast Ethertype
+\fB0x8848\fR, and then pushes an initial label stack entry.  The label
+stack entry's default label is 2 if the packet contains IPv6 and 0
+otherwise, its default traffic control value is the low 3 bits of the
+packet's DSCP value (0 if the packet is not IP), and its TTL is copied
+from the IP TTL (64 if the packet is not IP).
+.IP
+If the packet does already contain an MPLS label, pushes a new
+outermost label as a copy of the existing outermost label.
+.IP
+There are some limitations in the implementation.  \fBpush_mpls\fR
+followed by another \fBpush_mpls\fR will result in the first
+\fBpush_mpls\fR being discarded.
+.
+.IP \fBpop_mpls\fR:\fIethertype\fR
+Strips the outermost MPLS label stack entry.  If the MPLS label
+stripped was the only one, changes the ethertype of a packet to
+\fIethertype\fR, which should not ordinarily be an MPLS Ethertype.
+.
+.IP
+There are some limitations in the implementation.  \fBpop_mpls\fR
+followed by another \fBpush_mpls\fR without an intermediate
+\fBpush_mpls\fR will result in the first \fBpush_mpls\fR being
+discarded.
+.
 .IP \fBmod_dl_src\fB:\fImac\fR
 Sets the source Ethernet address to \fImac\fR.
 .
@@ -1046,21 +1074,6 @@ the \fBiter_hash\fR algorithm uses \fIarg\fR.
 .IP
 Refer to \fBnicira\-ext.h\fR for more details.
 .
-.IP "\fBautopath(\fIid\fB, \fIdst\fB[\fIstart\fB..\fIend\fB])\fR"
-Deprecated and slated for removal in Feburary 2013.
-.IP
-Given \fIid\fR, chooses an OpenFlow port and populates it in
-\fIdst\fB[\fIstart\fB..\fIend\fB]\fR, which must be an NXM field as
-described above.
-.IP
-Currently, \fIid\fR should be the OpenFlow port number of an interface on the
-bridge.  If it isn't then \fIdst\fB[\fIstart\fB..\fIend\fB]\fR will be
-populated with the OpenFlow port "none".  If \fIid\fR is a member of a bond,
-the normal bond selection logic will be used to choose the destination port.
-Otherwise, the register will be populated with \fIid\fR itself.
-.IP
-Refer to \fBnicira\-ext.h\fR for more details.
-.
 .IP "\fBbundle(\fIfields\fB, \fIbasis\fB, \fIalgorithm\fB, \fIslave_type\fB, slaves:[\fIs1\fB, \fIs2\fB, ...])\fR"
 Hashes \fIfields\fR using \fIbasis\fR as a universal hash parameter, then
 applies the bundle link selection \fIalgorithm\fR to choose one of the listed
index 4d8c39f..ec775c7 100644 (file)
@@ -2182,7 +2182,7 @@ ofctl_parse_flows__(struct ofputil_flow_mod *fms, size_t n_fms)
             break;
         }
     }
-    ovs_assert(IS_POW2(protocol));
+    ovs_assert(is_pow2(protocol));
 
     printf("chosen protocol: %s\n", ofputil_protocol_to_string(protocol));
 
index 1f15410..a506375 100755 (executable)
@@ -272,7 +272,7 @@ certificate    = $dir/cacert.pem       # The CA cert
 serial         = $dir/serial           # serial no file
 private_key    = $dir/private/cakey.pem# CA private key
 RANDFILE       = $dir/private/.rand    # random number file
-default_days   = 365                   # how long to certify for
+default_days   = 36525                 # how long to certify for
 default_crl_days= 30                   # how long before next CRL
 default_md     = md5                   # md to use
 policy         = policy                # default policy
@@ -303,7 +303,7 @@ EOF
             -newkey $newkey -keyout private/cakey.pem -out careq.pem \
             1>&3 2>&3
         openssl ca -config ca.cnf -create_serial -out cacert.pem \
-            -days 2191 -batch -keyfile private/cakey.pem -selfsign \
+            -days 36525 -batch -keyfile private/cakey.pem -selfsign \
             -infiles careq.pem 1>&3 2>&3
         chmod 0700 private/cakey.pem
 
@@ -514,7 +514,7 @@ elif test "$command" = self-sign; then
     # Create both the private key and certificate with restricted permissions.
     (umask 077 && \
      openssl x509 -in "$arg1-req.pem" -out "$arg1-cert.pem.tmp" \
-        -signkey "$arg1-privkey.pem" -req -days 2191 -text) 2>&3 || exit $?
+        -signkey "$arg1-privkey.pem" -req -days 36525 -text) 2>&3 || exit $?
 
     # Reset the permissions on the certificate to the user's default.
     cat "$arg1-cert.pem.tmp" > "$arg1-cert.pem"
index dd3099f..ab0ecd6 100644 (file)
@@ -212,8 +212,7 @@ static struct port *port_lookup(const struct bridge *, const char *name);
 static void port_configure(struct port *);
 static struct lacp_settings *port_configure_lacp(struct port *,
                                                  struct lacp_settings *);
-static void port_configure_bond(struct port *, struct bond_settings *,
-                                uint32_t *bond_stable_ids);
+static void port_configure_bond(struct port *, struct bond_settings *);
 static bool port_is_synthetic(const struct port *);
 
 static void reconfigure_system_stats(const struct ovsrec_open_vswitch *);
@@ -761,12 +760,9 @@ port_configure(struct port *port)
     /* Get bond settings. */
     if (s.n_slaves > 1) {
         s.bond = &bond_settings;
-        s.bond_stable_ids = xmalloc(s.n_slaves * sizeof *s.bond_stable_ids);
-        port_configure_bond(port, &bond_settings, s.bond_stable_ids);
+        port_configure_bond(port, &bond_settings);
     } else {
         s.bond = NULL;
-        s.bond_stable_ids = NULL;
-
         LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
             netdev_set_miimon_interval(iface->netdev, 0);
         }
@@ -779,7 +775,6 @@ port_configure(struct port *port)
     free(s.slaves);
     free(s.trunks);
     free(s.lacp_slaves);
-    free(s.bond_stable_ids);
 }
 
 /* Pick local port hardware address and datapath ID for 'br'. */
@@ -1446,9 +1441,9 @@ iface_create(struct bridge *br, struct if_cfg *if_cfg, int ofp_port)
 
             error = netdev_open(port->name, "internal", &netdev);
             if (!error) {
-                uint16_t ofp_port = if_cfg->ofport;
+                uint16_t fake_ofp_port = if_cfg->ofport;
 
-                ofproto_port_add(br->ofproto, netdev, &ofp_port);
+                ofproto_port_add(br->ofproto, netdev, &fake_ofp_port);
                 netdev_close(netdev);
             } else {
                 VLOG_WARN("could not open network device %s (%s)",
@@ -1966,15 +1961,16 @@ run_system_stats(void)
 }
 
 static inline const char *
-nx_role_to_str(enum nx_role role)
+ofp12_controller_role_to_str(enum ofp12_controller_role role)
 {
     switch (role) {
-    case NX_ROLE_OTHER:
+    case OFPCR12_ROLE_EQUAL:
         return "other";
-    case NX_ROLE_MASTER:
+    case OFPCR12_ROLE_MASTER:
         return "master";
-    case NX_ROLE_SLAVE:
+    case OFPCR12_ROLE_SLAVE:
         return "slave";
+    case OFPCR12_ROLE_NOCHANGE:
     default:
         return "*** INVALID ROLE ***";
     }
@@ -2010,7 +2006,8 @@ refresh_controller_status(void)
             }
 
             ovsrec_controller_set_is_connected(cfg, cinfo->is_connected);
-            ovsrec_controller_set_role(cfg, nx_role_to_str(cinfo->role));
+            ovsrec_controller_set_role(cfg, ofp12_controller_role_to_str(
+                                           cinfo->role));
             ovsrec_controller_set_status(cfg, &smap);
             smap_destroy(&smap);
         } else {
@@ -2804,8 +2801,10 @@ bridge_configure_remotes(struct bridge *br,
             if (!strncmp(c->target, "unix:", 5)) {
                 /* Connect to a listening socket */
                 whitelist = xasprintf("unix:%s/", ovs_rundir());
-                if (!equal_pathnames(c->target, whitelist,
-                                     strlen(whitelist))) {
+                if (strchr(c->target, '/') &&
+                   !equal_pathnames(c->target, whitelist,
+                     strlen(whitelist))) {
+                    /* Absolute path specified, but not in ovs_rundir */
                     VLOG_ERR_RL(&rl, "bridge %s: Not connecting to socket "
                                   "controller \"%s\" due to possibility for "
                                   "remote exploit.  Instead, specify socket "
@@ -3111,13 +3110,11 @@ iface_configure_lacp(struct iface *iface, struct lacp_slave_settings *s)
 }
 
 static void
-port_configure_bond(struct port *port, struct bond_settings *s,
-                    uint32_t *bond_stable_ids)
+port_configure_bond(struct port *port, struct bond_settings *s)
 {
     const char *detect_s;
     struct iface *iface;
     int miimon_interval;
-    size_t i;
 
     s->name = port->name;
     s->balance = BM_AB;
@@ -3169,17 +3166,7 @@ port_configure_bond(struct port *port, struct bond_settings *s,
 
     s->fake_iface = port->cfg->bond_fake_iface;
 
-    i = 0;
     LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
-        long long stable_id;
-
-        stable_id = smap_get_int(&iface->cfg->other_config, "bond-stable-id",
-                                 0);
-        if (stable_id <= 0 || stable_id >= UINT32_MAX) {
-            stable_id = iface->ofp_port;
-        }
-        bond_stable_ids[i++] = stable_id;
-
         netdev_set_miimon_interval(iface->netdev, miimon_interval);
     }
 }
index 16125a5..a7901a8 100644 (file)
@@ -1,6 +1,6 @@
 {"name": "Open_vSwitch",
- "version": "6.11.3",
- "cksum": "2234602985 17310",
+ "version": "7.0.0",
+ "cksum": "3537583872 17299",
  "tables": {
    "Open_vSwitch": {
      "columns": {
                   "min": 0, "max": 1}},
        "bond_mode": {
          "type": {"key": {"type": "string",
-           "enum": ["set", ["balance-tcp", "balance-slb", "active-backup", "stable"]]},
+           "enum": ["set", ["balance-tcp", "balance-slb", "active-backup"]]},
          "min": 0, "max": 1}},
        "lacp": {
          "type": {"key": {"type": "string",
index 18643c2..e1d9372 100644 (file)
           information such as destination MAC address, IP address, and TCP
           port.
         </dd>
-
-        <dt><code>stable</code></dt>
-        <dd>
-          <p>Deprecated and slated for removal in February 2013.</p>
-          <p>Attempts to always assign a given flow to the same slave
-          consistently.  In an effort to maintain stability, no load
-          balancing is done.  Uses a similar hashing strategy to
-          <code>balance-tcp</code>, always taking into account L3 and L4
-          fields even if LACP negotiations are unsuccessful. </p>
-          <p>Slave selection decisions are made based on <ref table="Interface"
-          column="other_config" key="bond-stable-id"/> if set.  Otherwise,
-          OpenFlow port number is used.  Decisions are consistent across all
-          <code>ovs-vswitchd</code> instances with equivalent
-          <ref table="Interface" column="other_config" key="bond-stable-id"/>
-          values.</p>
-        </dd>
       </dl>
 
       <p>These columns apply only to bonded ports.  Their values are
             Same as IPSEC_GRE except 64 bit key.
           </dd>
 
-          <dt><code>capwap</code></dt>
-          <dd>
-            An Ethernet tunnel over the UDP transport portion of CAPWAP (RFC
-            5415).  This allows interoperability with certain switches that do
-            not support GRE.  Only the tunneling component of the protocol is
-            implemented.  UDP ports 58881 and 58882 are used as the source and
-            destination ports respectively.  CAPWAP is currently supported only
-            with the Linux kernel datapath with kernel version 2.6.26 or later.
-
-            CAPWAP support is deprecated and will be removed no earlier than
-            February 2013.
-          </dd>
-
           <dt><code>vxlan</code></dt>
           <dd>
            <p>
              An Ethernet tunnel over the experimental, UDP-based VXLAN
              protocol described at
-             <code>http://tools.ietf.org/html/draft-mahalingam-dutt-dcops-vxlan-02</code>.
+             <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>
           </dd>
 
+          <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.
+          </dd>
+
           <dt><code>patch</code></dt>
           <dd>
             A pair of virtual devices that act as a patch cable.
       <p>
         These options apply to interfaces with <ref column="type"/> of
         <code>gre</code>, <code>ipsec_gre</code>, <code>gre64</code>,
-        <code>ipsec_gre64</code>, <code>capwap</code>, and
-        <code>vxlan</code>.
+        <code>ipsec_gre64</code>, <code>vxlan</code>, and <code>lisp</code>.
       </p>
 
       <p>
             key="in_key"/> at all.
           </li>
           <li>
-            A positive 24-bit (for VXLAN), 32-bit (for GRE) or 64-bit (for
-            CAPWAP) number.  The tunnel receives only packets with the
+            A positive 24-bit (for VXLAN and LISP), 32-bit (for GRE) or 64-bit
+            (for GRE64) number.  The tunnel receives only packets with the
             specified key.
           </li>
           <li>
             key="out_key"/> at all.
           </li>
           <li>
-            A positive 24-bit (for VXLAN), 32-bit (for GRE) or 64-bit (for
-            CAPWAP) number.  Packets sent through the tunnel will have the
+            A positive 24-bit (for VXLAN and LISP), 32-bit (for GRE) or 64-bit
+            (for GRE64) number.  Packets sent through the tunnel will have the
             specified key.
           </li>
           <li>
 
       <column name="status" key="source_ip">
         The source IP address used for an IPv4 tunnel end-point, such as
-        <code>gre</code> or <code>capwap</code>.
+        <code>gre</code>.
       </column>
 
       <column name="status" key="tunnel_egress_iface">
-        Egress interface for tunnels.  Currently only relevant for GRE and
-        CAPWAP tunnels.  On Linux systems, this column will show the name of
-        the interface which is responsible for routing traffic destined for the
-        configured <ref column="options" key="remote_ip"/>.  This could be an
-        internal interface such as a bridge port.
+        Egress interface for tunnels.  Currently only relevant for GRE tunnels
+        On Linux systems, this column will show the name of the interface
+        which is responsible for routing traffic destined for the configured
+        <ref column="options" key="remote_ip"/>.  This could be an internal
+        interface such as a bridge port.
       </column>
 
       <column name="status" key="tunnel_egress_iface_carrier"
     </group>
 
     <group title="Bonding Configuration">
-      <column name="other_config" key="bond-stable-id"
-              type='{"type": "integer", "minInteger": 1}'>
-        Used in <code>stable</code> bond mode to make slave
-        selection decisions.  Allocating <ref column="other_config"
-        key="bond-stable-id"/> values consistently across interfaces
-        participating in a bond will guarantee consistent slave selection
-        decisions across <code>ovs-vswitchd</code> instances when using
-        <code>stable</code> bonding mode.
-      </column>
-
       <column name="other_config" key="lacp-port-id"
               type='{"type": "integer", "minInteger": 1, "maxInteger": 65535}'>
         The LACP port ID of this <ref table="Interface"/>.  Port IDs are
index 46b94b9..73751d4 100644 (file)
@@ -6,6 +6,8 @@
 # without warranty of any kind.
 
 /var/log/openvswitch/*.log {
+       daily
+       compress
        sharedscripts
        missingok
        postrotate
index c41a7e5..4e8f576 100644 (file)
@@ -118,18 +118,16 @@ install python/compat/uuid.py $RPM_BUILD_ROOT/usr/share/openvswitch/python
 install python/compat/argparse.py $RPM_BUILD_ROOT/usr/share/openvswitch/python
 
 install -d -m 755 $RPM_BUILD_ROOT/etc/xensource/bugtool
-mv $RPM_BUILD_ROOT/usr/share/openvswitch/bugtool-plugins/* $RPM_BUILD_ROOT/etc/xensource/bugtool
+cp -rf $RPM_BUILD_ROOT/usr/share/openvswitch/bugtool-plugins/* $RPM_BUILD_ROOT/etc/xensource/bugtool
 
 # Get rid of stuff we don't want to make RPM happy.
 rm \
     $RPM_BUILD_ROOT/usr/bin/ovs-benchmark \
-    $RPM_BUILD_ROOT/usr/sbin/ovs-bugtool \
     $RPM_BUILD_ROOT/usr/bin/ovs-controller \
     $RPM_BUILD_ROOT/usr/bin/ovs-l3ping \
     $RPM_BUILD_ROOT/usr/bin/ovs-pki \
     $RPM_BUILD_ROOT/usr/bin/ovs-test \
     $RPM_BUILD_ROOT/usr/share/man/man1/ovs-benchmark.1 \
-    $RPM_BUILD_ROOT/usr/share/man/man8/ovs-bugtool.8 \
     $RPM_BUILD_ROOT/usr/share/man/man8/ovs-controller.8 \
     $RPM_BUILD_ROOT/usr/share/man/man8/ovs-l3ping.8 \
     $RPM_BUILD_ROOT/usr/share/man/man8/ovs-pki.8 \
@@ -408,6 +406,7 @@ exit 0
 /etc/logrotate.d/openvswitch
 /etc/profile.d/openvswitch.sh
 /usr/share/openvswitch/python/
+/usr/share/openvswitch/bugtool-plugins/*
 /usr/share/openvswitch/scripts/ovs-check-dead-ifs
 /usr/share/openvswitch/scripts/ovs-xapi-sync
 /usr/share/openvswitch/scripts/interface-reconfigure
@@ -421,6 +420,7 @@ exit 0
 /usr/share/openvswitch/scripts/ovs-ctl
 /usr/share/openvswitch/scripts/ovs-lib
 /usr/share/openvswitch/vswitch.ovsschema
+/usr/sbin/ovs-bugtool
 /usr/sbin/ovs-vlan-bug-workaround
 /usr/sbin/ovs-vswitchd
 /usr/sbin/ovsdb-server
@@ -441,6 +441,7 @@ exit 0
 /usr/share/man/man1/ovsdb-tool.1.gz
 /usr/share/man/man5/ovs-vswitchd.conf.db.5.gz
 /usr/share/man/man8/ovs-appctl.8.gz
+/usr/share/man/man8/ovs-bugtool.8.gz
 /usr/share/man/man8/ovs-ctl.8.gz
 /usr/share/man/man8/ovs-dpctl.8.gz
 /usr/share/man/man8/ovs-ofctl.8.gz