added support dump flows from tc. Signed-off-by: Paul Blakey <pa...@mellanox.com> Signed-off-by: Shahar Klein <shah...@mellanox.com> --- lib/dpif-hw-netlink.c | 215 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 199 insertions(+), 16 deletions(-)
diff --git a/lib/dpif-hw-netlink.c b/lib/dpif-hw-netlink.c index 9473832..663b15b 100644 --- a/lib/dpif-hw-netlink.c +++ b/lib/dpif-hw-netlink.c @@ -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 -- 1.8.3.1 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev