+ /* Packet classification. */
+ const struct cls_rule cr; /* In owning dp_netdev's 'cls'. */
+
+ /* Hash table index by unmasked flow. */
+ const struct hmap_node node; /* In owning dp_netdev's 'flow_table'. */
+ const struct flow flow; /* The flow that created this entry. */
+
+ /* Protects members marked OVS_GUARDED.
+ *
+ * Acquire after datapath's flow_mutex. */
+ struct ovs_mutex mutex OVS_ACQ_AFTER(dp_netdev_mutex);
+
+ /* Statistics.
+ *
+ * Reading or writing these members requires 'mutex'. */
+ struct ovsthread_stats stats; /* Contains "struct dp_netdev_flow_stats". */
+
+ /* Actions.
+ *
+ * Reading 'actions' requires 'mutex'.
+ * Writing 'actions' requires 'mutex' and (to allow for transactions) the
+ * datapath's flow_mutex. */
+ OVSRCU_TYPE(struct dp_netdev_actions *) actions;
+};
+
+static void dp_netdev_flow_free(struct dp_netdev_flow *);
+
+/* Contained by struct dp_netdev_flow's 'stats' member. */
+struct dp_netdev_flow_stats {
+ struct ovs_mutex mutex; /* Guards all the other members. */
+
+ long long int used OVS_GUARDED; /* Last used time, in monotonic msecs. */
+ long long int packet_count OVS_GUARDED; /* Number of packets matched. */
+ long long int byte_count OVS_GUARDED; /* Number of bytes matched. */
+ uint16_t tcp_flags OVS_GUARDED; /* Bitwise-OR of seen tcp_flags values. */
+};
+
+/* A set of datapath actions within a "struct dp_netdev_flow".
+ *
+ *
+ * Thread-safety
+ * =============
+ *
+ * A struct dp_netdev_actions 'actions' may be accessed without a risk of being
+ * freed by code that holds a read-lock or write-lock on 'flow->mutex' (where
+ * 'flow' is the dp_netdev_flow for which 'flow->actions == actions') or that
+ * owns a reference to 'actions->ref_cnt' (or both). */
+struct dp_netdev_actions {
+ /* These members are immutable: they do not change during the struct's
+ * lifetime. */
+ struct nlattr *actions; /* Sequence of OVS_ACTION_ATTR_* attributes. */
+ unsigned int size; /* Size of 'actions', in bytes. */
+};
+
+struct dp_netdev_actions *dp_netdev_actions_create(const struct nlattr *,
+ size_t);
+struct dp_netdev_actions *dp_netdev_flow_get_actions(
+ const struct dp_netdev_flow *);
+static void dp_netdev_actions_free(struct dp_netdev_actions *);
+
+/* PMD: Poll modes drivers. PMD accesses devices via polling to eliminate
+ * the performance overhead of interrupt processing. Therefore netdev can
+ * not implement rx-wait for these devices. dpif-netdev needs to poll
+ * these device to check for recv buffer. pmd-thread does polling for
+ * devices assigned to itself thread.
+ *
+ * DPDK used PMD for accessing NIC.
+ *
+ * A thread that receives packets from PMD ports, looks them up in the flow
+ * table, and executes the actions it finds.
+ **/
+struct pmd_thread {
+ struct dp_netdev *dp;
+ pthread_t thread;
+ int id;
+ atomic_uint change_seq;
+ char *name;