+ if (!error) {
+ VLOG_DBG_RL(&dpmsg_rl, "%s: %s success", dpif_name(dpif), operation);
+ } else if (ofperr_is_valid(error)) {
+ VLOG_WARN_RL(&error_rl, "%s: %s failed (%s)",
+ dpif_name(dpif), operation, ofperr_get_name(error));
+ } else {
+ VLOG_WARN_RL(&error_rl, "%s: %s failed (%s)",
+ dpif_name(dpif), operation, ovs_strerror(error));
+ }
+}
+
+static enum vlog_level
+flow_message_log_level(int error)
+{
+ /* If flows arrive in a batch, userspace may push down multiple
+ * unique flow definitions that overlap when wildcards are applied.
+ * Kernels that support flow wildcarding will reject these flows as
+ * duplicates (EEXIST), so lower the log level to debug for these
+ * types of messages. */
+ return (error && error != EEXIST) ? VLL_WARN : VLL_DBG;
+}
+
+static bool
+should_log_flow_message(int error)
+{
+ return !vlog_should_drop(THIS_MODULE, flow_message_log_level(error),
+ error ? &error_rl : &dpmsg_rl);
+}
+
+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 dpif_flow_stats *stats,
+ const struct nlattr *actions, size_t actions_len)
+{
+ struct ds ds = DS_EMPTY_INITIALIZER;
+ ds_put_format(&ds, "%s: ", dpif_name(dpif));
+ if (error) {
+ ds_put_cstr(&ds, "failed to ");
+ }
+ ds_put_format(&ds, "%s ", operation);
+ if (error) {
+ ds_put_format(&ds, "(%s) ", ovs_strerror(error));
+ }
+ odp_flow_format(key, key_len, mask, mask_len, NULL, &ds, true);
+ if (stats) {
+ ds_put_cstr(&ds, ", ");
+ dpif_flow_stats_format(stats, &ds);
+ }
+ if (actions || actions_len) {
+ ds_put_cstr(&ds, ", actions:");
+ format_odp_actions(&ds, actions, actions_len);
+ }
+ vlog(THIS_MODULE, flow_message_log_level(error), "%s", ds_cstr(&ds));
+ ds_destroy(&ds);
+}
+
+static void
+log_flow_put_message(struct dpif *dpif, const struct dpif_flow_put *put,
+ int error)
+{
+ if (should_log_flow_message(error)) {
+ struct ds s;
+
+ ds_init(&s);
+ ds_put_cstr(&s, "put");
+ if (put->flags & DPIF_FP_CREATE) {
+ ds_put_cstr(&s, "[create]");
+ }
+ if (put->flags & DPIF_FP_MODIFY) {
+ ds_put_cstr(&s, "[modify]");
+ }
+ if (put->flags & DPIF_FP_ZERO_STATS) {
+ ds_put_cstr(&s, "[zero]");
+ }
+ 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);
+ ds_destroy(&s);
+ }
+}
+
+static void
+log_flow_del_message(struct dpif *dpif, const struct dpif_flow_del *del,
+ int error)
+{
+ 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);
+ }
+}
+
+static void
+log_execute_message(struct dpif *dpif, const struct dpif_execute *execute,
+ int error)
+{
+ if (!(error ? VLOG_DROP_WARN(&error_rl) : VLOG_DROP_DBG(&dpmsg_rl))) {
+ struct ds ds = DS_EMPTY_INITIALIZER;
+ char *packet;
+
+ packet = ofp_packet_to_string(ofpbuf_data(execute->packet),
+ ofpbuf_size(execute->packet));
+ ds_put_format(&ds, "%s: execute ", dpif_name(dpif));
+ format_odp_actions(&ds, execute->actions, execute->actions_len);
+ if (error) {
+ ds_put_format(&ds, " failed (%s)", ovs_strerror(error));
+ }
+ ds_put_format(&ds, " on packet %s", packet);
+ vlog(THIS_MODULE, error ? VLL_WARN : VLL_DBG, "%s", ds_cstr(&ds));
+ ds_destroy(&ds);
+ free(packet);