@@ -852,63 +852,246 @@ static int
dpif_hw_netlink_flow_flush(struct dpif *dpif_)
{
struct dpif_hw_netlink *dpif = dpif_hw_netlink_cast(dpif_);
+ struct port_netdev_hash_data *data;
+ VLOG_DBG("%s %d %s, (%p) flush start\n", __FILE__, __LINE__, __func__,
+ dpif);
+ HMAP_FOR_EACH(data, node, &dpif->port_to_netdev) {
+ if (data->netdev) {
+ VLOG_DBG("%s %d %s, (%p) flusing port: %d, netdev: %p\n", __FILE__,
+ __LINE__, __func__, dpif, data->port, data->netdev);
+ tc_flush_flower(netdev_get_ifindex(data->netdev));
+ }
+ }
+
+ VLOG_DBG("%s %d %s, (%p) flush end\n", __FILE__, __LINE__, __func__, dpif);
return dpif->lp_dpif_netlink->dpif_class->
flow_flush(dpif->lp_dpif_netlink);
}
+struct dpif_hw_netlink_flow_dump {
+ struct dpif_flow_dump up;
+ struct dpif_flow_dump *netlink_dump;
+ struct nl_dump *flow_dumps;
+ int num_dumps;
+ int given;
+ struct ovs_mutex lock;
+ odp_port_t ports[10];
+ struct netdev *netdevs[10];
+};
+
+static struct dpif_hw_netlink_flow_dump *
+dpif_hw_netlink_flow_dump_cast(struct dpif_flow_dump *dump)
+{
+ return CONTAINER_OF(dump, struct dpif_hw_netlink_flow_dump, up);
+}
+
static struct dpif_flow_dump *
dpif_hw_netlink_flow_dump_create(const struct dpif *dpif_, bool terse)
{
- struct dpif_flow_dump *dump;
+ struct dpif_hw_netlink_flow_dump *dump;
struct dpif_hw_netlink *dpif = dpif_hw_netlink_cast(dpif_);
+ struct nl_dump *flow_dumps = 0;
+ int count = 0;
- dump =
- dpif->lp_dpif_netlink->dpif_class->
- flow_dump_create(dpif->lp_dpif_netlink, terse);
- dump->dpif = CONST_CAST(struct dpif *, dpif_);
+ int num_ports = hmap_count(&dpif->port_to_netdev);
+
+ dump = xmalloc(sizeof *dump);
+ dpif_flow_dump_init(&dump->up, dpif_);
+ dump->up.terse = terse;
- return dump;
+ if (num_ports) {
+ flow_dumps = xmalloc(sizeof (struct nl_dump) * num_ports);
+ struct port_netdev_hash_data *data;
+
+ HMAP_FOR_EACH(data, node, &dpif->port_to_netdev) {
+ if (data->netdev) {
+ dump->ports[count] = data->port;
+ dump->netdevs[count] = data->netdev;
+
+ tc_dump_flower_start(netdev_get_ifindex(data->netdev),
+ &flow_dumps[count]);
+ count++;
+ }
+ }
+ }
+
+ dump->netlink_dump =
+ dpif->lp_dpif_netlink->dpif_class->
+ flow_dump_create(dpif->lp_dpif_netlink, terse);
+ dump->flow_dumps = flow_dumps;
+ dump->num_dumps = count;
+ dump->given = 0;
+ ovs_mutex_init(&dump->lock);
+ return &dump->up;
}
static int
dpif_hw_netlink_flow_dump_destroy(struct dpif_flow_dump *dump_)
{
+ int error;
+ struct dpif_hw_netlink_flow_dump *dump =
+ dpif_hw_netlink_flow_dump_cast(dump_);
struct dpif_hw_netlink *dpif = dpif_hw_netlink_cast(dump_->dpif);
- dump_->dpif = dpif->lp_dpif_netlink;
- return dpif->lp_dpif_netlink->dpif_class->flow_dump_destroy(dump_);
+ int cur = 0;
+
+ for (cur = 0; cur < dump->num_dumps; cur++) {
+ struct nl_dump *nl_dump = &dump->flow_dumps[cur];
+
+ int ret = nl_dump_done(nl_dump);
+
+ if (ret != 0)
+ VLOG_ERR("nl_dump_done error ret[%d]: %d\n", cur, ret);
+ }
+
+ error =
+ dpif->lp_dpif_netlink->dpif_class->
+ flow_dump_destroy(dump->netlink_dump);
+
+ if (dump->flow_dumps)
+ free(dump->flow_dumps);
+ free(dump);
+
+ return error;
+}
+
+struct dpif_hw_netlink_flow_dump_thread {
+ struct dpif_flow_dump_thread up;
+ struct dpif_flow_dump_thread *netlink_thread;
+ struct dpif_hw_netlink_flow_dump *dump;
+ struct ofpbuf nl_flows;
+ struct ofpbuf temp_buf;
+ int current_dump;
+ int flower_done;
+};
+
+static void
+dpif_hw_netlink_get_next_dump(struct dpif_hw_netlink_flow_dump_thread *thread)
+{
+ /* TODO:Consider changing to a atomc dump->given... */
+
+ struct dpif_hw_netlink_flow_dump *dump = thread->dump;
+
+ ovs_mutex_lock(&dump->lock);
+ /* if we haven't finished (dumped everything) */
+ if (dump->given < dump->num_dumps) {
+ /* if we are the first to find that given dump is finished (for race
+ * condition, e.g 3 finish dump 0 at the same time) */
+ if (thread->current_dump == dump->given) {
+ thread->current_dump = ++dump->given;
+ /* did we just finish the last dump? done. */
+ if (dump->given == dump->num_dumps) {
+ thread->flower_done = 1;
+ }
+ } else
+ /* otherwise, we are behind, catch up */
+ thread->current_dump = dump->given;
+ } else {
+ /* some other thread finished */
+ thread->flower_done = 1;
+ }
+ ovs_mutex_unlock(&dump->lock);
}
static struct dpif_flow_dump_thread *
dpif_hw_netlink_flow_dump_thread_create(struct dpif_flow_dump *dump_)
{
+ struct dpif_hw_netlink_flow_dump *dump =
+ dpif_hw_netlink_flow_dump_cast(dump_);
struct dpif_hw_netlink *dpif = dpif_hw_netlink_cast(dump_->dpif);
+ struct dpif_hw_netlink_flow_dump_thread *thread;
- return dpif->lp_dpif_netlink->dpif_class->flow_dump_thread_create(dump_);
+ thread = xmalloc(sizeof *thread);
+ dpif_flow_dump_thread_init(&thread->up, &dump->up);
+ thread->netlink_thread =
+ dpif->lp_dpif_netlink->dpif_class->
+ flow_dump_thread_create(dump->netlink_dump);
+ thread->dump = dump;
+
+ /*
+ * A thread can be created at any time,
+ * so another thread might finish the dump already (and advance dump->given),
+ * so we might be done before we even started.
+ */
+
+ ovs_mutex_lock(&dump->lock);
+ thread->current_dump = dump->given;
+ thread->flower_done = dump->given < dump->num_dumps ? 0 : 1;
+ ovs_mutex_unlock(&dump->lock);
+
+ if (!thread->flower_done) {
+ ofpbuf_init(&thread->nl_flows, NL_DUMP_BUFSIZE); /* TODO:
+ * uninit
+ * where? */
+ ofpbuf_init(&thread->temp_buf, NL_DUMP_BUFSIZE);
+ }
+ /* another option is setting current to -1, and calling get_next_dump, but
+ * its kinda ugly */
+ return &thread->up;
}
+static struct dpif_hw_netlink_flow_dump_thread *
+dpif_hw_netlink_flow_dump_thread_cast(struct dpif_flow_dump_thread *thread)
+{
+ return CONTAINER_OF(thread, struct dpif_hw_netlink_flow_dump_thread, up);
+}
+
static void
dpif_hw_netlink_flow_dump_thread_destroy(struct dpif_flow_dump_thread *thread_)
{
struct dpif_hw_netlink *dpif = dpif_hw_netlink_cast(thread_->dpif);
+ struct dpif_hw_netlink_flow_dump_thread *thread
+ = dpif_hw_netlink_flow_dump_thread_cast(thread_);
+
+ dpif->lp_dpif_netlink->dpif_class->
+ flow_dump_thread_destroy(thread->netlink_thread);
- thread_->dpif = dpif->lp_dpif_netlink;
- return dpif->lp_dpif_netlink->
- dpif_class->flow_dump_thread_destroy(thread_);
+ free(thread);
}
static int
dpif_hw_netlink_flow_dump_next(struct dpif_flow_dump_thread *thread_,
struct dpif_flow *flows, int max_flows)
{
- struct dpif_hw_netlink *dpif = dpif_hw_netlink_cast(thread_->dpif);
+ struct dpif_hw_netlink_flow_dump_thread *thread
+ = dpif_hw_netlink_flow_dump_thread_cast(thread_);
+ struct dpif_hw_netlink_flow_dump *dump = thread->dump;
+ struct dpif_hw_netlink *dpif = dpif_hw_netlink_cast(thread->up.dpif);
+ int n_flows = 0;
+
+ while (!thread->flower_done && n_flows < max_flows) {
+ int cur = thread->current_dump;
+ odp_port_t inport = dump->ports[cur];
+ struct netdev *indev = dump->netdevs[cur];
+ struct ofpbuf nl_flow;
+ struct nl_dump *nl_dump = &dump->flow_dumps[cur];
+
+ if (nl_dump_next(nl_dump, &nl_flow, &thread->nl_flows)) {
+ struct tc_flow tc_flow;
+
+ if (parse_tc_flow(&nl_flow, &tc_flow))
+ continue;
+
+ /* if we got handle, convert netlink flow to dpif_flow */
+ if (tc_flow.handle)
+ dpif_hw_tc_flow_to_dpif_flow(dpif, &tc_flow, &flows[n_flows++],
+ inport, &thread->temp_buf, indev);
+ } else
+ dpif_hw_netlink_get_next_dump(thread);
+ }
- thread_->dpif = dpif->lp_dpif_netlink;
- return dpif->lp_dpif_netlink->dpif_class->flow_dump_next(thread_, flows,
- max_flows);
+ /* if we got here, flower done or got to max flows if flow done and not
+ * got got max, call kernel datapath to dump remaining flows */
+ if (thread->flower_done && n_flows < max_flows) {
+ return n_flows +
+ dpif->lp_dpif_netlink->dpif_class->
+ flow_dump_next(thread->netlink_thread, flows + n_flows,
+ max_flows - n_flows);
+ }
+ return n_flows;
}
static bool