dpif-linux: Always pass an actions attribute in dpif_flow_put().
authorBen Pfaff <blp@nicira.com>
Mon, 31 Jan 2011 23:46:03 +0000 (15:46 -0800)
committerBen Pfaff <blp@nicira.com>
Tue, 1 Feb 2011 05:40:07 +0000 (21:40 -0800)
The kernel expects that ODP_FLOW_NEW always has an ODP_FLOW_ATTR_ACTIONS
attribute, even though that attribute may be empty to drop all of the
packets in the flow.  Similarly, ODP_FLOW_SET as used by
dpif_linux_flow_put() should always have such an attribute, since it is
used by OVS to update the flow's actions.  So make it possible for
dpif_linux_flow_to_ofpbuf() to pass an empty actions attribute, and make
dpif_linux_flow_put() always force that behavior if the actions_len passed
to it is 0.

This fixes EINVAL error creating flows to drop packets.

Acked-by: Jesse Gross <jesse@nicira.com>
lib/dpif-linux.c

index 9b84145e2417097ec624d1a99e2494485ad48e8c..2e35857bad1f852ff0f8f9b92664396ab05eb1e7 100644 (file)
@@ -89,7 +89,10 @@ struct dpif_linux_flow {
      *
      * The 'stats' and 'used' members point to 64-bit data that might only be
      * aligned on 32-bit boundaries, so get_unaligned_u64() should be used to
-     * access their values. */
+     * access their values.
+     *
+     * If 'actions' is nonnull then ODP_FLOW_ATTR_ACTIONS will be included in
+     * the Netlink version of the command, even if actions_len is zero. */
     const struct nlattr *key;           /* ODP_FLOW_ATTR_KEY. */
     size_t key_len;
     const struct nlattr *actions;       /* ODP_FLOW_ATTR_ACTIONS. */
@@ -541,6 +544,7 @@ dpif_linux_flow_put(struct dpif *dpif_, enum dpif_flow_put_flags flags,
 {
     struct dpif_linux *dpif = dpif_linux_cast(dpif_);
     struct dpif_linux_flow request, reply;
+    struct nlattr dummy_action;
     struct ofpbuf *buf;
     int error;
 
@@ -549,7 +553,8 @@ dpif_linux_flow_put(struct dpif *dpif_, enum dpif_flow_put_flags flags,
     request.dp_ifindex = dpif->dp_ifindex;
     request.key = key;
     request.key_len = key_len;
-    request.actions = actions;
+    /* Ensure that ODP_FLOW_ATTR_ACTIONS will always be included. */
+    request.actions = actions ? actions : &dummy_action;
     request.actions_len = actions_len;
     if (flags & DPIF_FP_ZERO_STATS) {
         request.clear = true;
@@ -1462,7 +1467,7 @@ dpif_linux_flow_to_ofpbuf(const struct dpif_linux_flow *flow,
         nl_msg_put_unspec(buf, ODP_FLOW_ATTR_KEY, flow->key, flow->key_len);
     }
 
-    if (flow->actions_len) {
+    if (flow->actions || flow->actions_len) {
         nl_msg_put_unspec(buf, ODP_FLOW_ATTR_ACTIONS,
                           flow->actions, flow->actions_len);
     }