+static void
+dpctl_put_flow(int argc, char *argv[], enum dpif_flow_put_flags flags)
+{
+ const char *key_s = argv[argc - 2];
+ const char *actions_s = argv[argc - 1];
+ struct dpif_flow_stats stats;
+ struct ofpbuf actions;
+ struct ofpbuf key;
+ struct dpif *dpif;
+ char *dp_name;
+
+ ofpbuf_init(&key, 0);
+ run(odp_flow_key_from_string(key_s, NULL, &key), "parsing flow key");
+
+ ofpbuf_init(&actions, 0);
+ run(odp_actions_from_string(actions_s, NULL, &actions), "parsing actions");
+
+ dp_name = argc == 3 ? xstrdup(argv[1]) : get_one_dp();
+ run(parsed_dpif_open(dp_name, false, &dpif), "opening datapath");
+ free(dp_name);
+
+ run(dpif_flow_put(dpif, flags,
+ key.data, key.size,
+ actions.data, actions.size,
+ print_statistics ? &stats : NULL),
+ "updating flow table");
+
+ ofpbuf_uninit(&key);
+ ofpbuf_uninit(&actions);
+
+ if (print_statistics) {
+ struct ds s;
+
+ ds_init(&s);
+ dpif_flow_stats_format(&stats, &s);
+ puts(ds_cstr(&s));
+ ds_destroy(&s);
+ }
+}
+
+static void
+dpctl_add_flow(int argc, char *argv[])
+{
+ dpctl_put_flow(argc, argv, DPIF_FP_CREATE);
+}
+
+static void
+dpctl_mod_flow(int argc OVS_UNUSED, char *argv[])
+{
+ enum dpif_flow_put_flags flags;
+
+ flags = DPIF_FP_MODIFY;
+ if (may_create) {
+ flags |= DPIF_FP_CREATE;
+ }
+ if (zero_statistics) {
+ flags |= DPIF_FP_ZERO_STATS;
+ }
+
+ dpctl_put_flow(argc, argv, flags);
+}
+
+static void
+dpctl_del_flow(int argc, char *argv[])
+{
+ const char *key_s = argv[argc - 1];
+ struct dpif_flow_stats stats;
+ struct ofpbuf key;
+ struct dpif *dpif;
+ char *dp_name;
+
+ ofpbuf_init(&key, 0);
+ run(odp_flow_key_from_string(key_s, NULL, &key), "parsing flow key");
+
+ dp_name = argc == 2 ? xstrdup(argv[1]) : get_one_dp();
+ run(parsed_dpif_open(dp_name, false, &dpif), "opening datapath");
+ free(dp_name);
+
+ run(dpif_flow_del(dpif,
+ key.data, key.size,
+ print_statistics ? &stats : NULL), "deleting flow");
+
+ ofpbuf_uninit(&key);
+
+ if (print_statistics) {
+ struct ds s;
+
+ ds_init(&s);
+ dpif_flow_stats_format(&stats, &s);
+ puts(ds_cstr(&s));
+ ds_destroy(&s);
+ }
+}
+