diff mbox series

[ovs-dev,29/62] dpif-netdev: try to offload flow after dpcls_lookup

Message ID 20201228092520.11807-30-taoyunxiang@cmss.chinamobile.com
State Not Applicable
Headers show
Series DPDK Offload API to test | expand

Commit Message

Tao YunXiang Dec. 28, 2020, 9:24 a.m. UTC
From: Rongyin <rongyin@cmss.chinamobile.com>

The original netdev datapath offload mechanism is based on mega_ufid,
But Intel FPGA card only support exact match, so there is a so called
"wildcard" situation when the pkt miss FPGA table search and slow path
EMC cache search but hit in dpcls cache. As for original offload mechanism,
we won't try to offload such flows(as the mega_ufid is the same as before)
This patch tries to use ufid instead of mega_ufid during offloading. So
the original megaufid_to_mark and flow_to_mark mapping can be kept.

Also as for flows that has been offloaded but failed, we won't waste effort
to offload that flow again. So a offload_fail status flag is added in
megaufid_to_mark mapping. Before append offload list, we should try to
check this flag.

This patch changed offloading mechanism, should be considered carefully,
and task more tests.

Code Source From: Self Code

Description:

     see above

Jira:  #[Optional]
市场项目编号(名称):[Optional]
---
 lib/dpif-netdev.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 100 insertions(+), 12 deletions(-)
diff mbox series

Patch

diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 008ffa8..db28b88 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -2155,6 +2155,7 @@  struct megaflow_to_mark_data {
     const struct cmap_node node;
     ovs_u128 mega_ufid;
     uint32_t mark;
+    bool offload_failed; /* indicate if this ufid has been offloaded fail */
 };
 
 struct flow_mark {
@@ -2193,13 +2194,15 @@  flow_mark_free(uint32_t mark)
 
 /* associate megaflow with a mark, which is a 1:1 mapping */
 static void
-megaflow_to_mark_associate(const ovs_u128 *mega_ufid, uint32_t mark)
+megaflow_to_mark_associate(const ovs_u128 *mega_ufid, uint32_t mark,
+                           bool offload_failed)
 {
     size_t hash = dp_netdev_flow_hash(mega_ufid);
     struct megaflow_to_mark_data *data = xzalloc(sizeof(*data));
 
     data->mega_ufid = *mega_ufid;
     data->mark = mark;
+    data->offload_failed = offload_failed;
 
     cmap_insert(&flow_mark.megaflow_to_mark,
                 CONST_CAST(struct cmap_node *, &data->node), hash);
@@ -2242,6 +2245,23 @@  megaflow_to_mark_find(const ovs_u128 *mega_ufid)
     return INVALID_FLOW_MARK;
 }
 
+static inline bool
+megaflow_to_offload_st_find(const ovs_u128 *mega_ufid)
+{
+    size_t hash = dp_netdev_flow_hash(mega_ufid);
+    struct megaflow_to_mark_data *data;
+
+    CMAP_FOR_EACH_WITH_HASH (data, node, hash, &flow_mark.megaflow_to_mark) {
+        if (ovs_u128_equals(*mega_ufid, data->mega_ufid)) {
+            return data->offload_failed;
+        }
+    }
+
+    VLOG_DBG("Offload status of Mark id for ufid "UUID_FMT" was not found \n",
+             UUID_ARGS((struct uuid *)mega_ufid));
+    return false;
+}
+
 /* associate mark with a flow, which is 1:N mapping */
 static void
 mark_to_flow_associate(const uint32_t mark, struct dp_netdev_flow *flow)
@@ -2297,7 +2317,7 @@  mark_to_flow_disassociate(struct dp_netdev_pmd_thread *pmd,
             /* Taking a global 'port_mutex' to fulfill thread safety
              * restrictions for the netdev-offload-dpdk module. */
             ovs_mutex_lock(&pmd->dp->port_mutex);
-            ret = netdev_flow_del(port, &flow->mega_ufid, NULL);
+            ret = netdev_flow_del(port, &flow->ufid, NULL);
             ovs_mutex_unlock(&pmd->dp->port_mutex);
             netdev_close(port);
         }
@@ -2305,7 +2325,7 @@  mark_to_flow_disassociate(struct dp_netdev_pmd_thread *pmd,
         flow_mark_free(mark);
         VLOG_DBG("Freed flow mark %u\n", mark);
 
-        megaflow_to_mark_disassociate(&flow->mega_ufid);
+        megaflow_to_mark_disassociate(&flow->ufid);
     }
     dp_netdev_flow_unref(flow);
 
@@ -2420,7 +2440,10 @@  dp_netdev_flow_offload_put(struct dp_flow_offload_item *offload)
          * If a mega flow has already been offloaded (from other PMD
          * instances), do not offload it again.
          */
-        mark = megaflow_to_mark_find(&flow->mega_ufid);
+        mark = megaflow_to_mark_find(&flow->ufid);
+        if (megaflow_to_offload_st_find(&flow->ufid) == true) {
+            return -1;
+        }
         if (mark != INVALID_FLOW_MARK) {
             VLOG_DBG("Flow has already been offloaded with mark %u\n", mark);
             if (flow->mark != INVALID_FLOW_MARK) {
@@ -2448,7 +2471,7 @@  dp_netdev_flow_offload_put(struct dp_flow_offload_item *offload)
     ovs_mutex_lock(&pmd->dp->port_mutex);
     ret = netdev_flow_put(port, &offload->match,
                           CONST_CAST(struct nlattr *, offload->actions),
-                          offload->actions_len, &flow->mega_ufid, &info,
+                          offload->actions_len, &flow->ufid, &info,
                           NULL);
     ovs_mutex_unlock(&pmd->dp->port_mutex);
     netdev_close(port);
@@ -2458,14 +2481,25 @@  dp_netdev_flow_offload_put(struct dp_flow_offload_item *offload)
     }
 
     if (!modification) {
-        megaflow_to_mark_associate(&flow->mega_ufid, mark);
+        megaflow_to_mark_associate(&flow->ufid, mark,false);
         mark_to_flow_associate(mark, flow);
+        VLOG_DBG("TIMO DBG: associate ufid with st false");
+        VLOG_DBG("TIMO DBG: ufid:"UUID_FMT" mark:%u \n",
+              UUID_ARGS((struct uuid *)&flow->ufid),mark);
     }
     return 0;
 
 err_free:
     if (!modification) {
-        flow_mark_free(mark);
+        /*flow_mark_free(mark);*/
+        /* If offloaded fail, also generate ufid->mark mapping
+         * we waste some mark values in pool , but can get offload
+         * status
+         */
+        megaflow_to_mark_associate(&flow->ufid, mark,true);
+        VLOG_DBG("TIMO DBG: associate ufid with st true");
+        VLOG_DBG("TIMO DBG: ufid:"UUID_FMT" mark:%u \n",
+              UUID_ARGS((struct uuid *)&flow->ufid),mark);
     } else {
         mark_to_flow_disassociate(pmd, flow);
     }
@@ -3060,7 +3094,7 @@  dpif_netdev_get_flow_offload_status(const struct dp_netdev *dp,
     /* Taking a global 'port_mutex' to fulfill thread safety
      * restrictions for the netdev-offload-dpdk module. */
     ovs_mutex_lock(&dp->port_mutex);
-    ret = netdev_flow_get(netdev, &match, &actions, &netdev_flow->mega_ufid,
+    ret = netdev_flow_get(netdev, &match, &actions, &netdev_flow->ufid,
                           stats, attrs, &buf);
     ovs_mutex_unlock(&dp->port_mutex);
     netdev_close(netdev);
@@ -3362,7 +3396,10 @@  dp_netdev_flow_add(struct dp_netdev_pmd_thread *pmd,
     cmap_insert(&pmd->flow_table, CONST_CAST(struct cmap_node *, &flow->node),
                 dp_netdev_flow_hash(&flow->ufid));
 
-    queue_netdev_flow_put(pmd, flow, match, actions, actions_len);
+    /*Don't try to offload flows that has been offloaded failed */
+    if (megaflow_to_offload_st_find(&flow->ufid) == false) {
+        queue_netdev_flow_put(pmd, flow, match, actions, actions_len);
+    }
 
     if (OVS_UNLIKELY(!VLOG_DROP_DBG((&upcall_rl)))) {
         struct ds ds = DS_EMPTY_INITIALIZER;
@@ -3451,8 +3488,11 @@  flow_put_on_pmd(struct dp_netdev_pmd_thread *pmd,
             old_actions = dp_netdev_flow_get_actions(netdev_flow);
             ovsrcu_set(&netdev_flow->actions, new_actions);
 
-            queue_netdev_flow_put(pmd, netdev_flow, match,
-                                  put->actions, put->actions_len);
+            /*Don't try to offload flows that has been offloaded failed */
+            if (megaflow_to_offload_st_find(&netdev_flow->ufid) == false) {
+                queue_netdev_flow_put(pmd, netdev_flow, match,
+                                      put->actions, put->actions_len);
+            }
 
             if (stats) {
                 get_dpif_flow_status(pmd->dp, netdev_flow, stats, NULL);
@@ -4212,7 +4252,37 @@  dp_netdev_actions_free(struct dp_netdev_actions *actions)
 {
     free(actions);
 }
-
+
+static void
+dp_netdev_append_hw_offload(struct dp_netdev_pmd_thread *pmd,
+                            struct dp_netdev_flow *flow)
+{
+    struct match flow_put_match;
+    struct dp_netdev_actions *flow_put_actions;
+    struct dp_flow_offload_item *offload;
+    int op = DP_NETDEV_FLOW_OFFLOAD_OP_ADD;
+
+    match_wc_init(&flow_put_match,&(flow->flow));
+    /* If this flow has been offloaded, but fail, won't offload again
+     * Otherwise if this flow has been offloaded succeded, it means
+     * although the ufid is the same, but exact flow is different
+     * in this scenario, or hw flow is ageout. we should also try to
+     * offload it to hw
+     */
+    if (megaflow_to_offload_st_find(&flow->ufid) == true) {
+        return ;
+    }
+    flow_put_actions = dp_netdev_flow_get_actions(flow);
+
+    offload = dp_netdev_alloc_flow_offload(pmd, flow, op);
+    offload->match = flow_put_match;
+    offload->actions = xmalloc(flow_put_actions->size);
+    memcpy(offload->actions, flow_put_actions->actions, flow_put_actions->size);
+    offload->actions_len = flow_put_actions->size;
+
+    dp_netdev_append_flow_offload(offload);
+}
+
 static void
 dp_netdev_rxq_set_cycles(struct dp_netdev_rxq *rx,
                          enum rxq_cycles_counter_type type,
@@ -6532,6 +6602,15 @@  smc_lookup_batch(struct dp_netdev_pmd_thread *pmd,
                 flow->flow.in_port.odp_port == packet->md.in_port.odp_port)) {
                     tcp_flags = miniflow_get_tcp_flags(&keys[i].mf);
 
+                    /* In case of wildcard condition: FPGA and EMC lookup miss but
+                     * smc/dpcls lookup hit, before insert EMC, try to offload
+                     * netdev flows again(correspond to new ufid)
+                     */
+                    if (netdev_is_flow_api_enabled() &&
+                        (flow->flow.dl_type == htons(ETH_TYPE_IP))) {
+                        dp_netdev_append_hw_offload(pmd,flow);
+                    }
+
                     /* SMC hit and emc miss, we insert into EMC */
                     keys[i].len =
                         netdev_flow_key_size(miniflow_n_values(&keys[i].mf));
@@ -6882,6 +6961,15 @@  fast_path_processing(struct dp_netdev_pmd_thread *pmd,
         }
 
         flow = dp_netdev_flow_cast(rules[i]);
+        /* In case of wildcard condition: FPGA and EMC lookup miss but
+         * smc/dpcls lookup hit, before insert EMC, try to offload
+         * netdev flows again(correspond to new mega_ufid)
+         */
+        if (netdev_is_flow_api_enabled() &&
+            (flow->flow.dl_type == htons(ETH_TYPE_IP))) {
+            dp_netdev_append_hw_offload(pmd,flow);
+        }
+
         uint32_t hash =  dp_netdev_flow_hash(&flow->ufid);
         smc_insert(pmd, keys[i], hash);