[ovs-dev] [RFCv3 08/13] dpif: Add Unique flow identifiers.

Joe Stringer joestringer at nicira.com
Tue Sep 2 10:48:46 UTC 2014


One of the limiting factors on the number of flows that can be supported
in the datapath is the overhead of assembling flow dump messages in the
datapath. This patch adds a new alternative to dumping the key, mask and
actions from the datapath, which is a 128-bit unique identifier for the
flow. For each flow dump, the dpif user specifies which fields may be
omitted, allowing the common case to only dump a pair of 128-bit ID and
flow stats.

Signed-off-by: Joe Stringer <joestringer at nicira.com>
---
I'm still looking at whether it might be worth trying a 64-bit UID
instead. Any feedback on this would be welcome.

v3: Rebase.
---
 datapath/linux/compat/include/linux/openvswitch.h |   26 +++++++++++
 lib/dpctl.c                                       |    6 ++-
 lib/dpif-linux.c                                  |    5 +-
 lib/dpif-netdev.c                                 |   12 ++++-
 lib/dpif-provider.h                               |    8 +++-
 lib/dpif.c                                        |   38 ++++++++++++---
 lib/dpif.h                                        |   34 ++++++++++++--
 lib/odp-util.c                                    |   51 +++++++++++++++++++++
 lib/odp-util.h                                    |   25 ++++++++++
 ofproto/ofproto-dpif-upcall.c                     |   14 ++++--
 ofproto/ofproto-dpif.c                            |   13 ++++--
 11 files changed, 205 insertions(+), 27 deletions(-)

diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h
index 9c18b3b..33397ee 100644
--- a/datapath/linux/compat/include/linux/openvswitch.h
+++ b/datapath/linux/compat/include/linux/openvswitch.h
@@ -470,6 +470,10 @@ struct ovs_key_nd {
  * a wildcarded match. Omitting attribute is treated as wildcarding all
  * corresponding fields. Optional for all requests. If not present,
  * all flow key bits are exact match bits.
+ * @OVS_FLOW_ATTR_UID: Nested %OVS_UID_ATTR_* attributes specifying unique
+ * identifiers for flows and providing alternative semantics for flow
+ * installation and retrieval. Required for all requests if the datapath is
+ * created with %OVS_DP_F_INDEX_BY_UID.
  *
  * These attributes follow the &struct ovs_header within the Generic Netlink
  * payload for %OVS_FLOW_* commands.
@@ -483,12 +487,34 @@ enum ovs_flow_attr {
 	OVS_FLOW_ATTR_USED,      /* u64 msecs last used in monotonic time. */
 	OVS_FLOW_ATTR_CLEAR,     /* Flag to clear stats, tcp_flags, used. */
 	OVS_FLOW_ATTR_MASK,      /* Sequence of OVS_KEY_ATTR_* attributes. */
+	OVS_FLOW_ATTR_UID,       /* 64-bit Unique flow identifier. */
 	__OVS_FLOW_ATTR_MAX
 };
 
 #define OVS_FLOW_ATTR_MAX (__OVS_FLOW_ATTR_MAX - 1)
 
 /**
+ * enum ovs_uid_attr - Unique identifier types.
+ *
+ * @OVS_UID_ATTR_FLAGS: A 32-bit value specifying changes to the behaviour of
+ * the current %OVS_FLOW_CMD_* request. Optional for all requests.
+ * @OVS_UID_ATTR_ID: A 64-bit value uniquely identifying the flow.
+ */
+enum ovs_uid_attr {
+	OVS_UID_ATTR_UNSPEC,
+	OVS_UID_ATTR_FLAGS,	/* u32 of OVS_UID_F_* */
+	OVS_UID_ATTR_ID,	/* u64 unique flow identifier. */
+	__OVS_UID_ATTR_MAX
+};
+
+#define OVS_UID_ATTR_MAX (__OVS_UID_ATTR_MAX - 1)
+
+/* Skip attributes for notifications. */
+#define OVS_UID_F_SKIP_KEY	(1 << 0)
+#define OVS_UID_F_SKIP_MASK	(1 << 1)
+#define OVS_UID_F_SKIP_ACTIONS	(1 << 2)
+
+/**
  * enum ovs_sample_attr - Attributes for %OVS_ACTION_ATTR_SAMPLE action.
  * @OVS_SAMPLE_ATTR_PROBABILITY: 32-bit fraction of packets to sample with
  * @OVS_ACTION_ATTR_SAMPLE.  A value of 0 samples no packets, a value of
diff --git a/lib/dpctl.c b/lib/dpctl.c
index 623f5b1..db4c8f5 100644
--- a/lib/dpctl.c
+++ b/lib/dpctl.c
@@ -736,7 +736,7 @@ dpctl_dump_flows(int argc, const char *argv[], struct dpctl_params *dpctl_p)
     }
 
     ds_init(&ds);
-    flow_dump = dpif_flow_dump_create(dpif);
+    flow_dump = dpif_flow_dump_create(dpif, 0);
     flow_dump_thread = dpif_flow_dump_thread_create(flow_dump);
     while (dpif_flow_dump_next(flow_dump_thread, &f, 1)) {
         if (filter) {
@@ -836,12 +836,13 @@ dpctl_put_flow(int argc, const char *argv[], enum dpif_flow_put_flags flags,
         dpctl_error(dpctl_p, error, "parsing actions");
         goto out_freeactions;
     }
+    /* XXX: UID parsing */
     error = dpif_flow_put(dpif, flags,
                           ofpbuf_data(&key), ofpbuf_size(&key),
                           ofpbuf_size(&mask) == 0 ? NULL : ofpbuf_data(&mask),
                           ofpbuf_size(&mask),
                           ofpbuf_data(&actions), ofpbuf_size(&actions),
-                          dpctl_p->print_statistics ? &stats : NULL);
+                          NULL, 0, dpctl_p->print_statistics ? &stats : NULL);
     if (error) {
         dpctl_error(dpctl_p, error, "updating flow table");
         goto out_freeactions;
@@ -928,6 +929,7 @@ dpctl_del_flow(int argc, const char *argv[], struct dpctl_params *dpctl_p)
 
     error = dpif_flow_del(dpif,
                           ofpbuf_data(&key), ofpbuf_size(&key),
+                          NULL, 0, /* XXX */
                           dpctl_p->print_statistics ? &stats : NULL);
     if (error) {
         dpctl_error(dpctl_p, error, "deleting flow");
diff --git a/lib/dpif-linux.c b/lib/dpif-linux.c
index 2c387ed..a32a550 100644
--- a/lib/dpif-linux.c
+++ b/lib/dpif-linux.c
@@ -1120,7 +1120,8 @@ dpif_linux_flow_dump_cast(struct dpif_flow_dump *dump)
 }
 
 static struct dpif_flow_dump *
-dpif_linux_flow_dump_create(const struct dpif *dpif_)
+dpif_linux_flow_dump_create(const struct dpif *dpif_,
+                            uint32_t dump_flags OVS_UNUSED)
 {
     const struct dpif_linux *dpif = dpif_linux_cast(dpif_);
     struct dpif_linux_flow_dump *dump;
@@ -1207,6 +1208,8 @@ dpif_linux_flow_to_dpif_flow(struct dpif_flow *dpif_flow,
     dpif_flow->mask_len = linux_flow->mask_len;
     dpif_flow->actions = linux_flow->actions;
     dpif_flow->actions_len = linux_flow->actions_len;
+    dpif_flow->uid = NULL;
+    dpif_flow->uid_len = 0;
     dpif_linux_flow_get_stats(linux_flow, &dpif_flow->stats);
 }
 
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 0ccf47d..66795fd 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -1270,6 +1270,9 @@ dp_netdev_flow_to_dpif_flow(const struct dp_netdev_flow *netdev_flow,
     flow->actions = actions->actions;
     flow->actions_len = actions->size;
 
+    flow->uid = NULL;
+    flow->uid_len = 0;
+
     get_dpif_flow_stats(netdev_flow, &flow->stats);
 }
 
@@ -1558,7 +1561,8 @@ dpif_netdev_flow_dump_cast(struct dpif_flow_dump *dump)
 }
 
 static struct dpif_flow_dump *
-dpif_netdev_flow_dump_create(const struct dpif *dpif_)
+dpif_netdev_flow_dump_create(const struct dpif *dpif_,
+                             uint32_t dump_flags OVS_UNUSED)
 {
     struct dpif_netdev_flow_dump *dump;
 
@@ -1676,6 +1680,10 @@ dpif_netdev_flow_dump_next(struct dpif_flow_dump_thread *thread_,
         f->actions = dp_actions->actions;
         f->actions_len = dp_actions->size;
 
+        /* UID. */
+        f->uid = NULL;
+        f->uid_len = 0;
+
         /* Stats. */
         get_dpif_flow_stats(netdev_flow, &f->stats);
     }
@@ -2093,7 +2101,7 @@ dp_netdev_upcall(struct dp_netdev *dp, struct dpif_packet *packet_,
         ds_destroy(&ds);
     }
 
-    return dp->upcall_cb(packet, flow, type, userdata, actions, wc,
+    return dp->upcall_cb(packet, flow, type, userdata, actions, wc, NULL,
                          put_actions, dp->upcall_aux);
 }
 
diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h
index 89b32dd..691827f 100644
--- a/lib/dpif-provider.h
+++ b/lib/dpif-provider.h
@@ -256,8 +256,12 @@ struct dpif_class {
      *
      * 'flow_dump_create' and 'flow_dump_thread_create' must initialize the
      * structures that they return with dpif_flow_dump_init() and
-     * dpif_flow_dump_thread_init(), respectively. */
-    struct dpif_flow_dump *(*flow_dump_create)(const struct dpif *dpif);
+     * dpif_flow_dump_thread_init(), respectively.
+     *
+     * 'dump_flags' is a bitmask of OVS_UID_F_* values which describe the
+     * behaviour for dumping flows. */
+    struct dpif_flow_dump *(*flow_dump_create)(const struct dpif *dpif,
+                                               uint32_t dump_flags);
     int (*flow_dump_destroy)(struct dpif_flow_dump *dump);
 
     struct dpif_flow_dump_thread *(*flow_dump_thread_create)(
diff --git a/lib/dpif.c b/lib/dpif.c
index b2a1972..b5b8ec9 100644
--- a/lib/dpif.c
+++ b/lib/dpif.c
@@ -87,6 +87,7 @@ static void log_flow_message(const struct dpif *dpif, int error,
                              const char *operation,
                              const struct nlattr *key, size_t key_len,
                              const struct nlattr *mask, size_t mask_len,
+                             const struct nlattr *uid, size_t uid_len,
                              const struct dpif_flow_stats *stats,
                              const struct nlattr *actions, size_t actions_len);
 static void log_operation(const struct dpif *, const char *operation,
@@ -835,6 +836,7 @@ dpif_flow_flush(struct dpif *dpif)
 int
 dpif_flow_get(struct dpif *dpif,
               const struct nlattr *key, size_t key_len,
+              const struct nlattr *uid, size_t uid_len,
               struct ofpbuf *buf, struct dpif_flow *flow)
 {
     struct dpif_op *opp;
@@ -843,7 +845,11 @@ dpif_flow_get(struct dpif *dpif,
     op.type = DPIF_OP_FLOW_GET;
     op.u.flow_get.key = key;
     op.u.flow_get.key_len = key_len;
+    op.u.flow_get.uid = uid;
+    op.u.flow_get.uid_len = uid_len;
     op.u.flow_get.buffer = buf;
+
+    memset(flow, 0, sizeof *flow);
     op.u.flow_get.flow = flow;
     op.u.flow_get.flow->key = key;
     op.u.flow_get.flow->key_len = key_len;
@@ -860,6 +866,7 @@ dpif_flow_put(struct dpif *dpif, enum dpif_flow_put_flags flags,
               const struct nlattr *key, size_t key_len,
               const struct nlattr *mask, size_t mask_len,
               const struct nlattr *actions, size_t actions_len,
+              const struct nlattr *uid, size_t uid_len,
               struct dpif_flow_stats *stats)
 {
     struct dpif_op *opp;
@@ -873,6 +880,8 @@ dpif_flow_put(struct dpif *dpif, enum dpif_flow_put_flags flags,
     op.u.flow_put.mask_len = mask_len;
     op.u.flow_put.actions = actions;
     op.u.flow_put.actions_len = actions_len;
+    op.u.flow_put.uid = uid;
+    op.u.flow_put.uid_len = uid_len;
     op.u.flow_put.stats = stats;
 
     opp = &op;
@@ -885,6 +894,7 @@ dpif_flow_put(struct dpif *dpif, enum dpif_flow_put_flags flags,
 int
 dpif_flow_del(struct dpif *dpif,
               const struct nlattr *key, size_t key_len,
+              const struct nlattr *uid, size_t uid_len,
               struct dpif_flow_stats *stats)
 {
     struct dpif_op *opp;
@@ -893,6 +903,8 @@ dpif_flow_del(struct dpif *dpif,
     op.type = DPIF_OP_FLOW_DEL;
     op.u.flow_del.key = key;
     op.u.flow_del.key_len = key_len;
+    op.u.flow_del.uid = uid;
+    op.u.flow_del.uid_len = uid_len;
     op.u.flow_del.stats = stats;
 
     opp = &op;
@@ -902,14 +914,15 @@ dpif_flow_del(struct dpif *dpif,
 }
 
 /* Creates and returns a new 'struct dpif_flow_dump' for iterating through the
- * flows in 'dpif'.
+ * flows in 'dpif'.  'dump_flags' is a bitmask of 'OVS_UID_F_*' flags that
+ * describes the behavior of the flow dump operation.
  *
  * This function always successfully returns a dpif_flow_dump.  Error
  * reporting is deferred to dpif_flow_dump_destroy(). */
 struct dpif_flow_dump *
-dpif_flow_dump_create(const struct dpif *dpif)
+dpif_flow_dump_create(const struct dpif *dpif, uint32_t dump_flags)
 {
-    return dpif->dpif_class->flow_dump_create(dpif);
+    return dpif->dpif_class->flow_dump_create(dpif, dump_flags);
 }
 
 /* Destroys 'dump', which must have been created with dpif_flow_dump_create().
@@ -974,7 +987,8 @@ dpif_flow_dump_next(struct dpif_flow_dump_thread *thread,
         for (f = flows; f < &flows[n] && should_log_flow_message(0); f++) {
             log_flow_message(dpif, 0, "flow_dump",
                              f->key, f->key_len, f->mask, f->mask_len,
-                             &f->stats, f->actions, f->actions_len);
+                             f->uid, f->uid_len, &f->stats,
+                             f->actions, f->actions_len);
         }
     } else {
         VLOG_DBG_RL(&dpmsg_rl, "%s: dumped all flows", dpif_name(dpif));
@@ -1454,6 +1468,7 @@ static void
 log_flow_message(const struct dpif *dpif, int error, const char *operation,
                  const struct nlattr *key, size_t key_len,
                  const struct nlattr *mask, size_t mask_len,
+                 const struct nlattr *uid, size_t uid_len,
                  const struct dpif_flow_stats *stats,
                  const struct nlattr *actions, size_t actions_len)
 {
@@ -1466,6 +1481,13 @@ log_flow_message(const struct dpif *dpif, int error, const char *operation,
     if (error) {
         ds_put_format(&ds, "(%s) ", ovs_strerror(error));
     }
+    if (uid) {
+        ovs_u128 hash;
+
+        odp_uid_from_nlattrs(uid, uid_len, &hash, NULL);
+        odp_format_uid(&hash, &ds);
+        ds_put_cstr(&ds, " ");
+    }
     odp_flow_format(key, key_len, mask, mask_len, NULL, &ds, true);
     if (stats) {
         ds_put_cstr(&ds, ", ");
@@ -1499,7 +1521,8 @@ log_flow_put_message(struct dpif *dpif, const struct dpif_flow_put *put,
         }
         log_flow_message(dpif, error, ds_cstr(&s),
                          put->key, put->key_len, put->mask, put->mask_len,
-                         put->stats, put->actions, put->actions_len);
+                         put->uid, put->uid_len, put->stats,
+                         put->actions, put->actions_len);
         ds_destroy(&s);
     }
 }
@@ -1510,7 +1533,8 @@ log_flow_del_message(struct dpif *dpif, const struct dpif_flow_del *del,
 {
     if (should_log_flow_message(error)) {
         log_flow_message(dpif, error, "flow_del", del->key, del->key_len,
-                         NULL, 0, !error ? del->stats : NULL, NULL, 0);
+                         NULL, 0, NULL, 0, !error ? del->stats : NULL,
+                         NULL, 0);
     }
 }
 
@@ -1565,7 +1589,7 @@ log_flow_get_message(const struct dpif *dpif, const struct dpif_flow_get *get,
         log_flow_message(dpif, error, "flow_get",
                          get->key, get->key_len,
                          get->flow->mask, get->flow->mask_len,
-                         &get->flow->stats,
+                         get->flow->uid, get->flow->uid_len, &get->flow->stats,
                          get->flow->actions, get->flow->actions_len);
     }
 }
diff --git a/lib/dpif.h b/lib/dpif.h
index be1bc4f..af09bbc 100644
--- a/lib/dpif.h
+++ b/lib/dpif.h
@@ -519,12 +519,16 @@ int dpif_flow_put(struct dpif *, enum dpif_flow_put_flags,
                   const struct nlattr *key, size_t key_len,
                   const struct nlattr *mask, size_t mask_len,
                   const struct nlattr *actions, size_t actions_len,
+                  const struct nlattr *uid, size_t uid_len,
                   struct dpif_flow_stats *);
+
 int dpif_flow_del(struct dpif *,
                   const struct nlattr *key, size_t key_len,
+                  const struct nlattr *uid, size_t uid_len,
                   struct dpif_flow_stats *);
 int dpif_flow_get(struct dpif *,
                   const struct nlattr *key, size_t key_len,
+                  const struct nlattr *uid, size_t uid_len,
                   struct ofpbuf *, struct dpif_flow *);
 
 /* Flow dumping interface
@@ -555,7 +559,8 @@ int dpif_flow_get(struct dpif *,
  *
  * All error reporting is deferred to the call to dpif_flow_dump_destroy().
  */
-struct dpif_flow_dump *dpif_flow_dump_create(const struct dpif *);
+struct dpif_flow_dump *dpif_flow_dump_create(const struct dpif *,
+                                             uint32_t dump_flags);
 int dpif_flow_dump_destroy(struct dpif_flow_dump *);
 
 struct dpif_flow_dump_thread *dpif_flow_dump_thread_create(
@@ -570,6 +575,8 @@ struct dpif_flow {
     size_t mask_len;              /* 'mask' length in bytes. */
     const struct nlattr *actions; /* Actions, as OVS_ACTION_ATTR_ */
     size_t actions_len;           /* 'actions' length in bytes. */
+    const struct nlattr *uid;     /* Unique flow identifier. */
+    size_t uid_len;               /* 'uid' length in bytes. */
     struct dpif_flow_stats stats; /* Flow statistics. */
 };
 int dpif_flow_dump_next(struct dpif_flow_dump_thread *,
@@ -621,6 +628,8 @@ struct dpif_flow_put {
     size_t mask_len;                /* Length of 'mask' in bytes. */
     const struct nlattr *actions;   /* Actions to perform on flow. */
     size_t actions_len;             /* Length of 'actions' in bytes. */
+    const struct nlattr *uid;       /* Unique flow identifier. */
+    size_t uid_len;                 /* Length of 'uid' in bytes. */
 
     /* Output. */
     struct dpif_flow_stats *stats;  /* Optional flow statistics. */
@@ -629,8 +638,17 @@ struct dpif_flow_put {
 /* Delete a flow.
  *
  * The flow is specified by the Netlink attributes with types OVS_KEY_ATTR_* in
- * the 'key_len' bytes starting at 'key'.  Succeeds with status 0 if the flow
- * is deleted, or fails with ENOENT if the dpif does not contain such a flow.
+ * the 'key_len' bytes starting at 'key', or the Netlink attributes with
+ * types OVS_UID_ATTR_* in the 'uid_len' bytes starting at 'uid'. At least one
+ * of 'key' or 'uid' must be specified. Succeeds with status 0 if the flow is
+ * deleted, or fails with ENOENT if the dpif does not contain such a flow.
+ *
+ * XXX: Current semantics are that if a datapath is set up with INDEX_BY_UID,
+ * it will only accept operations that have a UID specified (and reject others).
+ * However, UID is generated in the udpif and some users (eg ovs-dpctl) have no
+ * way of determining the UID from a flow. We could accept either, which would
+ * require datapaths to index by flow and by UID, or perhaps shift the UID
+ * down to the dpif layer.
  *
  * If the operation succeeds, then 'stats', if nonnull, will be set to the
  * flow's statistics before its deletion. */
@@ -638,6 +656,8 @@ struct dpif_flow_del {
     /* Input. */
     const struct nlattr *key;       /* Flow to delete. */
     size_t key_len;                 /* Length of 'key' in bytes. */
+    const struct nlattr *uid;       /* UID of flow to delete. */
+    size_t uid_len;                 /* Length of 'uid' in bytes. */
 
     /* Output. */
     struct dpif_flow_stats *stats;  /* Optional flow statistics. */
@@ -674,6 +694,8 @@ struct dpif_execute {
  * the 'key_len' bytes starting at 'key'. 'buffer' must point to an initialized
  * buffer, with a recommended size of DPIF_FLOW_BUFSIZE bytes.
  *
+ * XXX: See dpif_flow_del comment regarding UID.
+ *
  * On success, 'flow' will be populated with the mask, actions and stats for
  * the datapath flow corresponding to 'key'. The mask and actions may point
  * within '*buffer', or may point at RCU-protected data. Therefore, callers
@@ -687,6 +709,8 @@ struct dpif_flow_get {
     /* Input. */
     const struct nlattr *key;       /* Flow to get. */
     size_t key_len;                 /* Length of 'key' in bytes. */
+    const struct nlattr *uid;       /* UID of flow to get. */
+    size_t uid_len;                 /* Length of 'uid' in bytes. */
     struct ofpbuf *buffer;          /* Storage for output parameters. */
 
     /* Output. */
@@ -752,7 +776,8 @@ struct dpif_upcall {
  * wildcard mask suitable for that purpose into 'wc'.  If the actions to store
  * into the flow entry are the same as 'actions', then the callback may leave
  * 'put_actions' empty; otherwise it must store the desired actions into
- * 'put_actions'.
+ * 'put_actions'. The callback must fill in 'uid' with the userspace id
+ * corresponding to 'flow'.
  *
  * Returns 0 if successful, ENOSPC if the flow limit has been reached and no
  * flow should be installed, or some otherwise a positive errno value. */
@@ -762,6 +787,7 @@ typedef int upcall_callback(const struct ofpbuf *packet,
                             const struct nlattr *userdata,
                             struct ofpbuf *actions,
                             struct flow_wildcards *wc,
+                            ovs_u128 *uid,
                             struct ofpbuf *put_actions,
                             void *aux);
 
diff --git a/lib/odp-util.c b/lib/odp-util.c
index 8a96068..bc0ac4c 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -2898,6 +2898,57 @@ odp_flow_key_hash(const struct nlattr *key, size_t key_len)
                       key_len / sizeof(uint32_t), 0);
 }
 
+int
+odp_uid_from_nlattrs(const struct nlattr *nla, size_t nla_len, ovs_u128 *uid,
+                     uint32_t *flags)
+{
+    static const struct nl_policy ovs_uid_policy[] = {
+        [OVS_UID_ATTR_FLAGS] = { .type = NL_A_U32, .optional = true },
+        [OVS_UID_ATTR_ID] = { .type = NL_A_UNSPEC,
+                              .min_len = sizeof *uid }
+    };
+    struct nlattr *a[ARRAY_SIZE(ovs_uid_policy)];
+    const ovs_u128 *uidp;
+    struct ofpbuf buf;
+
+    if (!nla) {
+        return EINVAL;
+    }
+
+    ofpbuf_use_const(&buf, nla, nla_len);
+    if (!nl_policy_parse(&buf, 0, ovs_uid_policy, a, ARRAY_SIZE(a))) {
+        VLOG_WARN("Failed to parse UID_ATTRs (%p, len=%"PRIuSIZE")",
+                  nla, nla_len);
+        return EINVAL;
+    }
+
+    uidp = nl_attr_get_unspec(a[OVS_UID_ATTR_ID], sizeof *uid);
+    memcpy(uid, uidp, sizeof *uid);
+
+    if (flags && a[OVS_UID_ATTR_FLAGS]) {
+        *flags = nl_attr_get_u32(a[OVS_UID_ATTR_FLAGS]);
+    }
+    return 0;
+}
+
+void
+odp_uid_to_nlattrs(struct ofpbuf *buf, const ovs_u128 *uid, uint32_t flags)
+{
+    if (flags) {
+        nl_msg_put_u32(buf, OVS_UID_ATTR_FLAGS, flags);
+    }
+    if (uid) {
+        nl_msg_put_unspec(buf, OVS_UID_ATTR_ID, uid, sizeof *uid);
+    }
+}
+
+void
+odp_format_uid(const ovs_u128 *uid, struct ds *ds)
+{
+    ds_put_format(ds, "uid:%"PRIx32"%"PRIx32"%"PRIx32"%"PRIx32,
+                  uid->h[0], uid->h[1], uid->h[2], uid->h[3]);
+}
+
 static void
 log_odp_key_attributes(struct vlog_rate_limit *rl, const char *title,
                        uint64_t attrs, int out_of_range_attr,
diff --git a/lib/odp-util.h b/lib/odp-util.h
index b9b33e5..5cd71b0 100644
--- a/lib/odp-util.h
+++ b/lib/odp-util.h
@@ -134,6 +134,27 @@ struct odputil_keybuf {
     uint32_t keybuf[DIV_ROUND_UP(ODPUTIL_FLOW_KEY_BYTES, 4)];
 };
 
+/* The maximum number of bytes that odp_uid_from_uid() appends to a buffer.
+ * This is the upper bound on the length of a nlattr-formatted flow key that
+ * ovs-vswitchd fully understands.
+ *
+ * As with ODPUTIL_FLOW_KEY_BYTES, the datapath may have a different idea of a
+ * flow, so this isn't necessarily an upper bound on the length of a UID that
+ * the datapath can pass to ovs-vswitchd.
+ *
+ *                                     struct  pad  nl hdr  total
+ *                                     ------  ---  ------  -----
+ * OVS_UID_ATTR_FLAGS                     4     -      4      8
+ * OVS_UID_ATTR_UID                      16     -      4     20
+ *  ------------------------------------------------------------
+ *  total                                                    28
+ *
+ */
+#define ODPUTIL_FLOW_UID_BYTES 28
+struct odputil_uidbuf {
+    uint32_t uidbuf[DIV_ROUND_UP(ODPUTIL_FLOW_UID_BYTES, 4)];
+};
+
 enum odp_key_fitness odp_tun_key_from_attr(const struct nlattr *,
                                            struct flow_tnl *);
 
@@ -154,6 +175,8 @@ void odp_flow_key_from_mask(struct ofpbuf *, const struct flow *mask,
                             size_t max_mpls_depth, bool recirc);
 
 uint32_t odp_flow_key_hash(const struct nlattr *, size_t);
+void odp_uid_to_nlattrs(struct ofpbuf *, const ovs_u128 *, uint32_t flags);
+void odp_format_uid(const ovs_u128 *uid, struct ds *);
 
 /* Estimated space needed for metadata. */
 enum { ODP_KEY_METADATA_SIZE = 9 * 8 };
@@ -180,6 +203,8 @@ enum odp_key_fitness odp_flow_key_to_mask(const struct nlattr *key, size_t len,
                                           struct flow *mask,
                                           const struct flow *flow);
 const char *odp_key_fitness_to_string(enum odp_key_fitness);
+int odp_uid_from_nlattrs(const struct nlattr *, size_t,
+                         ovs_u128 *uid, uint32_t *flags);
 
 void commit_odp_tunnel_action(const struct flow *, struct flow *base,
                               struct ofpbuf *odp_actions);
diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c
index 50ae5c9..2369b0f 100644
--- a/ofproto/ofproto-dpif-upcall.c
+++ b/ofproto/ofproto-dpif-upcall.c
@@ -635,7 +635,8 @@ recv_upcalls(struct handler *handler)
                  * while traffic is being received.  Print a rate-limited
                  * message in case it happens frequently. */
                 dpif_flow_put(udpif->dpif, DPIF_FP_CREATE, dupcall->key,
-                              dupcall->key_len, NULL, 0, NULL, 0, NULL);
+                              dupcall->key_len, NULL, 0, NULL, 0, NULL, 0,
+                              NULL);
                 VLOG_INFO_RL(&rl, "received packet on unassociated datapath "
                              "port %"PRIu32, flow.in_port.odp_port);
             }
@@ -713,7 +714,7 @@ udpif_revalidator(void *arg)
 
             start_time = time_msec();
             if (!udpif->reval_exit) {
-                udpif->dump = dpif_flow_dump_create(udpif->dpif);
+                udpif->dump = dpif_flow_dump_create(udpif->dpif, 0);
             }
         }
 
@@ -953,7 +954,7 @@ upcall_uninit(struct upcall *upcall)
 static int
 upcall_cb(const struct ofpbuf *packet, const struct flow *flow,
           enum dpif_upcall_type type, const struct nlattr *userdata,
-          struct ofpbuf *actions, struct flow_wildcards *wc,
+          struct ofpbuf *actions, struct flow_wildcards *wc, ovs_u128 *uid,
           struct ofpbuf *put_actions, void *aux)
 {
     struct udpif *udpif = aux;
@@ -991,6 +992,11 @@ upcall_cb(const struct ofpbuf *packet, const struct flow *flow,
         }
     }
 
+    if (uid) {
+        memset(uid, 0, sizeof *uid);
+    }
+
+    atomic_read_relaxed(&udpif->flow_limit, &flow_limit);
     if (udpif_get_n_flows(udpif) >= flow_limit) {
         error = ENOSPC;
         goto out;
@@ -1220,7 +1226,7 @@ ukey_new(const struct udpif *udpif, struct upcall *upcall)
                                upcall->flow->in_port.odp_port, recirc);
     }
 
-    atomic_read(&enable_megaflows, &megaflow);
+    atomic_read_relaxed(&enable_megaflows, &megaflow);
     ofpbuf_use_stack(&mask, &ukey->maskbuf, sizeof ukey->maskbuf);
     if (megaflow) {
         size_t max_mpls;
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index a635ca6..565330a 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -965,7 +965,7 @@ check_recirc(struct dpif_backer *backer)
 
     error = dpif_flow_put(backer->dpif, DPIF_FP_CREATE,
                           ofpbuf_data(&key), ofpbuf_size(&key), NULL, 0, NULL,
-                          0, NULL);
+                          0, NULL, 0, NULL);
     if (error && error != EEXIST) {
         if (error != EINVAL) {
             VLOG_WARN("%s: Reciculation flow probe failed (%s)",
@@ -975,7 +975,7 @@ check_recirc(struct dpif_backer *backer)
     }
 
     error = dpif_flow_del(backer->dpif, ofpbuf_data(&key), ofpbuf_size(&key),
-                          NULL);
+                          NULL, 0, NULL);
     if (error) {
         VLOG_WARN("%s: failed to delete recirculation feature probe flow",
                   dpif_name(backer->dpif));
@@ -1092,7 +1092,8 @@ check_max_mpls_depth(struct dpif_backer *backer)
         odp_flow_key_from_flow(&key, &flow, NULL, 0, false);
 
         error = dpif_flow_put(backer->dpif, DPIF_FP_CREATE,
-                              ofpbuf_data(&key), ofpbuf_size(&key), NULL, 0, NULL, 0, NULL);
+                              ofpbuf_data(&key), ofpbuf_size(&key), NULL, 0,
+                              NULL, 0, NULL, 0, NULL);
         if (error && error != EEXIST) {
             if (error != EINVAL) {
                 VLOG_WARN("%s: MPLS stack length feature probe failed (%s)",
@@ -1101,7 +1102,9 @@ check_max_mpls_depth(struct dpif_backer *backer)
             break;
         }
 
-        error = dpif_flow_del(backer->dpif, ofpbuf_data(&key), ofpbuf_size(&key), NULL);
+        error = dpif_flow_del(backer->dpif,
+                              ofpbuf_data(&key), ofpbuf_size(&key),
+                              NULL, 0, NULL);
         if (error) {
             VLOG_WARN("%s: failed to delete MPLS feature probe flow",
                       dpif_name(backer->dpif));
@@ -4632,7 +4635,7 @@ ofproto_unixctl_dpif_dump_flows(struct unixctl_conn *conn,
     }
 
     ds_init(&ds);
-    flow_dump = dpif_flow_dump_create(ofproto->backer->dpif);
+    flow_dump = dpif_flow_dump_create(ofproto->backer->dpif, 0);
     flow_dump_thread = dpif_flow_dump_thread_create(flow_dump);
     while (dpif_flow_dump_next(flow_dump_thread, &f, 1)) {
         struct flow flow;
-- 
1.7.10.4




More information about the dev mailing list