+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 dpif_port dpif_port;
+ struct dpif_port_dump port_dump;
+ struct ofpbuf actions;
+ struct ofpbuf key;
+ struct ofpbuf mask;
+ struct dpif *dpif;
+ struct ds s;
+ char *dp_name;
+ struct simap port_names;
+
+ dp_name = argc == 4 ? xstrdup(argv[1]) : get_one_dp();
+ run(parsed_dpif_open(dp_name, false, &dpif), "opening datapath");
+ free(dp_name);
+
+
+ simap_init(&port_names);
+ DPIF_PORT_FOR_EACH (&dpif_port, &port_dump, dpif) {
+ simap_put(&port_names, dpif_port.name, odp_to_u32(dpif_port.port_no));
+ }
+
+ ds_init(&s);
+ ofpbuf_init(&key, 0);
+ ofpbuf_init(&mask, 0);
+ run(odp_flow_from_string(key_s, &port_names, &key, &mask),
+ "parsing flow key");
+
+ simap_destroy(&port_names);
+
+ ofpbuf_init(&actions, 0);
+ run(odp_actions_from_string(actions_s, NULL, &actions), "parsing actions");
+
+ run(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),
+ print_statistics ? &stats : NULL),
+ "updating flow table");
+
+ ofpbuf_uninit(&key);
+ ofpbuf_uninit(&mask);
+ 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 dpif_port dpif_port;
+ struct dpif_port_dump port_dump;
+ struct ofpbuf key;
+ struct ofpbuf mask; /* To be ignored. */
+ struct dpif *dpif;
+ char *dp_name;
+ struct simap port_names;
+
+ dp_name = argc == 3 ? xstrdup(argv[1]) : get_one_dp();
+ run(parsed_dpif_open(dp_name, false, &dpif), "opening datapath");
+ free(dp_name);
+
+ simap_init(&port_names);
+ DPIF_PORT_FOR_EACH (&dpif_port, &port_dump, dpif) {
+ simap_put(&port_names, dpif_port.name, odp_to_u32(dpif_port.port_no));
+ }
+
+ ofpbuf_init(&key, 0);
+ ofpbuf_init(&mask, 0);
+ run(odp_flow_from_string(key_s, &port_names, &key, &mask), "parsing flow key");
+
+ run(dpif_flow_del(dpif,
+ ofpbuf_data(&key), ofpbuf_size(&key),
+ print_statistics ? &stats : NULL), "deleting flow");
+
+ simap_destroy(&port_names);
+ ofpbuf_uninit(&key);
+ ofpbuf_uninit(&mask);
+
+ if (print_statistics) {
+ struct ds s;
+
+ ds_init(&s);
+ dpif_flow_stats_format(&stats, &s);
+ puts(ds_cstr(&s));
+ ds_destroy(&s);
+ }
+}
+